From 3a607a197e291fc60222ddc4754ef0c9a1a40cc3 Mon Sep 17 00:00:00 2001 From: goldsimon Date: Sun, 3 Jun 2007 18:36:42 +0000 Subject: [PATCH] opt.h, ip_frag.c, ip_frag.h, ip.c: Added option IP_FRAG_USES_STATIC_BUF (defaulting to off for now) that can be set to 0 to send fragmented packets by passing PBUF_REFs down the stack. --- CHANGELOG | 5 ++ src/core/ipv4/ip.c | 4 +- src/core/ipv4/ip_frag.c | 118 ++++++++++++++++++++++++++++---- src/include/ipv4/lwip/ip_frag.h | 13 ++-- src/include/lwip/opt.h | 12 +++- 5 files changed, 131 insertions(+), 21 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 3513fbac..cdf1579a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,11 @@ HISTORY ++ New features: + 2007-05-18 Simon Goldschmidt + * opt.h, ip_frag.c, ip_frag.h, ip.c: Added option IP_FRAG_USES_STATIC_BUF + (defaulting to off for now) that can be set to 0 to send fragmented + packets by passing PBUF_REFs down the stack. + 2007-05-23 Frédéric Bernon * api_lib.c: Implement SO_RCVTIMEO for accept and recv on TCP connections, such present in patch #5959. diff --git a/src/core/ipv4/ip.c b/src/core/ipv4/ip.c index 37269a4d..8194d694 100644 --- a/src/core/ipv4/ip.c +++ b/src/core/ipv4/ip.c @@ -69,8 +69,8 @@ void ip_init(void) { -#if IP_FRAG - ip_frag_init(); +#if IP_REASSEMBLY + ip_reass_init(); #endif } diff --git a/src/core/ipv4/ip_frag.c b/src/core/ipv4/ip_frag.c index 632d02e4..f77b29cf 100644 --- a/src/core/ipv4/ip_frag.c +++ b/src/core/ipv4/ip_frag.c @@ -46,8 +46,7 @@ #include "lwip/snmp.h" #include "lwip/stats.h" -#if (IP_FRAG || IP_REASSEMBLY) - +#if IP_REASSEMBLY static u8_t ip_reassbuf[IP_HLEN + IP_REASS_BUFSIZE]; static u8_t ip_reassbitmap[IP_REASS_BUFSIZE / (8 * 8) + 1]; static const u8_t bitmap_bits[8] = { 0xff, 0x7f, 0x3f, 0x1f, @@ -58,7 +57,9 @@ static u8_t ip_reassflags; #define IP_REASS_FLAG_LASTFRAG 0x01 static u8_t ip_reasstmr; +#endif /* IP_REASSEMBLY */ +#if IP_REASSEMBLY || IP_FRAG_USES_STATIC_BUF /* * Copy len bytes from offset in pbuf to buffer * @@ -84,13 +85,14 @@ copy_from_pbuf(struct pbuf *p, u16_t * offset, } return p; } +#endif /* IP_REASSEMBLY || IP_FRAG_USES_STATIC_BUF */ - +#if IP_REASSEMBLY /** - * Initializes IP reassembly and fragmentation states. + * Initializes IP reassembly states. */ void -ip_frag_init(void) +ip_reass_init(void) { ip_reasstmr = 0; ip_reassflags = 0; @@ -299,30 +301,54 @@ nullreturn: pbuf_free(p); return NULL; } +#endif /* IP_REASSEMBLY */ +#if IP_FRAG +#if IP_FRAG_USES_STATIC_BUF static u8_t buf[MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU)]; +#endif /* IP_FRAG_USES_STATIC_BUF */ /** * 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_ROM) + * by using a fixed size static memory buffer (PBUF_REF) or + * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF). + * + * @param p ip packet to send + * @param netif the netif on which to send + * @param dest destination ip address to which to send + * + * @return ERR_OK if sent successfully, err_t otherwise */ err_t ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest) { struct pbuf *rambuf; +#if IP_FRAG_USES_STATIC_BUF struct pbuf *header; +#else + struct pbuf *newpbuf; + struct ip_hdr *original_iphdr; +#endif struct ip_hdr *iphdr; - u16_t nfb = 0; + u16_t nfb; u16_t left, cop; u16_t mtu = netif->mtu; u16_t ofo, omf; u16_t last; u16_t poff = IP_HLEN; u16_t tmp; +#if !IP_FRAG_USES_STATIC_BUF + u16_t newpbuflen, left_to_copy; +#endif /* Get a RAM based MTU sized pbuf */ +#if IP_FRAG_USES_STATIC_BUF + /* When using a static buffer, we use a PBUF_REF, which we will + * use to reference the packet (without link header). + * Layer and length is irrelevant. + */ rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF); if (rambuf == NULL) { LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n")); @@ -334,6 +360,10 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest) /* Copy the IP header in it */ iphdr = rambuf->payload; SMEMCPY(iphdr, p->payload, IP_HLEN); +#else /* IP_FRAG_USES_STATIC_BUF */ + original_iphdr = p->payload; + iphdr = original_iphdr; +#endif /* IP_FRAG_USES_STATIC_BUF */ /* Save original offset */ tmp = ntohs(IPH_OFFSET(iphdr)); @@ -342,29 +372,75 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest) left = p->tot_len - IP_HLEN; + nfb = (mtu - IP_HLEN) / 8; + while (left) { last = (left <= mtu - IP_HLEN); /* Set new offset and MF flag */ - ofo += nfb; tmp = omf | (IP_OFFMASK & (ofo)); if (!last) tmp = tmp | IP_MF; - IPH_OFFSET_SET(iphdr, htons(tmp)); /* Fill this fragment */ - nfb = (mtu - IP_HLEN) / 8; cop = last ? left : nfb * 8; +#if IP_FRAG_USES_STATIC_BUF p = copy_from_pbuf(p, &poff, (u8_t *) iphdr + IP_HLEN, cop); +#else /* IP_FRAG_USES_STATIC_BUF */ + /* When not using a static buffer, create a chain of pbufs. + * The first will be a PBUF_RAM holding the link and IP header. + * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, + * but limited to the size of an mtu. + */ + rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM); + if (rambuf == NULL) { + return ERR_MEM; + } + SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); + iphdr = rambuf->payload; + + /* Can just adjust p directly for needed offset. */ + p->payload = (u8_t *)p->payload + poff; + p->len -= poff; + + left_to_copy = cop; + while (left_to_copy) { + newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; + /* Is this pbuf already empty? */ + if (!newpbuflen) { + p = p->next; + continue; + } + newpbuf = pbuf_alloc(PBUF_RAW, 0, PBUF_REF); + if (newpbuf == NULL) { + pbuf_free(rambuf); + return ERR_MEM; + } + /* Mirror this pbuf, although we might not need all of it. */ + newpbuf->payload = p->payload; + newpbuf->len = newpbuf->tot_len = newpbuflen; + /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain + * so that it is removed when pbuf_dechain is later called on rambuf. + */ + pbuf_cat(rambuf, newpbuf); + left_to_copy -= newpbuflen; + if (left_to_copy) + p = p->next; + } + poff = newpbuflen; +#endif /* IP_FRAG_USES_STATIC_BUF */ /* Correct header */ + IPH_OFFSET_SET(iphdr, htons(tmp)); IPH_LEN_SET(iphdr, htons(cop + IP_HLEN)); IPH_CHKSUM_SET(iphdr, 0); IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); +#if IP_FRAG_USES_STATIC_BUF if (last) pbuf_realloc(rambuf, left + IP_HLEN); + /* This part is ugly: we alloc a RAM based pbuf for * the link level header for each chunk and then * free it.A PBUF_ROM style pbuf for which pbuf_header @@ -382,11 +458,29 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest) pbuf_free(rambuf); return ERR_MEM; } +#else /* IP_FRAG_USES_STATIC_BUF */ + /* No need for separate header pbuf - we allowed room for it in rambuf + * when allocated. + */ + netif->output(netif, rambuf, dest); + IPFRAG_STATS_INC(ip_frag.xmit); + + /* Unfortunately we can't reuse rambuf - the hardware may still be + * using the buffer. Instead we free it (and the ensuing chain) and + * recreate it next time round the loop. If we're lucky the hardware + * will have already sent the packet, the free will really free, and + * there will be zero memory penalty. + */ + + pbuf_free(rambuf); +#endif /* IP_FRAG_USES_STATIC_BUF */ left -= cop; + ofo += nfb; } +#if IP_FRAG_USES_STATIC_BUF pbuf_free(rambuf); +#endif /* IP_FRAG_USES_STATIC_BUF */ snmp_inc_ipfragoks(); return ERR_OK; } - -#endif /* IP_FRAG || IP_REASSEMBLY */ +#endif /* IP_FRAG */ diff --git a/src/include/ipv4/lwip/ip_frag.h b/src/include/ipv4/lwip/ip_frag.h index 081555d6..1fc58f26 100644 --- a/src/include/ipv4/lwip/ip_frag.h +++ b/src/include/ipv4/lwip/ip_frag.h @@ -39,24 +39,25 @@ #include "lwip/netif.h" #include "lwip/ip_addr.h" -#if (IP_FRAG || IP_REASSEMBLY) - #ifdef __cplusplus extern "C" { #endif -/* The IP timer interval in milliseconds. */ +#if IP_REASSEMBLY +/* The IP reassembly timer interval in milliseconds. */ #define IP_TMR_INTERVAL 1000 -void ip_frag_init(void); +void ip_reass_init(void); void ip_reass_tmr(void); struct pbuf * ip_reass(struct pbuf *p); +#endif /* IP_REASSEMBLY */ + +#if IP_FRAG err_t ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest); +#endif /* IP_FRAG */ #ifdef __cplusplus } #endif -#endif /* IP_FRAG || IP_REASSEMBLY */ - #endif /* __LWIP_IP_FRAG_H__ */ diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 61b99488..7d1b4c98 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -264,8 +264,18 @@ a lot of data that needs to be copied, this should be set high. */ #define IP_REASS_BUFSIZE 5760 #endif +/* Use a static MTU-sized buffer for IP fragmentation. + + * Otherwise pbufs are allocated and reference the original + * packet data to be fragmented. + +*/ +#ifndef IP_FRAG_USES_STATIC_BUF +#define IP_FRAG_USES_STATIC_BUF 1 +#endif + /* Assumed max MTU on any interface for IP frag buffer */ -#ifndef IP_FRAG_MAX_MTU +#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU) #define IP_FRAG_MAX_MTU 1500 #endif