Microchip® Advanced Software Framework

ip_frag.c File Reference

This is the IPv4 packet segmentation and reassembly implementation.

#include "lwip/opt.h"
#include "lwip/ip_frag.h"
#include "lwip/def.h"
#include "lwip/inet_chksum.h"
#include "lwip/netif.h"
#include "lwip/snmp.h"
#include "lwip/stats.h"
#include "lwip/icmp.h"
#include <string.h>

Data Structures

struct  ip_reass_helper
 This is a helper struct which holds the starting offset and the ending offset of this fragment to easily chain the fragments. More...
 

Macros

#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB)
 
#define IP_REASS_CHECK_OVERLAP   1
 The IP reassembly code currently has the following limitations: More...
 
#define IP_REASS_FLAG_LASTFRAG   0x01
 
#define IP_REASS_FREE_OLDEST   1
 Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is full (IP_REASS_MAX_PBUFS pbufs are enqueued). More...
 

Functions

err_t ip_frag (struct pbuf *p, struct netif *netif, ip_addr_t *dest)
 Fragment an IP datagram if too large for the netif. More...
 
struct pbufip_reass (struct pbuf *p)
 Reassembles incoming IP fragments into an IP datagram. More...
 
static int ip_reass_chain_frag_into_datagram_and_validate (struct ip_reassdata *ipr, struct pbuf *new_p)
 Chain a new pbuf into the pbuf list that composes the datagram. More...
 
static void ip_reass_dequeue_datagram (struct ip_reassdata *ipr, struct ip_reassdata *prev)
 Dequeues a datagram from the datagram queue. More...
 
static struct ip_reassdataip_reass_enqueue_new_datagram (struct ip_hdr *fraghdr, int clen)
 Enqueues a new fragment into the fragment queue. More...
 
static int ip_reass_free_complete_datagram (struct ip_reassdata *ipr, struct ip_reassdata *prev)
 Free a datagram (struct ip_reassdata) and all its pbufs. More...
 
static int ip_reass_remove_oldest_datagram (struct ip_hdr *fraghdr, int pbufs_needed)
 Free the oldest datagram to make room for enqueueing new fragments. More...
 
void ip_reass_tmr (void)
 Reassembly timer base function for both NO_SYS == 0 and 1 (!). More...
 

Variables

static u16_t ip_reass_pbufcount
 
PACK_STRUCT_BEGIN struct
ip_reass_helper 
PACK_STRUCT_STRUCT
 
static struct ip_reassdatareassdatagrams
 

#define IP_ADDRESSES_AND_ID_MATCH (   iphdrA,
  iphdrB 
)
Value:
(ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \
IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0
#define ip_addr_cmp(addr1, addr2)
Definition: ip_addr.h:198
#define IPH_ID(hdr)
Definition: ip.h:150

Referenced by ip_reass(), and ip_reass_remove_oldest_datagram().

#define IP_REASS_CHECK_OVERLAP   1

The IP reassembly code currently has the following limitations:

  • IP header options are not supported
  • fragments must not overlap (e.g. due to different routes), currently, overlapping or duplicate fragments are thrown away if IP_REASS_CHECK_OVERLAP=1 (the default)!
Todo:
: work with IP header options

Setting this to 0, you can turn off checking the fragments for overlapping regions. The code gets a little smaller. Only use this if you know that overlapping won't occur on your network!

#define IP_REASS_FLAG_LASTFRAG   0x01
#define IP_REASS_FREE_OLDEST   1

Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is full (IP_REASS_MAX_PBUFS pbufs are enqueued).

The code gets a little smaller. Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA is set to 1, so one datagram can be reassembled at a time, only.

err_t ip_frag ( struct pbuf p,
struct netif netif,
ip_addr_t dest 
)

Fragment an IP datagram if too large for the netif.

Chop the datagram in MTU sized chunks and send them in order by using a fixed size static memory buffer (PBUF_REF) or point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF).

Parameters
pip packet to send
netifthe netif on which to send
destdestination ip address to which to send
Returns
ERR_OK if sent successfully, err_t otherwise

References ERR_MEM, ERR_OK, htons, if(), inet_chksum(), ip_frag(), IP_HLEN, IP_MF, IP_OFFMASK, IP_REASS_DEBUG, IPFRAG_STATS_INC, IPH_CHKSUM_SET, IPH_LEN_SET, IPH_OFFSET, IPH_OFFSET_SET, iphdr, pbuf::len, LWIP_ASSERT, LWIP_DEBUGF, LWIP_MEM_ALIGN, netif::mtu, pbuf::next, ntohs, NULL, netif::output, pbuf::payload, pbuf_alloc(), pbuf_cat(), pbuf_chain(), pbuf_copy_partial(), pbuf_free(), pbuf_header(), PBUF_IP, PBUF_LINK, PBUF_RAM, PBUF_RAW, pbuf_realloc(), PBUF_REF, pbuf_ref(), snmp_inc_ipfragcreates, snmp_inc_ipfragoks, and pbuf::tot_len.

Referenced by ip_frag(), ip_reass(), and ip_reass_enqueue_new_datagram().

static int ip_reass_chain_frag_into_datagram_and_validate ( struct ip_reassdata ipr,
struct pbuf new_p 
)
static

Chain a new pbuf into the pbuf list that composes the datagram.

The pbuf list will grow over time as new pbufs are rx. Also checks that the datagram passes basic continuity checks (if the last fragment was received at least once).

Parameters
root_ppoints to the 'root' pbuf for the current datagram being assembled.
new_ppoints to the pbuf for the current fragment
Returns
0 if invalid, >0 otherwise

References ip_reassdata::datagram_len, ip_reassdata::flags, if(), IP_HLEN, IP_OFFMASK, IP_REASS_FLAG_LASTFRAG, ip_reass_pbufcount, IPH_HL, IPH_LEN, IPH_OFFSET, pbuf::len, LWIP_ASSERT, ntohs, NULL, ip_reassdata::p, pbuf::payload, pbuf_clen(), and pbuf_free().

Referenced by ip_reass().

static void ip_reass_dequeue_datagram ( struct ip_reassdata ipr,
struct ip_reassdata prev 
)
static

Dequeues a datagram from the datagram queue.

Doesn't deallocate the pbufs.

Parameters
iprpoints to the queue entry to dequeue

References LWIP_ASSERT, memp_free(), ip_reassdata::next, and NULL.

Referenced by ip_reass(), and ip_reass_free_complete_datagram().

static struct ip_reassdata* ip_reass_enqueue_new_datagram ( struct ip_hdr fraghdr,
int  clen 
)
static

Enqueues a new fragment into the fragment queue.

Parameters
fraghdrpoints to the new fragments IP hdr
clennumber of pbufs needed to enqueue (used for freeing other datagrams if not enough space)
Returns
A pointer to the queue location into which the fragment was enqueued

References ip_frag(), IP_HLEN, IP_REASS_DEBUG, ip_reass_remove_oldest_datagram(), IPFRAG_STATS_INC, ip_reassdata::iphdr, LWIP_DEBUGF, memp_malloc(), ip_reassdata::next, NULL, reassdatagrams, and ip_reassdata::timer.

Referenced by ip_reass().

static int ip_reass_free_complete_datagram ( struct ip_reassdata ipr,
struct ip_reassdata prev 
)
static

Free a datagram (struct ip_reassdata) and all its pbufs.

Updates the total count of enqueued pbufs (ip_reass_pbufcount), SNMP counters and sends an ICMP time exceeded packet.

Parameters
iprdatagram to free
prevthe previous datagram in the linked list
Returns
the number of pbufs freed

References ICMP_TE_FRAG, icmp_time_exceeded(), if(), IP_HLEN, ip_reass_dequeue_datagram(), ip_reass_pbufcount, ip_reassdata::iphdr, LWIP_ASSERT, ip_reassdata::next, NULL, ip_reassdata::p, pbuf::payload, pbuf_clen(), pbuf_free(), and snmp_inc_ipreasmfails.

Referenced by ip_reass_remove_oldest_datagram(), and ip_reass_tmr().

static int ip_reass_remove_oldest_datagram ( struct ip_hdr fraghdr,
int  pbufs_needed 
)
static

Free the oldest datagram to make room for enqueueing new fragments.

The datagram 'fraghdr' belongs to is not freed!

Parameters
fraghdrIP header of the current fragment
pbufs_needednumber of pbufs needed to enqueue (used for freeing other datagrams if not enough space)
Returns
the number of pbufs freed

References IP_ADDRESSES_AND_ID_MATCH, ip_reass_free_complete_datagram(), ip_reassdata::iphdr, ip_reassdata::next, NULL, reassdatagrams, and ip_reassdata::timer.

Referenced by ip_reass(), and ip_reass_enqueue_new_datagram().

void ip_reass_tmr ( void  )

Reassembly timer base function for both NO_SYS == 0 and 1 (!).

Should be called every 1000 msec (defined by IP_TMR_INTERVAL).

References IP_REASS_DEBUG, ip_reass_free_complete_datagram(), LWIP_DEBUGF, ip_reassdata::next, NULL, reassdatagrams, ip_reassdata::timer, and U16_F.

Referenced by ip_reass_timer().

PACK_STRUCT_BEGIN struct ip_reass_helper PACK_STRUCT_STRUCT