/*-----------------------------------------------------------------------------*/ void uip_split_output( void ) { u16_t tcplen, len1, len2; /* We only try to split maximum sized TCP segments. */ if( BUF->proto == UIP_PROTO_TCP && uip_len == UIP_BUFSIZE - UIP_LLH_LEN ) { tcplen = uip_len - UIP_TCPIP_HLEN; /* Split the segment in two. If the original packet length was odd, we make the second packet one byte larger. */ len1 = len2 = tcplen / 2; if( len1 + len2 < tcplen ) { ++len2; } /* Create the first packet. This is done by altering the length field of the IP header and updating the checksums. */ uip_len = len1 + UIP_TCPIP_HLEN; #if UIP_CONF_IPV6 /* For IPv6, the IP length field does not include the IPv6 IP header length. */ BUF->len[0] = ( (uip_len - UIP_IPH_LEN) >> 8 ); BUF->len[1] = ( (uip_len - UIP_IPH_LEN) & 0xff ); #else /* UIP_CONF_IPV6 */ BUF->len[0] = uip_len >> 8; BUF->len[1] = uip_len & 0xff; #endif /* UIP_CONF_IPV6 */ /* Recalculate the TCP checksum. */ BUF->tcpchksum = 0; BUF->tcpchksum = ~( uip_tcpchksum() ); #if !UIP_CONF_IPV6 /* Recalculate the IP checksum. */ BUF->ipchksum = 0; BUF->ipchksum = ~( uip_ipchksum() ); #endif /* UIP_CONF_IPV6 */ /* Transmit the first packet. */ /* uip_fw_output();*/ // tcpip_output(); /* Now, create the second packet. To do this, it is not enough to just alter the length field, but we must also update the TCP sequence number and point the uip_appdata to a new place in memory. This place is detemined by the length of the first packet (len1). */ uip_len = len2 + UIP_TCPIP_HLEN; #if UIP_CONF_IPV6 /* For IPv6, the IP length field does not include the IPv6 IP header length. */ BUF->len[0] = ( (uip_len - UIP_IPH_LEN) >> 8 ); BUF->len[1] = ( (uip_len - UIP_IPH_LEN) & 0xff ); #else /* UIP_CONF_IPV6 */ BUF->len[0] = uip_len >> 8; BUF->len[1] = uip_len & 0xff; #endif /* UIP_CONF_IPV6 */ /* uip_appdata += len1;*/ memcpy( uip_appdata, ( u8_t * ) uip_appdata + len1, len2 ); uip_add32( BUF->seqno, len1 ); BUF->seqno[0] = uip_acc32[0]; BUF->seqno[1] = uip_acc32[1]; BUF->seqno[2] = uip_acc32[2]; BUF->seqno[3] = uip_acc32[3]; /* Recalculate the TCP checksum. */ BUF->tcpchksum = 0; BUF->tcpchksum = ~( uip_tcpchksum() ); #if !UIP_CONF_IPV6 /* Recalculate the IP checksum. */ BUF->ipchksum = 0; BUF->ipchksum = ~( uip_ipchksum() ); #endif /* UIP_CONF_IPV6 */ /* Transmit the second packet. */ /* uip_fw_output();*/ // tcpip_output(); }
s8_t uip_ipinput(struct uip_pbuf *p,struct uip_netif *inp) { u16_t iphdr_len; struct uip_ip_hdr *iphdr; struct uip_netif *netif; iphdr = p->payload; if(UIP_IPH_V(iphdr)!=4) { UIP_ERROR("uip_ipinput: ip packet dropped due to bad version number.\n"); uip_pbuf_free(p); return 0; } iphdr_len = UIP_IPH_HL(iphdr); iphdr_len *= 4; if(iphdr_len>p->len) { UIP_ERROR("uip_ipinput: ip packet dropped due to too small packet size.\n"); uip_pbuf_free(p); return 0; } if(uip_ipchksum(iphdr,iphdr_len)!=0) { UIP_STAT(++uip_stat.ip.drop); UIP_STAT(++uip_stat.ip.chkerr); UIP_ERROR("uip_ipinput: bad checksum.\n"); uip_pbuf_free(p); return 0; } uip_pbuf_realloc(p,ntohs(UIP_IPH_LEN(iphdr))); for(netif=uip_netif_list;netif!=NULL;netif=netif->next) { if(uip_netif_isup(netif) && !ip_addr_isany(&netif->ip_addr)) { if(ip_addr_cmp(&iphdr->dst,&netif->ip_addr) || ip_addr_isbroadcast(&iphdr->dst,netif)) break; } } if(!netif) { UIP_ERROR("uip_ipinput: no route found.\n"); uip_pbuf_free(p); return 0; } if((UIP_IPH_OFFSET(iphdr)&htons(UIP_IP_OFFMASK|UIP_IP_MF))!=0) { #if UIP_IP_REASSEMBLY p = uip_ipreass(p); if(p==NULL) return UIP_ERR_OK; iphdr = (struct uip_ip_hdr*)p->payload; #else uip_pbuf_free(p); UIP_STAT(++uip_stat.ip.drop); UIP_ERROR("ip: fragment dropped.\n"); return 0; #endif } switch(UIP_IPH_PROTO(iphdr)) { case UIP_PROTO_TCP: uip_tcpinput(p,inp); break; case UIP_PROTO_ICMP: uip_icmpinput(p,inp); break; default: UIP_LOG("uip_ipinput: Unsupported protocol.\n"); if(!ip_addr_isbroadcast(&(iphdr->dst),inp) && !ip_addr_ismulticast(&(iphdr->dst))) { p->payload = iphdr; uip_icmp_destunreach(p,UIP_ICMP_DUR_PROTO); } uip_pbuf_free(p); break; } return 0; }
static struct uip_pbuf* uip_ipreass(struct uip_pbuf *p) { u16_t offset, len; u16_t i; struct uip_pbuf *q; struct uip_ip_hdr *iphdr,*fraghdr; /* If ip_reasstmr is zero, no packet is present in the buffer, so we write the IP header of the fragment into the reassembly buffer. The timer is updated with the maximum age. */ iphdr = (struct uip_ip_hdr*)uip_reassbuf; fraghdr = (struct uip_ip_hdr*)p->payload; if(uip_reasstmr == 0) { UIP_MEMCPY(iphdr, fraghdr, UIP_IP_HLEN); uip_reasstmr = UIP_REASS_MAXAGE; uip_reassflags = 0; uip_reasstime = gettime(); /* Clear the bitmap. */ UIP_MEMSET(uip_reassbitmap, 0,sizeof(uip_reassbitmap)); } /* Check if the incoming fragment matches the one currently present in the reasembly buffer. If so, we proceed with copying the fragment into the buffer. */ if(ip_addr_cmp(&iphdr->src,&fraghdr->src) && ip_addr_cmp(&iphdr->dst,&fraghdr->dst) && UIP_IPH_ID(iphdr) == UIP_IPH_ID(fraghdr)) { len = ntohs(UIP_IPH_LEN(fraghdr)) - UIP_IPH_HL(fraghdr)*4; offset = (ntohs(UIP_IPH_OFFSET(fraghdr))&UIP_IP_OFFMASK)*8; /* If the offset or the offset + fragment length overflows the reassembly buffer, we discard the entire packet. */ if(offset > UIP_REASS_BUFSIZE || offset + len > UIP_REASS_BUFSIZE) { uip_reasstmr = 0; uip_reasstime = 0; goto nullreturn; } /* Copy the fragment into the reassembly buffer, at the right offset. */ i = UIP_IPH_HL(fraghdr)*4; uip_copyfrom_pbuf(p,&i,&uip_reassbuf[UIP_IP_HLEN+offset],len); /* Update the bitmap. */ if(offset / (8 * 8) == (offset + len) / (8 * 8)) { /* If the two endpoints are in the same byte, we only update that byte. */ uip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8 ) & 7] & ~bitmap_bits[((offset + len) / 8 ) & 7]; } else { /* If the two endpoints are in different bytes, we update the bytes in the endpoints and fill the stuff inbetween with 0xff. */ uip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8 ) & 7]; for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) { uip_reassbitmap[i] = 0xff; } uip_reassbitmap[(offset + len) / (8 * 8)] |= ~bitmap_bits[((offset + len) / 8 ) & 7]; } /* If this fragment has the More Fragments flag set to zero, we know that this is the last fragment, so we can calculate the size of the entire packet. We also set the IP_REASS_FLAG_LASTFRAG flag to indicate that we have received the final fragment. */ if((ntohs(UIP_IPH_OFFSET(fraghdr))&UIP_IP_MF)==0) { uip_reassflags |= UIP_REASS_FLAG_LASTFRAG; uip_reasslen = offset + len; } /* Finally, we check if we have a full packet in the buffer. We do this by checking if we have the last fragment and if all bits in the bitmap are set. */ if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) { /* Check all bytes up to and including all but the last byte in the bitmap. */ for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) { if(uip_reassbitmap[i] != 0xff) { goto nullreturn; } } /* Check the last byte in the bitmap. It should contain just the right amount of bits. */ if(uip_reassbitmap[uip_reasslen / (8 * 8)] != (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) { goto nullreturn; } uip_reasslen += UIP_IP_HLEN; /* Pretend to be a "normal" (i.e., not fragmented) IP packet from now on. */ UIP_IPH_LEN_SET(iphdr,htons(uip_reasslen)); UIP_IPH_OFFSET_SET(iphdr,0); UIP_IPH_CHKSUM_SET(iphdr,0); UIP_IPH_CHKSUM_SET(iphdr,uip_ipchksum(iphdr,UIP_IP_HLEN)); /* If we have come this far, we have a full packet in the buffer, so we allocate a pbuf and copy the packet into it. We also reset the timer. */ uip_reasstmr = 0; uip_reasstime = 0; uip_pbuf_free(p); p = uip_pbuf_alloc(UIP_PBUF_LINK,uip_reasslen,UIP_PBUF_POOL); if(p==NULL) return NULL; i = 0; for(q=p;q!=NULL;q=q->next) { UIP_MEMCPY(q->payload,&uip_reassbuf[i],((q->len>(uip_reasslen-i))?(uip_reasslen-i):q->len)); i += q->len; } return p; } } nullreturn: uip_pbuf_free(p); return NULL; }
void uip_udpsend(struct uip_driver_s *dev, struct uip_udp_conn *conn) { struct uip_udpip_hdr *pudpbuf = UDPBUF; if (dev->d_sndlen > 0) { /* The total lenth to send is the size of the application data plus * the IP and UDP headers (and, eventually, the ethernet header) */ dev->d_len = dev->d_sndlen + UIP_IPUDPH_LEN; /* Initialize the IP header. Note that for IPv6, the IP length field * does not include the IPv6 IP header length. */ #ifdef CONFIG_NET_IPv6 pudpbuf->vtc = 0x60; pudpbuf->tcf = 0x00; pudpbuf->flow = 0x00; pudpbuf->len[0] = (dev->d_sndlen >> 8); pudpbuf->len[1] = (dev->d_sndlen & 0xff); pudpbuf->nexthdr = UIP_PROTO_UDP; pudpbuf->hoplimit = conn->ttl; uip_ipaddr_copy(pudpbuf->srcipaddr, &dev->d_ipaddr); uip_ipaddr_copy(pudpbuf->destipaddr, &conn->ripaddr); #else /* CONFIG_NET_IPv6 */ pudpbuf->vhl = 0x45; pudpbuf->tos = 0; pudpbuf->len[0] = (dev->d_len >> 8); pudpbuf->len[1] = (dev->d_len & 0xff); ++g_ipid; pudpbuf->ipid[0] = g_ipid >> 8; pudpbuf->ipid[1] = g_ipid & 0xff; pudpbuf->ipoffset[0] = 0; pudpbuf->ipoffset[1] = 0; pudpbuf->ttl = conn->ttl; pudpbuf->proto = UIP_PROTO_UDP; uiphdr_ipaddr_copy(pudpbuf->srcipaddr, &dev->d_ipaddr); uiphdr_ipaddr_copy(pudpbuf->destipaddr, &conn->ripaddr); /* Calculate IP checksum. */ pudpbuf->ipchksum = 0; pudpbuf->ipchksum = ~(uip_ipchksum(dev)); #endif /* CONFIG_NET_IPv6 */ /* Initialize the UDP header */ pudpbuf->srcport = conn->lport; pudpbuf->destport = conn->rport; pudpbuf->udplen = HTONS(dev->d_sndlen + UIP_UDPH_LEN); #ifdef CONFIG_NET_UDP_CHECKSUMS /* Calculate UDP checksum. */ pudpbuf->udpchksum = 0; pudpbuf->udpchksum = ~(uip_udpchksum(dev)); if (pudpbuf->udpchksum == 0) { pudpbuf->udpchksum = 0xffff; } #else pudpbuf->udpchksum = 0; #endif nllvdbg("Outgoing UDP packet length: %d (%d)\n", dev->d_len, (pudpbuf->len[0] << 8) | pudpbuf->len[1]); #ifdef CONFIG_NET_STATISTICS uip_stat.udp.sent++; uip_stat.ip.sent++; #endif }