extract coap query - c

I need your help in extracting the query value in a coap message.The coap message looks like
coap://[ff08:90:5001:0:0:0:0:1]:12345/c?a=4
decoded packet is 52 02 00 00 91 63 63 61 3d 34 . Here 63 61 3d 34 is the query part ?a=4 . There is a data after query. I have pointed my buffer pointer to 63(?), now I'm struck in getting the value 34(4). How do I go to the value and extract it?
coap_h *hdr = (coap_h *)(buf);
buf = (uint8_t *)(hdr + 1);
len = buf[0] & 0xf;
buf += len + 1;
buf points to 52 initially and then I move the buf to the options field 91 and check for length then increment the buf which points to 63 (?). hope i'm clear this time.

I don't have the time at the moment to parse your packet by hand, but you should know that the way options work has changed dramatically in CoAP-12. I have implemented some functions to encode and parse options, which you might find useful:
https://github.com/darconeous/smcp/blob/master/src/smcp/coap.c
https://github.com/darconeous/smcp/blob/master/src/smcp/coap.h

Related

ESP32 - Extract Manufacturer Specific Data from advertisement

TL;DR: One ESP32 broadcasts via BLE (already working), another ESP32 listens. I am unable to parse the received advertisements correctly, i.e. can't extract the manufacturer specific data!
Goal: One ESP32 (call A) broadcasts an advertisement containing manufacturer specific data (MSD), which is received by another ESP32 (call B) who prints that data to the console.
I am using the new RISC-V based ESP32C3 which supports Bluetooth 5.0, though everything I do is based on Bluetooth 4.2.
Where I am:
A can broadcast a valid advertisement (checked with an Ubertooth/Wireshark)
B receives something from A, though the packet only very loosely corresponds to the (correct) packet received by the Ubertooth.
Code:
Structs used to set up A:
// Struct defining advertising parameters
static esp_ble_adv_params_t ble_adv_params = {
.adv_int_min = 0x0800,
.adv_int_max = 0x0900,
.adv_type = ADV_TYPE_NONCONN_IND,
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
.channel_map = ADV_CHNL_ALL,
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, // NO IDEA ABOUT THAT ONE, ESPECIALLY GIVEN THAT WE SEND NONCONNECTABLE AND NONSCANNABLE ADVERTISEMENTS!
};
Struct used to define the payload of the advertisement:
esp_ble_adv_data_t ble_adv_data =
{
.set_scan_rsp = false,
.include_name = true, // "Name" refers to the name passed as an argument within "esp_ble_gap_set_device_name()"
.include_txpower = false,
.min_interval = 0xffff, // Not sure what those are for, as the chosen advertisement packets are non-connectable...
.max_interval = 0xFFFF,
.appearance = 64, // 64 is appearance ID of phone. Only to maybe be able to find it on my Galaxy phone
.manufacturer_len = ble_adv_payload_len,
.p_manufacturer_data = (uint8_t *) ble_adv_payload, // Currently just some human-readable string used for debugging
.service_data_len = 0,
.p_service_data = NULL,
.service_uuid_len = 0,
.p_service_uuid = NULL,
.flag = 0
};
As the Ubertooth receives correct packets sent by A, I reckon A has been set up correctly.
Struct used to define scanning behavior of B:
// Struct defining scanning parameters
static esp_ble_scan_params_t ble_scan_params = {
.scan_type = BLE_SCAN_TYPE_PASSIVE, // Don't send scan requests upon receiving an advertisement
.own_addr_type = BLE_ADDR_TYPE_PUBLIC, // Use (static) public address, makes debugging easier
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ONLY_WLST, // Consider all advertisements
.scan_interval = 0x50, // Time between each scan window begin
.scan_window = 0x30, // Length of scan window
.scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE // Filters out duplicate advertisements, e.g. if an advertisement received k times, it is only reported once
};
The majority of the remaining code is just boilerplate, the only really relevant part is the callback function of B, which gets called whenever a GAP-Event occurs (GAP-Events can be found in esp_gap_ble_api.h, beginning on line 138).
B's callback function:
void esp_ble_callback_fun(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
// Do a case split on the different events. For now, only "ESP_GAP_BLE_SCAN_RESULT_EVT" is of interest
switch (event) {
case ESP_GAP_BLE_SCAN_RESULT_EVT:
if ((param->scan_rst).search_evt != ESP_GAP_SEARCH_INQ_RES_EVT) {
printf(
"B: Callback function received a non-\"ESP_GAP_SEARCH_INQ_RES_EVT\" event!\n");
return;
}
// Copy the parameter UNION
esp_ble_gap_cb_param_t scan_result = *param;
// Create a POINTER to the "bda" entry, which is accessed by interpreting the scan_result UNION as a scan_rst STRUCT
// Note that "esp_bd_addr_t" is a typedef for a uint8_t array!
esp_bd_addr_t *ble_adv_addr = &scan_result.scan_rst.bda;
printf("\n-------------------------\nMessage: \n");
uint8_t adv_data_len = scan_result.scan_rst.adv_data_len;
uint8_t *adv_data = scan_result.scan_rst.ble_adv;
printf("Message length: %i\n", adv_data_len);
printf("Message body:\n"); // NOT SO SURE ABOUT THIS!
for(int i = 0; i < adv_data_len; ++i)
{
printf("%X", adv_data[i]);
}
printf("\n-------------------------\n");
break; // #suppress("No break at end of case")
default:
// NOT SUPPORTED! JUST IGNORE THEM!
break;
}
}
Sample output:
Serial output by B:
Message:
Message length: 22
Message body:
31940069414C4943454FF486579512FFFFFFFF
Packet as received in Wireshark:
Frame 78135: 61 bytes on wire (488 bits), 61 bytes captured (488 bits) on interface /tmp/pipe, id 0
PPI version 0, 24 bytes
Version: 0
Flags: 0x00
.... ...0 = Alignment: Not aligned
0000 000. = Reserved: 0x00
Header length: 24
DLT: 251
Reserved: 36750c0000620900e05b56b811051000
Bluetooth
Bluetooth Low Energy Link Layer
Access Address: 0x8e89bed6
Packet Header: 0x1c22 (PDU Type: ADV_NONCONN_IND, ChSel: #2, TxAdd: Public)
.... 0010 = PDU Type: ADV_NONCONN_IND (0x2)
...0 .... = RFU: 0
..1. .... = Channel Selection Algorithm: #2
.0.. .... = Tx Address: Public
0... .... = Reserved: False
Length: 28
Advertising Address: Espressi_43:3e:d6 (7c:df:a1:43:3e:d6)
Advertising Data
Appearance: Generic Phone
Device Name: ALICE
Manufacturer Specific
Slave Connection Interval Range: 81918.8 - 81918.8 msec
Connection Interval Min: 65535 (81918.8 msec)
Connection Interval Max: 65535 (81918.8 msec)
CRC: 0x905934
0000 00 00 18 00 fb 00 00 00 36 75 0c 00 00 62 09 00 ........6u...b..
0010 e0 5b 56 b8 11 05 10 00 d6 be 89 8e 22 1c d6 3e .[V........."..>
0020 43 a1 df 7c 03 19 40 00 06 09 41 4c 49 43 45 04 C..|..#...ALICE.
0030 ff 48 65 79 05 12 ff ff ff ff 09 9a 2c .Hey........,
For a packet without MSD, I computed the longest common subsequence between the binary representation of a packet received by B (i.e. content of adv_data) and the packet received by the Ubertooth. They only had 46 bits in common, a weird number for sure!
My questions:
Am I right in assuming that adv_data, i.e. scan_result.scan_rst.ble_adv holds the raw BLE packet? The definition of ble_adv (esp_gap_ble_api.h, line 936) is incredibly confusing IMO, as it is called "Received EIR" despite EIRs only being introduced in Bluetooth 5.0...
How can I extract the MSD from a received BLE advertisement?
EIR was introduced a long time ago and was present in Bluetooth 4.0.
You should use %02X when printing hex strings since that will include leading zeros.
ble_adv contains only the EIR content, not the whole packet.
EIR uses length, type, value encoding. Your manufacturing data is encoded like this:
4 (length)
0xff (manufacturer data)
Hey (content)
Note that the two bytes of the manufacturer data content should be a Bluetooth SIG registered company id.

C array assign & access

I'm writing C code in a PIC16F1824, and are using UART.
I had this for receiving:
for(int i = 0; i < 9; i++){
while(!PIR1bits.RCIF);
RX_arr[i] = RCREG;
while(PIR1bits.RCIF);
}
RX_arr is an array declared as int RX_arr[9];
RCREG is the UART receving register and is supposed to have
0xFF 86 00 00 00 00 00 00 47;
Question1:
When i = 1, RX_arr[0]'s value(0xFF in this case) also changes when RX_arr[1] = RCREG is executed(Both postion 0 and 1 have 0x86).
Later I found using this segment of code instead of the for loop above will successfully assign one byte into each position:
if(!RCSTAbits.FERR && !RCSTAbits.OERR){
RX_arr[0] = RCREG;
}
However, the byte saved is wrong, only the 0xFF is always correct, other bytes are some other values. I found the OERR bit is set, which indicates an overrun error(2 byte FIFO buffer is full before accessed). How can I receive all the bytes in RCREG?
Question2:
After I get the response in question1, I read the useful information in it, which is in byte 2 and 3, and I made a variable called data. In my case the data is a sampled temperature, and I want to collect 20 samples,and save them in an array called ppm_array. sum_ppm is supposed to be the sum of all 20 samples, and will add the new sampled temperature to it every time a new sample is collected. When I run sum_ppm += ppm_array[i](sum_ppm = 0, ppm_array[0] = 1616, and the rest of the positions are 0),I got sum_ppm = 4508160. Why isn't it 1616??? Am I adding the address of them?
data = RX_arr[2] * 256 + RX_arr[3];
ppm_array[i] = data;
sum_ppm += ppm_array[i]
Many thanks.

Getting error "The capture file appears to be damaged or corrupt. (pcap: File has 1847605831-byte packet, bigger than maximum of 65535)"

I am getting error when i am trying to dump a packet in pcap file.
{
unsigned char *ofilename = "packet.pcap";
pcap_t *fp;
pcap_dumper_t *dumpfile;
const struct pcap_pkthdr *header;
fp = pcap_open_dead(DLT_RAW,256);
if(fp != NULL)
{
dumpfile = pcap_dump_open(fp, ofilename);
if(dumpfile == NULL)
{
printf("\nError opening output file\n");
return;
}
pcap_dump((u_char *)dumpfile,header,data);
pcap_close(fp);
pcap_dump_close(dumpfile);
}
}
HERE data is a u8 data[256].. its 256 byte data.. which has the packet bytes like this
FF FF FF FF FF FF 00 50 56 A8 11 39 81 00 0F FC 81 00 1F FC 08 06 00 01 08 00 06 04 00 01 00 50 56 A8 11 39 65 2B 01 0A 00 00 00 00 00 00 65 2B
But when i open packet.pcap i am getting "The capture file appears to be damaged or corrupt. (pcap: File has 1847605831-byte packet, bigger than maximum of 65535)"
Could someone pls help me on this whats going wrong
Kindly install "pcapfix" on Linux and run it on the corrupt file as follows
$ pcapfix -d 'file / file path here'
This will fix it.
Try something such as
{
unsigned char *ofilename = "packet.pcap";
pcap_t *fp;
pcap_dumper_t *dumpfile;
struct pcap_pkthdr header;
fp = pcap_open_dead(DLT_RAW,256);
if(fp != NULL)
{
dumpfile = pcap_dump_open(fp, ofilename);
if(dumpfile == NULL)
{
printf("\nError opening output file\n");
return;
}
header.caplen = 256; /* or however many bytes actually contain packet data */
header.len = 256; /* or however many bytes actually contain packet data */
gettimefoday(&header.ts); /* I'm assuming this is on some flavor of UN*X */
pcap_dump((u_char *)dumpfile,&header,data);
pcap_close(fp);
pcap_dump_close(dumpfile);
}
}
For one thing, just because a function takes an argument of type "{something} *", that doesn't mean you should pass to it a variable of type "{something} *". You must pass it a value of type "{something} *", but it must be a valid value, i.e. it must point to something.
An uninitialized variable of type "{something} ``*", which is what you have in your code, doesn't point to anywhere valid.
However, if you declare a variable of type "{something}", rather than "{something} *", you can use the & operator on that variable to get a value of type "{something} *" that points to the variable.
Then, as indicated, you have to give that variable a value if you're passing it to pcap_dump(). You have to set the len and caplen members of a struct pcap_pkthdr; the caplen member must be equal to the actual number bytes of packet data (which might be less than the size of the array if the packet isn't, in your case, exactly 256 bytes long), and the len member must be at least that value; len would only be bigger than caplen if the packet came from a capture done with a "snapshot length" value that discarded everything in the packet past a certain point, which isn't the case here, so len should be equal to caplen.
You probably also want to set the time stamp of the packet; I'm assuming you're running on some form of UN*X here, so you can use gettimeofday() to get the current time. If this is Windows with WinPcap, you'll probably have to do something else.
(header must not be const here, as you have to set it. It doesn't have to be const; it's const in the declaration of pcap_dump(), but that just means that pcap_dump() won't change it, so you can pass it a pointer to something that's const; you don't have to pass it something that'sconst`.)

Passing a 256-bit wire to a C function through the Verilog VPI

I have a 256-bit value in Verilog:
reg [255:0] val;
I want to define a system task $foo that calls out to external C using the VPI, so I can call $foo like this:
$foo(val);
Now, in the C definition for the function 'foo', I cannot simply read the argument as an integer (PLI_INT32), because I have too many bits to fit in one of those. But, I can read the argument as a string, which is the same thing as an array of bytes. Here is what I wrote:
static int foo(char *userdata) {
vpiHandle systfref, args_iter, argh;
struct t_vpi_value argval;
PLI_BYTE8 *value;
systfref = vpi_handle(vpiSysTfCall, NULL);
args_iter = vpi_iterate(vpiArgument, systfref);
argval.format = vpiStringVal;
argh = vpi_scan(args_iter);
vpi_get_value(argh, &argval);
value = argval.value.str;
int i;
for (i = 0; i < 32; i++) {
vpi_printf("%.2x ", value[i]);
}
vpi_printf("\n");
vpi_free_object(args_iter);
return 0;
}
As you can see, this code reads the argument as a string and then prints out each character (aka byte) in the string. This works almost perfectly. However, the byte 00 always gets read as 20. For example, if I assign the Verilog reg as follows:
val = 256'h000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f;
And call it using $foo(val), then the C function prints this at simulation time:
VPI: 20 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
I have tested this with many different values and have found that the byte 00 always gets mapped to 20, no matter where or how many times it appears in val.
Also, note that if I read the value in as a vpiHexStrVal, and print the string, it looks fine.
So, two questions:
Is there a better way to read in my 256-bit value from the Verilog?
What's going on with the 20? Is this a bug? Am I missing something?
Note: I am using Aldec for simulation.
vpiStringVal is used when the value is expected to be ASCII text, in order to get the value as a pointer to a C string. This is useful if you want to use it with C functions that expect a C string, such as printf() with the %s format, fopen(), etc. However, C strings cannot contain the null character (since null is used to terminate C strings), and also cannot represent x or z bits, so this is not a format that should be used if you need to distinguish any possible vector value. It looks like the simulator you are using formats the null character as a space (0x20); other simulators just skip them, but that doesn't help you either. To distinguish any possible vector value use either vpiVectorVal (the most compact representation) or vpiBinStrVal (a binary string with one 0/1/x/z character for each bit).

C Convert String to Ints Issue

I'm trying to parse some input on an embedded system.
I'm expecting something like this:
SET VARNAME=1,2,3,4,5,6,7,8,9,10\0
When I'm converting the separate strings to ints, both atoi() and strtol() seem to be returning 0 if the string begins with 8.
Here is my code:
char *pch, *name, *vars;
signed long value[256];
int i;
#ifdef UARTDEBUG
char convert[100];
#endif
if(strncmp(inBuffer, "SET",3)==0)
{
pch = strtok(inBuffer," ");
pch = strtok(NULL," ");
name = strtok(pch, "=");
vars = strtok(NULL,"=");
pch = strtok(vars,",");
i = 0;
while(pch != NULL)
{
value[i] = atoi(pch);
#ifdef UARTDEBUG
snprintf(convert, sizeof(convert), "Long:%d=String:\0", value[i]);
strncat(convert, pch, 10);
SendLine(convert);
#endif
i++;
pch = strtok(NULL,",");
// Check for overflow
if(i > sizeof(value)-1)
{
return;
}
}
SetVariable(name, value, i);
}
Passing it:
SET VAR=1,2,3,4,5,6,7,8,9,10\0
gives the following in my uart debug:
Long:1=String:1
Long:2=String:2
Long:3=String:3
Long:4=String:4
Long:5=String:5
Long:6=String:6
Long:7=String:7
Long:0=String:8
Long:9=String:9
Long:10=String:10
UPDATE:
I've checked the inBuffer both before and after 'value[i] = atoi(pch);' and it's identical and appears to have been split up to the right point.
S E T V A R 1 2 3 4 5 6 7 8 9 , 1 0
53 45 54 00 56 41 52 00 31 00 32 00 33 00 34 00 35 00 36 00 37 00 38 00 39 2c 31 30 00 00 00 00
UPDATE 2:
My UARTDEBUG section currently reads:
#ifdef UARTDEBUG
snprintf(convert, 20, "Long:%ld=String:%s", value[i], pch);
SendLine(convert);
#endif
If I comment out the snprintf() line, everything works perfectly. So what's going on with that?
can't you try to write your own atoi?
it's like ten lines long and then you can debug it easily (and check where the problem really is)
'0' = 0x30
'1' = 0x31
and so on, you just need to do something like
string[x] - 0x30 * pow(10, n)
for each digit you have
Not related, but
if(i > sizeof(value)-1)
{
return;
}
should be
if(i == sizeof(value)/sizeof(value[0]) )
{
return;
}
May be the cause of the problem if other pieces of code do the overflow checking in the wrong way and because of that they overwrite part of your string
I've just tried compiling and running your sample code on my own system. The output is correct (i.e. '8' appears where it should be in the output string) which indicates to me that something else is going on outside of the scope of the code you've provided to us.
I'm going to go out on a limb and say that one of your variables or functions is trampling your input string or some other variable or array. SendLine and SetVariable are places to look.
But more importantly, you haven't given us the tools to help you solve your problem. When asking people to help you debug your program, provide a simple test case, with full source, that exemplifies the problem. Otherwise, we're left to guess what the problem is, which is frustrating for us and unproductive for you.
atoi returns 0 for something that it can't render as numeric -- this is just a hunch, but have you tried dumping the binary representation of the string (or even checking that the string lengths match up)?

Resources