Packetbuffer Basics

From Contiki
Jump to: navigation, search

Back to Contiki Tutorials


Introduction

This tutorial is a introduction to different operations on the packet buffer on ContikiOS 2.7. We will also cover brief details about each of the functions and how they work. A packet buffer is a structure that is used to create a outbound packet or store a inbound packet. A packet buffer is also used to operate on a packet and it can store only one packet at a time.

A packet buffer has two section: header section and data section.
Buf.jpg
For outbound packets, the header is stored in packetbuf header section and data is stored in packetbuf data section.
Out.jpg
For incoming packets, both the packet header and the packet data is stored in the data section of the packetbuf.
In.jpg

You will learn

Through this tutorial you will learn about the structure of packet buffer and how exactly it is maintained in ContikiOS. You will also learn about different functions and possible operations on packet buffer. We will discuss each of the function in details to help you understand the current implementations. This will help you in any projects since packet buffer is necessary component for any networking project in contikiOS.

Source Codes

~/contiki-2.7/core/net/packetbuf.c

~/contiki-2.7/core/net/packetbuf.h


Description of the Parameters and Initialization of Packet Buffer Structure

In this section, we will cover the implementations details of packet buffer in ContikiOS. We also talk about different parameters and variables that are used to store some information about packet buffer and also to operate on the packet buffer.

Packet Attributes

In this section we will discuss the details about different attributes of the packet in packet buffer.

struct packetbuf_attr packetbuf_attrs[PACKETBUF_NUM_ATTRS];
struct packetbuf_addr packetbuf_addrs[PACKETBUF_NUM_ADDRS];

These two structures are used to store the attributes of the packet stored in packet buffer and the addresses related to the packet in packet buffer i.e. source and destination address. Here the addresses are RIME addresses which is the address format used in the contiki RIME stack. The respective structures are defined as follows.

typedef uint16_t packetbuf_attr_t;

struct packetbuf_attr {
/*   uint8_t type; */
  packetbuf_attr_t val;
};
struct packetbuf_addr {
/*   uint8_t type; */
  rimeaddr_t addr;
};

Therefore packetbuf_attrs is an array of packets attributes. The array size is PACKETBUF_NUM_ATTRS. Similarly, packetbuf_addrs is an array of packet addresses. The array size is PACKETBUF_NUM_ADDRS.

The sizes are defined as follows where PACKETBUF_ATTR_MAX=28:

//  File:   ~/contiki-2.7/core/net/packetbuf.h
#define PACKETBUF_NUM_ADDRS 4
#define PACKETBUF_NUM_ATTRS (PACKETBUF_ATTR_MAX - PACKETBUF_NUM_ADDRS)

The reason behind such definition is that the PACKETBUF_ATTR_MAX also counts the packet's associated rime addresses as the packet's attribute.

Now, to set an attribute we have to call the following function. We have to supply the attribute "type" and the "value":

static inline int
packetbuf_set_attr(uint8_t type, const packetbuf_attr_t val)
{
/*   packetbuf_attrs[type].type = type; */
  packetbuf_attrs[type].val = val;
  return 1;
}

The attribute types are defined as follows.

enum {
  PACKETBUF_ATTR_NONE,//or  integer value=0

  /* Scope 0 attributes: used only on the local node. */
  PACKETBUF_ATTR_CHANNEL,//or  integer value=1
  PACKETBUF_ATTR_NETWORK_ID,//or  integer value=2
  PACKETBUF_ATTR_LINK_QUALITY,//or  integer value=3
  PACKETBUF_ATTR_RSSI,//or  integer value=4
  PACKETBUF_ATTR_TIMESTAMP,//or  integer value=5
  PACKETBUF_ATTR_RADIO_TXPOWER,//or  integer value=6
  PACKETBUF_ATTR_LISTEN_TIME,//or  integer value=7
  PACKETBUF_ATTR_TRANSMIT_TIME,//or  integer value=8
  PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS,//or  integer value=9
  PACKETBUF_ATTR_MAC_SEQNO,//or  integer value=10
  PACKETBUF_ATTR_MAC_ACK,//or  integer value=11

  /* Scope 1 attributes: used between two neighbors only. */
  PACKETBUF_ATTR_RELIABLE,//or  integer value=12
  PACKETBUF_ATTR_PACKET_ID,//or  integer value=13
  PACKETBUF_ATTR_PACKET_TYPE,//or  integer value=14
  PACKETBUF_ATTR_REXMIT,//or  integer value=15
  PACKETBUF_ATTR_MAX_REXMIT,//or  integer value=16
  PACKETBUF_ATTR_NUM_REXMIT,//or  integer value=17
  PACKETBUF_ATTR_PENDING,//or  integer value=18
  
  /* Scope 2 attributes: used between end-to-end nodes. */
  PACKETBUF_ATTR_HOPS,//or  integer value=19
  PACKETBUF_ATTR_TTL,//or  integer value=20
  PACKETBUF_ATTR_EPACKET_ID,//or  integer value=21
  PACKETBUF_ATTR_EPACKET_TYPE,//or  integer value=22
  PACKETBUF_ATTR_ERELIABLE,//or  integer value=23

  /* These must be last */
  PACKETBUF_ADDR_SENDER,//or  integer value=24
  PACKETBUF_ADDR_RECEIVER,//or  integer value=25
  PACKETBUF_ADDR_ESENDER,//or  integer value=26
  PACKETBUF_ADDR_ERECEIVER,//or  integer value=27
  
  PACKETBUF_ATTR_MAX //or  integer value=28
};

Therefore to choose an attribute you have to choose from the first 24 entries. For example, packetbuf_set_attr(PACKETBUF_ATTR_RSSI,8) will set the RSSI attribute packet of the packet to be 8.

Similarly to get the value of a certain packet attribute, we have to use following function.

static inline packetbuf_attr_t
packetbuf_attr(uint8_t type)
{
  return packetbuf_attrs[type].val;
}

For example, packetbuf_attr(PACKETBUF_ATTR_RSSI) will return the RSSI value associated with the packet.

Now, to set the packet addresses, we have to use the packetbuf_set_addr(type,*addr) function. Here type can be PACKETBUF_ADDR_SENDER, PACKETBUF_ADDR_RECEIVER, PACKETBUF_ADDR_ESENDER or PACKETBUF_ADDR_ERECEIVER i.e any value between 24-27. The value of PACKETBUF_ADDR_FIRST is 24. Here PACKETBUF_ADDR_ESENDER or PACKETBUF_ADDR_ERECEIVER are used for multihop routing. The data stored by a=these four types of fields are as follows.

  1. PACKETBUF_ADDR_SENDER: Immediate sender
  2. PACKETBUF_ADDR_RECEIVER: Immediate Reciever
  3. PACKETBUF_ADDR_ESENDER: Original Sender of a multihop packet
  4. PACKETBUF_ADDR_ERECEIVER: Original Receiver of a multihop packet

Say, node 4.0 sends a packet to node 1.0 through node 3.0 and node 2.0 . When node 3.0 forwards a packet from node 4.0 to node 2.0 the respective addresses will be PACKETBUF_ADDR_SENDER=3.0, PACKETBUF_ADDR_RECEIVER=2.0, PACKETBUF_ADDR_ESENDER =4.0, PACKETBUF_ADDR_ERECEIVER=1.0;

static inline int
packetbuf_set_addr(uint8_t type, const rimeaddr_t *addr)
{
/*   packetbuf_addrs[type - PACKETBUF_ADDR_FIRST].type = type; */
  rimeaddr_copy(&packetbuf_addrs[type - PACKETBUF_ADDR_FIRST].addr, addr); 
//Since packetbuf_addrs is an array of size 4
  return 1;
}

Similarly, to get the address attributes we have to use the following function.

static inline const rimeaddr_t *
packetbuf_addr(uint8_t type)
{
  return &packetbuf_addrs[type - PACKETBUF_ADDR_FIRST].addr;
}


There are two more function that copies the entire attribute array. They are as follows.

void
packetbuf_attr_copyto(struct packetbuf_attr *attrs,
		    struct packetbuf_addr *addrs)
{
  memcpy(attrs, packetbuf_attrs, sizeof(packetbuf_attrs));
  memcpy(addrs, packetbuf_addrs, sizeof(packetbuf_addrs));
}
void
packetbuf_attr_copyfrom(struct packetbuf_attr *attrs,
		      struct packetbuf_addr *addrs)
{
  memcpy(packetbuf_attrs, attrs, sizeof(packetbuf_attrs));
  memcpy(packetbuf_addrs, addrs, sizeof(packetbuf_addrs));
}

Some Important variables

In this section we will talk about the structure which actually implements the packet buffer. We will also talk about some important variables and pointers used to modify and access the actual data in the packet buffer.

The packet buffer is implemented by using a array structure as follows.

/* The declarations below ensure that the packet buffer is aligned on an even 16-bit boundary.
 On some platforms (most notably the msp430), having a potentially misaligned packet buffer
 may lead to problems when accessing 16-bit values. */
static uint16_t packetbuf_aligned[(PACKETBUF_SIZE + PACKETBUF_HDR_SIZE) / 2 + 1]; //Array of 16 bit elements
static uint8_t *packetbuf = (uint8_t *)packetbuf_aligned;
//Array of 8 bit elements. So each entry of the array is a character

where PACKETBUF_SIZE is the maximum size of a packet including header and PACKETBUF_HDR_SIZE is the size of the header of a packet. packetbuf points to the array that stores the packet data. Note the conversion from uint16_t array structure to a uint8_t array structure. The reason behind using uint8_t format is that it can store a character(8 bit), therefore each entry of the array can be used to store a character. The size of the buffer is (PACKETBUF_SIZE + PACKETBUF_HDR_SIZE + 2).

The reason to consider the buffer size to be (PACKETBUF_SIZE + PACKETBUF_HDR_SIZE + 2) is that the incoming packets are stored entirely in the data section. Therefore the data section of the buffer should have enough space to accommodate an entire packet which can be equal to PACKETBUF_SIZE number of bytes/characters.


By default PACKETBUF_SIZE is 128 and PACKETBUF_HDR_SIZE is 48 (Defined in ~/contiki-2.7/core/net/packetbuf.h)
static uint8_t *packetbufptr;
//This is a pointer used to point to the memory location which stores the packet's data/payload part.

static uint16_t buflen, bufptr;
static uint8_t hdrptr;
packetbufptr is used to point to the memory location which stores the packet's data/payload part.

The data section may be in the packet buffer structure or may be in some external location. In either cases, packetbufptr points to the actual address of the packet's payload/data which may be part of packetbuf or maybe some external memory address.

hdrptr stores the index of the packetbuf array where the first character of the header of a packet is stored. 

For outgoing packets, the header is stored in the slots with number starting from hdrptr to PACKETBUF_HDR_SIZE-1. Keep in mind that the first location of an array is numbered as 0. Therefore, the header is stored in packetbuf[hdrptr] to packetbuf[PACKETBUF_HDR_SIZE-1]. For example say i.e say the PACKETBUF_HDR_SIZE is 9 and hdrptr=5 then packetbuf[5:8] contains the header.

Header.jpg


buflen stores the size of the packet's payload/data that is stored in the data section of the packetbuf. 

For outgoing packets, it is the length of the packet's payload or data part. For incoming packet, since the whole packet is stored in the data section of the buffer, buflen referes to the total size of the packet.

bufptr is used to locate the first character of the packet's data part/payload within the packetbuf array. 

The value stored in the bufptr is a offset value. When we add bufptr value with PACKETBUF_HDR_SIZE, we get the index of the array which stores the first character of the packet's payload/data part. Here is an example for bufptr=4.

Bufptr.jpg

Description of the different Functions that delete data of packetbuf

void packetbuf_clear(void)

This function clears the packetbuf and resets all internal state pointers (header size, header pointer, external data pointer). It is used before preparing a packet in the packetbuf or copying a packet to the packetbuf.

However this function doesn't delete the previous data. It just resets the pointers and variables discussed in the previous section. The source code for this function is as follows.

buflen = bufptr = 0;
hdrptr = PACKETBUF_HDR_SIZE;
packetbufptr = &packetbuf[PACKETBUF_HDR_SIZE];
packetbuf_attr_clear();

The following code resets the variables that points to the payload section. Setting buflen to be zero means that the buffer doesn't contain a payload/data part of a packet. Setting bufptr to be zero implies that the new packet's data must be stores from the beginning of the buffer's data section.

buflen = bufptr = 0;


The following lines reset the header pointer to the end of the header section of the buffer which implies that the there is no header. It also sets the packetbufptr pointer to the first location of the array after the the header section which is also the beginning of the payload section.

hdrptr = PACKETBUF_HDR_SIZE;
packetbufptr = &packetbuf[PACKETBUF_HDR_SIZE];


Note that this function doesn't delete the content of the memory. It just resets the pointers. You should be careful about that while using this function in your code.

packetbuf_attr_clear();

Now, this function clears all the attributes including the address fields of the buffer. The code is as follows

void
packetbuf_attr_clear(void)
{
  int i;
  for(i = 0; i < PACKETBUF_NUM_ATTRS; ++i) {
    packetbuf_attrs[i].val = 0;  // Reset the attribute value to 0 i.e NULL
  }
  for(i = 0; i < PACKETBUF_NUM_ADDRS; ++i) {
    rimeaddr_copy(&packetbuf_addrs[i].addr, &rimeaddr_null); // Reset the rime address values to 0 i.e NULL
  }
}

void packetbuf_clear_hdr(void)

This function only resets the header field of the packet buffer.This function resets all the internal state pointers pertaining to the header (header size, header pointer, but not external data pointer). It is used after sending a packet in the packetbuf, to be able to reuse the packet buffer for a later retransmission.

hdrptr = PACKETBUF_HDR_SIZE;

Similar to the packet buffer clear operation, this line just resets the header field pointer to the end of the header section of the buffer which thereby implies that there is no header. It doesn't delete the content of the memory. You should be careful about that while coding. Here is a example with PACKETBUF_HDR_SIZE=10.

After clear.jpg

void packetbuf_hdr_remove(int size)

This function is used to remove the first part of the header in the packetbuf, when processing outgoing packets. It removes the first "size" number of entries of the header which is nothing but a pointer operation where the hdrptr pointer has to be set to point to the new beginning. The following code does exactly the same thing.

hdrptr += size;

It moves the header pointer upwards by "size" number of slots.

Note that, this is a operation for outgoing packets only.

Here is an example with size=4, hdrptr=1 and PACKETBUF_HDR_SIZE=13.

Example remove.jpg

void packetbuf_hdrreduce(int size)

This function is used to remove the first part of the header in the packetbuf, when processing incoming packets. If the function is unable to remove the requested amount of header space, the function returns zero and does nothing.

if(buflen < size) {
  return 0;
}

bufptr += size;
buflen -= size;
return 1;

Since the incoming packets are stored in the data section of the buffer, bufptr is actually the offset to get the location of the packet's first byte which is also the first byte of the packet's header. Therefore, to remove the first size number of bytes of the packet header, we just need to increase the bufptr value i.e the offset value.

bufptr += size;

Since the size of the packer is now lesser than actual and since for incoming packet buflen is the total packet length, the function reduces buflen by "size".

buflen -= size;
Note that, this is a operation for inbound/incoming packets only.

Here is an example with PACKETBUF_HDR_SIZE =6 and "size"=2.

Packetbuf hdrreduce.jpg

Description of the Functions related to different length parameters

void packetbuf_set_datalen(uint16_t len)

For outbound packets, the packetbuf consists of two parts: header and data. This function is used to set the length of the data in the packetbuf. The only thing that we need to do is to set the "buflen" value to be "len" since "buflen" value is used to refer to the data section of the packet. The data section will be located in the array entries with indexes starting from (PACKETBUF_HDR_SIZE + bufptr) to (PACKETBUF_HDR_SIZE + bufptr + buflen - 1).

 buflen = len;

Here is an example for outbound packet, with len=8 and bufptr=0.

Data len.jpg

uint16_t packetbuf_datalen(void)

This function returns the length/amount of data stored in the data section of the packet buffer.

For outbound packets, the packetbuf consists of two parts: header and data. 
This function is used to get the length of the data in the packetbuf. 
For incoming packets, both the packet header and the packet data is stored in the data portion of the packetbuf. 
This function is then used to get the total length of the packet - both header and data.

Since the value is already stored in buflen, the only operation of this function is to return the value of buflen. This emphasizes on the importance of the variable buflen. If it is not set properly, the all the operations on the current packet will be erroneous.

The ContikiOS code for this function is as follows.

 return buflen;

uint8_t packetbuf_hdrlen(void)

This function is used to get the length of the header in the packetbuf. The header is stored in the packetbuf and accessed via the packetbuf_hdrptr() function.

This is useful only for the outgoing packets since incoming packets are stored entirely in the data section.
Therefore, for incoming packets it will return 0.

Since the header is located at the array locations starting from hdrptr (inclusive) to PACKETBUF_HDR_SIZE-1 (inclusive) the size of the header is nothing but the number of slots between them. The value is same as PACKETBUF_HDR_SIZE - hdrptr. Say, PACKETBUF_HDR_SIZE =8, hdrptr=3, then the header is stored in locations 3,4,5,6,7 i.e header size=5 = 8-3 = PACKETBUF_HDR_SIZE-hdrptr.

 
 return PACKETBUF_HDR_SIZE - hdrptr;

uint16_t packetbuf_totlen(void)

This function is used to get the total length of the header and data in the packetbuf.

As discussed already, for an outbound packet, packetbuf_hdrlen() returns the header length and packetbuf_datalen() return the length of the data section. For an inbound/incoming packet, packetbuf_hdrlen() returns "0" and packetbuf_datalen() returns the total length of the packet.

Thereby the code to get the total length is as follows.

 
  return packetbuf_hdrlen() + packetbuf_datalen();

Description of the Functions related to different pointers

void *packetbuf_dataptr(void)

This function is used to get a pointer to the data in the packetbuf. The data is either stored in the packetbuf, or referenced to an external location. For outbound packets, the packetbuf consists of two parts: header and data. The header is accessed with the packetbuf_hdrptr() function.

So, for outbound packets this function is used to get a pointer to the data/payload of the packets.

For incoming packets, both the packet header and the packet data is stored in the data portion of the packetbuf.

So, for incoming packets this function is used to get a pointer to the header of the incoming packets.
 
  return (void *)(&packetbuf[bufptr + PACKETBUF_HDR_SIZE]);

In this case bufptr value is the offset from the buffers data section beginning to point to the location that contains the first character of the packet.

For outgoing packets, if bufptr=0, the packet's data/payload are stored from the beginning of the buffer's data section i.e at buffer index = PACKETBUF_HDR_SIZE.

However, for incoming packet if bufptr=0, first character of data is at buffer index = (PACKETBUF_HDR_SIZE + packet's header size), since both the packet header and the packet data are stored in the data portion of the packetbuf.

Here is an example scenario.

Dataptr.jpg

void *packetbuf_hdrptr(void)

For outbound packets, the packetbuf consists of two parts: header and data. This function is used to get a pointer to the header in the packetbuf. The header is stored in the packetbuf. "hdrptr" provides the index of the first character's location in the packetbuf array. Therefore this function just returns the address of the packetbuf array entry pointed by hdrptr.

For inbound packets, hdrptr= PACKETBUF_HDR_SIZE.

This function is useful only for outbound/outgoing packets. 

The code for this function is as follows.

 
  return (void *)(&packetbuf[hdrptr]);

void packetbuf_reference(void *ptr, uint16_t len)

This function is used to make the packetbuf point to external data. The function also specifies the length of the external data that the packetbuf references. The "ptr" argument points to the external data and the "len" is the length of the external data. Since the packet buffer doesn't store the data section anymore, the buffer should be cleared.

The code for this function is as follows.

 
packetbuf_clear();//clears the buffer
packetbufptr = ptr;//points to the external data
buflen = len;//Set the data length to be equal to the external data length

int packetbuf_is_reference(void)

For outbound packets, the packetbuf consists of two parts: header and data. This function is used to check if the packetbuf points to external data that has previously been referenced with packetbuf_reference().

 
  return packetbufptr != &packetbuf[PACKETBUF_HDR_SIZE];

This function checks whether the packetbufptr points to the data section of the packetbuf. If yes, then the function returns 0 since the external data has not been previously referenced. Otherwise it return TRUE or 1. Therefore this function is a boolean function.

void *packetbuf_reference_ptr(void)

For outbound packets, the packetbuf consists of two parts: header and data. The data may point to external data that has previously been referenced with packetbuf_reference(). This function is used to get a pointer to the external data.

If there is no external data, it will return a pointer to the beginning of the data section in the packetbuf.

 
  return packetbufptr;

Description of the Functions related to Copying

int packetbuf_copyfrom(const void *from, uint16_t len)

This function copies data from the memory location pointed by "from" into the packetbuf. If the data that is to be copied is larger than the packetbuf, only the data that fits in the packetbuf is copied. The number of bytes that could be copied into the packetbuf is returned.


{
  uint16_t l;

  packetbuf_clear(); //Clears the buffer before storing the new data 
  /* check if the size of the data is greater than the size of a packet i.e PACKETBUF_SIZE. 
  If yes, then copy only the first PACKETBUF_SIZE bytes of the data. Otherwise copy everything.*/
  l = len > PACKETBUF_SIZE? PACKETBUF_SIZE: len; 
  // the variable l stores the amount of data to be copied to packetbuf
  memcpy(packetbufptr, from, l);
  //packetbufptr points to the beginning of the packet buffer data section i.e where the data need to be stored.
  buflen = l;
  return l;
}

void packetbuf_compact(void)

This function compacts the packetbuf by copying the data portion of the packetbuf so that becomes consecutive to the header. It also copies external data that has previously been referenced with packetbuf_reference() into the packetbuf.

This function is called by the Rime code before a packet is to be sent by a device driver. This assures that the entire packet is consecutive in memory.

Note that, this code assumes the lengths and other variables to be set properly.

The source code of this function is as follows.

{
  int i, len;

  if(packetbuf_is_reference()) {
    memcpy(&packetbuf[PACKETBUF_HDR_SIZE], packetbuf_reference_ptr(),
	   packetbuf_datalen());
  } else if(bufptr > 0) {
    len = packetbuf_datalen() + PACKETBUF_HDR_SIZE;
    for(i = PACKETBUF_HDR_SIZE; i < len; i++) {
      packetbuf[i] = packetbuf[bufptr + i];
    }

    bufptr = 0;
  }
}

Now, we discuss the code in more details.

The first step is to check whether the data is external or not. If yes then we can simply copy the data into the buffer. The following code does exactly that. As discussed before packetbuf_is_reference() is a Boolean function to check whether the packet's data section refer to a external data, packetbuf_reference_ptr() return the pointer to the external data and packetbuf_datalen() return the number of bytes to be copied i.e. the length of the data section.

if(packetbuf_is_reference()) {
    memcpy(&packetbuf[PACKETBUF_HDR_SIZE], packetbuf_reference_ptr(),packetbuf_datalen());
}

Here is an example illustrating the above mentioned concept.

Packetbuf compact2.jpg

If the data is not external, but the data is not compactly stored, this function makes it compact. If bufptr > 0, then there is a gap or offset between the actual beginning location of the data section and the supposed beginning location of the data section i.e the location with id = PACKETBUF_HDR_SIZE. This function shift the data to the supposed location within the buffer. The following code does that.

len = packetbuf_datalen() + PACKETBUF_HDR_SIZE; //This gives us the supposed location for the last byte of the packet
for(i = PACKETBUF_HDR_SIZE; i < len; i++) { 
      packetbuf[i] = packetbuf[bufptr + i]; //This line shift the data to be the actual location
}

bufptr = 0; //Since the data is shifted to the beginning of the buffer's data section, the offset is now 0 again.

Here is an example illustrating the above mentioned situation.

Packetbuf compact1.jpg

int packetbuf_copyto_hdr(uint8_t *to)

This function copies the header portion of the packetbuf to an external buffer. The external buffer to which the packetbuf is to be copied must be able to accomodate at least PACKETBUF_HDR_SIZE bytes. The number of bytes that was copied to the external buffer is returned.

The source code this function is as follows.

{
#if DEBUG_LEVEL > 0
  {
    int i;
    PRINTF("packetbuf_write_hdr: header:\n");
    for(i = hdrptr; i < PACKETBUF_HDR_SIZE; ++i) {
      PRINTF("0x%02x, ", packetbuf[i]);
    }
    PRINTF("\n");
  }
#endif /* DEBUG_LEVEL */
  memcpy(to, packetbuf + hdrptr, PACKETBUF_HDR_SIZE - hdrptr);//packetbuf points to the beginning of the buffer array.
  return PACKETBUF_HDR_SIZE - hdrptr;
}


In the above potion of code, the main line is the following

memcpy(to, packetbuf + hdrptr, PACKETBUF_HDR_SIZE - hdrptr);

where "to" is the destination address. (packetbuf + hdrptr) is the address of the buffer entry which stores the first byte of the packet's header. (PACKETBUF_HDR_SIZE - hdrptr) is the actual size of the header.

Note that, this function should be used only for outgoing packet. Since the incoming packet header is stored in the data section of the buffer, this approach will not work (PACKETBUF_HDR_SIZE - hdrptr=0) for that.


int packetbuf_copyto(void *to)

This function copies the packetbuf to an external buffer. Both the data portion and the header portion of the packetbuf is copied. If the packetbuf referenced external data (referenced with packetbuf_reference()) the external data is copied.

The external buffer to which the packetbuf is to be copied must be able to accommodate at least PACKETBUF_SIZE bytes. The number of bytes that was copied to the external buffer is returned.


{
#if DEBUG_LEVEL > 0
  {
         ...
  }
#endif /* DEBUG_LEVEL */
  
  if(PACKETBUF_HDR_SIZE - hdrptr + buflen > PACKETBUF_SIZE) {
    /* Too large packet */
    return 0;
  }
  memcpy(to, packetbuf + hdrptr, PACKETBUF_HDR_SIZE - hdrptr);
  memcpy((uint8_t *)to + PACKETBUF_HDR_SIZE - hdrptr, packetbufptr + bufptr, buflen);
  return PACKETBUF_HDR_SIZE - hdrptr + buflen;
}


This function first copies from the header section of the buffer and then copy from the data section of the buffer. The following lines copies the data from the header section of the packetbuf. The destination address is "to" and the source address is the address of the entry packetbuf[hdrptr] which is (packetbuf+hdrptr). (PACKETBUF_HDR_SIZE - hdrptr) is the actual size of the header i.e the number of bytes to be copied for the header only.

memcpy(to, packetbuf + hdrptr, PACKETBUF_HDR_SIZE - hdrptr);

The following lines copies the data from the data/payload section of the packetbuf. The destination address is "(uint8_t *)to + PACKETBUF_HDR_SIZE - hdrptr". The reason is that "PACKETBUF_HDR_SIZE - hdrptr" bytes of header data is already copied. This gives us the next available memory location. The source address is (packetbufptr + bufptr). "packetbufptr" points to the packet's data part beginning. If the data is external, "packetbufptr" points to the external source, otherwise "packetbufptr" points to packetbuf[PACKETBUF_HDR_SIZE]. "buflen" is the actual size of the data i.e the number of bytes to be copied for the packet's data part only.

memcpy((uint8_t *)to + PACKETBUF_HDR_SIZE - hdrptr, packetbufptr + bufptr, buflen);



int packetbuf_hdralloc(int size)

This function is used to allocate extra space in the header portion in the packetbuf, when preparing outbound packets for transmission. If the function is unable to allocate sufficient header space, the function returns zero and does not allocate anything.

  if(hdrptr >= size && packetbuf_totlen() + size <= PACKETBUF_SIZE) 
  {
    hdrptr -= size;
    return 1;
  }
  return 0;

if hdrptr >= size then, there is a possibility. But if the total length of the packet after adding extra space is greater PACKETBUF_SIZE then we can allocate more space.

if hdrptr <= size or packet total length + size > PACKETBUF_SIZE, it is not possible to allocate "size" amount of extra bytes or space.

hdrptr -= size;

This increases the header size. Since the end location of the header is fixed at PACKETBUF_HDR_SIZE-1, only way to assign more space is to move the beginning location pointer.