/********************************************************************************************************* ** 函数名称: __inetPingRecv ** 功能描述: 接收 ping 包 ** 输 入 : iSock socket ** usSeqRecv 需要判断的 seq ** piTTL 接收到的 TTL ** 输 出 : ERROR ** 全局变量: ** 调用模块: *********************************************************************************************************/ static INT __inetPingRecv (INT iSock, UINT16 usSeqRecv, INT *piTTL) { CHAR cBuffer[512]; INT iCnt = 20; /* 默认最多接收的数据包数 */ REGISTER ssize_t sstLen; INT iAddLen = sizeof(struct sockaddr_in); struct sockaddr_in sockaddrinFrom; struct ip_hdr *iphdrFrom; struct icmp_echo_hdr *icmphdrFrom; while ((sstLen = recvfrom(iSock, cBuffer, sizeof(cBuffer), 0, (struct sockaddr *)&sockaddrinFrom, (socklen_t *)&iAddLen)) > 0) { if (sstLen >= (sizeof(struct ip_hdr) + sizeof(struct icmp_echo_hdr))) { iphdrFrom = (struct ip_hdr *)cBuffer; icmphdrFrom = (struct icmp_echo_hdr *)(cBuffer + (IPH_HL(iphdrFrom) * 4)); if ((icmphdrFrom->id == 0xAFAF) && (icmphdrFrom->seqno == htons(usSeqRecv))) { *piTTL = 0; *piTTL = (u8_t)IPH_TTL(iphdrFrom); return (ERROR_NONE); } } iCnt--; /* 接收到错误的数据包太多 */ if (iCnt < 0) { break; /* 退出 */ } } return (PX_ERROR); }
static void ping_recv(int s) { char buf[64]; int fromlen, len; struct sockaddr_in from; struct ip_hdr *iphdr; struct icmp_echo_hdr *iecho; fromlen = sizeof(from); while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0) { if (len >= (int)(sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr))) { ip_addr_t fromaddr; inet_addr_to_ipaddr(&fromaddr, &from.sin_addr); LWIP_DEBUGF( PING_DEBUG, ("ping: recv ")); ip_addr_debug_print(PING_DEBUG, &fromaddr); LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\r\n", (sys_now() - ping_time))); iphdr = (struct ip_hdr *)buf; iecho = (struct icmp_echo_hdr *)(buf + (IPH_HL(iphdr) * 4)); if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num))) { /* do some ping result processing */ PING_RESULT((ICMPH_TYPE(iecho) == ICMP_ER)); return; } else { LWIP_DEBUGF( PING_DEBUG, ("ping: drop\r\n")); } } } if (len == 0) { LWIP_DEBUGF( PING_DEBUG, ("ping: recv - %"U32_F" ms - timeout\r\n", (sys_now()-ping_time))); } /* do some ping result processing */ PING_RESULT(0); }
static void ping_recv(int s) { char* buf = NULL; int fromlen, len; struct sockaddr_in from; struct ip_hdr *iphdr; struct icmp_echo_hdr *iecho; int ms; BOOL bResult = FALSE; //Allocate a buffer to contain the received data. buf = (char*)KMemAlloc(1500,KMEM_SIZE_TYPE_ANY); if(NULL == buf) { return; } while((len = lwip_recvfrom(s, buf, 1500, 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0) { if(len >= (int)(sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr))) { ip_addr_t fromaddr; inet_addr_to_ipaddr(&fromaddr, &from.sin_addr); //Get times between sent and receive. ms = sys_now() - ping_time; ms *= SYSTEM_TIME_SLICE; iphdr = (struct ip_hdr *)buf; iecho = (struct icmp_echo_hdr *)(buf + (IPH_HL(iphdr) * 4)); if (((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num)) && iecho->type == ICMP_ER)) { len = len - sizeof(struct ip_hdr) - sizeof(struct icmp_echo_hdr); //Adjust received data's length,since it //includes IP and ICMP headers. _hx_printf(" [%d] Reply from %s,size = %d,time = %d(ms)\r\n",ping_pkt_seq,inet_ntoa(fromaddr),len,ms); ping_succ ++; bResult = TRUE; } else { //printf(" ping : Received invalid replay,drop it.\r\n"); } } } if (!bResult) { _hx_printf(" [%d] Request time out.\r\n",ping_pkt_seq); } if(buf) //Release it. { KMemFree(buf,KMEM_SIZE_TYPE_ANY,0); } }
uint8_t udp_lookup(struct ip_hdr *iphdr, struct netif *inp) { struct udp_pcb *pcb; struct udp_hdr *udphdr; uint16_t src, dest; udphdr = (struct udp_hdr *)(uint8_t *)iphdr + IPH_HL(iphdr) * 4/sizeof(uint8_t); src = NTOHS(udphdr->src); dest = NTOHS(udphdr->dest); pcb = pcb_cache; if(pcb != NULL && pcb->remote_port == src && pcb->local_port == dest && (ip_addr_isany(&pcb->remote_ip) || ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) && (ip_addr_isany(&pcb->local_ip) || ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { return 1; } else { for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { if(pcb->remote_port == src && pcb->local_port == dest && (ip_addr_isany(&pcb->remote_ip) || ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) && (ip_addr_isany(&pcb->local_ip) || ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { pcb_cache = pcb; break; } } if(pcb == NULL) { for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { if(pcb->local_port == dest && (ip_addr_isany(&pcb->remote_ip) || ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) && (ip_addr_isany(&pcb->local_ip) || ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { break; } } } } if(pcb != NULL) { return 1; } else { return 1; } }
static u8_t ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr) { struct ip_hdr *iphdr; struct icmp_echo_hdr *iecho; LWIP_UNUSED_ARG(arg); LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(addr); LWIP_ASSERT("p != NULL", p != NULL); if ((p->tot_len >= (PBUF_IP_HLEN + sizeof(struct icmp_echo_hdr)))) { iphdr = (struct ip_hdr *)p->payload; iecho = (struct icmp_echo_hdr *)(p->payload + (IPH_HL(iphdr) * 4)); if ((lns.ping_reply != NULL) && (iecho->id == PING_ID) && (iecho->seqno == htons(lns.ping_seq_num))) { lns.ping_recv_tstamp = vmm_timer_timestamp(); lns.ping_reply->ripaddr[0] = ip4_addr1(&lns.ping_addr); lns.ping_reply->ripaddr[1] = ip4_addr2(&lns.ping_addr); lns.ping_reply->ripaddr[2] = ip4_addr3(&lns.ping_addr); lns.ping_reply->ripaddr[3] = ip4_addr4(&lns.ping_addr); lns.ping_reply->ttl = IPH_TTL(iphdr); lns.ping_reply->len = p->tot_len - (IPH_HL(iphdr) * 4); lns.ping_reply->seqno = lns.ping_seq_num; vmm_completion_complete(&lns.ping_done); /* Free the pbuf */ pbuf_free(p); /* Eat the packet. lwIP should not process it. */ return 1; } } /* Don't eat the packet. Let lwIP process it. */ return 0; }
/* Update UDP datagram's check sum accordingly. */ static void _udp_check_sum(struct ip_hdr* p, struct pbuf* pb) { struct udp_hdr* pUdpHdr = NULL; int iph_len = IPH_HL(p); LWIP_UNUSED_ARG(pb); iph_len *= 4; pUdpHdr = (struct udp_hdr*)((char*)p + iph_len); __NATDEBUG("%s: reset UDP chksum from [%x] to 0.\r\n", __func__, pUdpHdr->chksum); pUdpHdr->chksum = 0; /* Reset check sum. */ }
/* * Validate a TCP segment's checksum,return TRUE if pass the validation, * FALSE will be returned otherwise. */ static BOOL validateTCPChksum(struct ip_hdr* p, struct pbuf* pb) { struct tcp_hdr* pTcpHdr = NULL; int iph_len = IPH_HL(p); int ip_len = ntohs(IPH_LEN(p)); /* Total IP packet length. */ int chksum_old = 0, chksum_new = 0; ip_addr_t src, dest; iph_len *= 4; /* Locate TCP header. */ pTcpHdr = (struct tcp_hdr*)((char*)p + iph_len); /* Validate pbuf object. */ if (pb->tot_len < (iph_len + sizeof(struct tcp_hdr))) { return FALSE; } /* Validate the length of this packet. */ if (ip_len < (iph_len + sizeof(struct tcp_hdr))) { return FALSE; } /* * Preserve TCP segment's check sum value before re-calculate * the value. */ chksum_old = pTcpHdr->chksum; ip_addr_copy(src, p->src); ip_addr_copy(dest, p->dest); pbuf_header(pb, -iph_len); /* move to TCP header. */ pTcpHdr->chksum = 0; /* Reset the original check sum. */ /* Recalculate the segment's checksum value. */ chksum_new = inet_chksum_pseudo(pb, &src, &dest, IP_PROTO_TCP, /* IP payload length,e.i,TCP header plus data. */ ip_len - iph_len); //pb->tot_len); pbuf_header(pb, iph_len); /* move back. */ if (chksum_new != chksum_old) { __LOG("TCP checksum fail:ip_len = %d,pbuf_tot_len = %d,src_addr:%s\r\n", ip_len, pb->tot_len, inet_ntoa(p->src.addr)); IP_STATS_INC(tcp.chkerr); IP_STATS_INC(tcp.drop); return FALSE; } return TRUE; }
/* Check if there is an entry that for a given output IP packet. */ static BOOL _OutPacketMatch(struct ip_hdr* pHdr, __EASY_NAT_ENTRY* pNatEntry) { struct tcp_hdr* pTcpHdr = NULL; struct udp_hdr* pUdpHdr = NULL; int iph_len = 0; BUG_ON(NULL == pHdr); BUG_ON(NULL == pNatEntry); /* Increment total match times counter. */ NatManager.stat.match_times++; /* Check according protocol type. */ iph_len = IPH_HL(pHdr); iph_len *= 4; switch (pHdr->_proto) { case IP_PROTO_TCP: pTcpHdr = (struct tcp_hdr*)((char*)pHdr + iph_len); if ((pHdr->src.addr == pNatEntry->srcAddr_bef.addr) && (pHdr->dest.addr == pNatEntry->dstAddr_bef.addr) && (pTcpHdr->src == htons(pNatEntry->srcPort_bef)) && (pTcpHdr->dest == htons(pNatEntry->dstPort_bef))) { return TRUE; } return FALSE; break; case IP_PROTO_UDP: pUdpHdr = (struct udp_hdr*)((char*)pHdr + iph_len); if ((pHdr->src.addr == pNatEntry->srcAddr_bef.addr) && (pHdr->dest.addr == pNatEntry->dstAddr_bef.addr) && (pUdpHdr->src == htons(pNatEntry->srcPort_bef)) && (pUdpHdr->dest == htons(pNatEntry->dstPort_bef))) { return TRUE; } return FALSE; break; case IP_PROTO_ICMP: return OutPacketMatch_ICMP(pNatEntry, pHdr); break; default: return FALSE; break; } return FALSE; }
/* Output direction translation. */ static void OutTranslation(__EASY_NAT_ENTRY* pEntry, struct ip_hdr* pHdr,struct pbuf* pb) { struct tcp_hdr* pTcpHdr = NULL; struct udp_hdr* pUdpHdr = NULL; int iph_len = 0; BUG_ON(NULL == pEntry); BUG_ON(NULL == pHdr); BUG_ON(NULL == pb); /* * Update NAT entry state info. * It must be done before actual translation,since it maybe * altered in specific protocol's translation process,such * as TCP,it may set the entry's timeout value to MAX to * purge the entry as soon as possible,in case of the TCP * connection released. */ pEntry->ms = 0; pEntry->match_times++; /* Translate address first. */ pHdr->src.addr = pEntry->srcAddr_aft.addr; /* Farther translation according protocol. */ iph_len = IPH_HL(pHdr); iph_len *= 4; switch (pHdr->_proto) { case IP_PROTO_TCP: pTcpHdr = (struct tcp_hdr*)((char*)pHdr + iph_len); //pTcpHdr->src = htons(pEntry->srcPort_aft); TcpTranslation(pEntry, pTcpHdr, out); break; case IP_PROTO_UDP: pUdpHdr = (struct udp_hdr*)((char*)pHdr + iph_len); pUdpHdr->src = htons(pEntry->srcPort_aft); break; case IP_PROTO_ICMP: OutTranslation_ICMP(pEntry, pHdr, pb); break; default: break; } /* Update the packet's checksum. */ _iphdr_check_sum(pHdr, pb); }
u8_t ip_lookup(void *header, struct netif *inp) { struct ip_hdr *iphdr; iphdr = header; /* Refuse anything that isn't IPv4. */ if(IPH_V(iphdr) != 4) { return 0; } /* Immediately accept/decline packets that are fragments or has options. */ #if IP_REASSEMBLY == 0 /* if((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) { return 0; }*/ #endif /* IP_REASSEMBLY == 0 */ #if IP_OPTIONS == 0 if(IPH_HL(iphdr) != 5) { return 0; } #endif /* IP_OPTIONS == 0 */ switch(IPH_PROTO(iphdr)) { #if LWIP_UDP > 0 case IP_PROTO_UDP: return udp_lookup(iphdr, inp); break; #endif /* LWIP_UDP */ #if LWIP_TCP > 0 case IP_PROTO_TCP: return 1; #endif /* LWIP_TCP */ case IP_PROTO_ICMP: return 1; break; default: return 0; } }
void ip_debug_print(struct pbuf *p) { struct ip_hdr *iphdr = p->payload; u8_t *payload; payload = (u8_t *)iphdr + IP_HLEN/sizeof(u8_t); DEBUGF(IP_DEBUG, ("IP header:\n")); DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); DEBUGF(IP_DEBUG, ("|%2d |%2d | %2d | %4d | (v, hl, tos, len)\n", IPH_V(iphdr), IPH_HL(iphdr), IPH_TOS(iphdr), ntohs(IPH_LEN(iphdr)))); DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); DEBUGF(IP_DEBUG, ("| %5d |%d%d%d| %4d | (id, flags, offset)\n", ntohs(IPH_ID(iphdr)), ntohs(IPH_OFFSET(iphdr)) >> 15 & 1, ntohs(IPH_OFFSET(iphdr)) >> 14 & 1, ntohs(IPH_OFFSET(iphdr)) >> 13 & 1, ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)); DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); DEBUGF(IP_DEBUG, ("| %2d | %2d | 0x%04x | (ttl, proto, chksum)\n", IPH_TTL(iphdr), IPH_PROTO(iphdr), ntohs(IPH_CHKSUM(iphdr)))); DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); DEBUGF(IP_DEBUG, ("| %3ld | %3ld | %3ld | %3ld | (src)\n", ntohl(iphdr->src.addr) >> 24 & 0xff, ntohl(iphdr->src.addr) >> 16 & 0xff, ntohl(iphdr->src.addr) >> 8 & 0xff, ntohl(iphdr->src.addr) & 0xff)); DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); DEBUGF(IP_DEBUG, ("| %3ld | %3ld | %3ld | %3ld | (dest)\n", ntohl(iphdr->dest.addr) >> 24 & 0xff, ntohl(iphdr->dest.addr) >> 16 & 0xff, ntohl(iphdr->dest.addr) >> 8 & 0xff, ntohl(iphdr->dest.addr) & 0xff)); DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); }
/* Update TCP segment's check sum. */ static void _tcp_check_sum(struct ip_hdr* p, struct pbuf* pb) { struct tcp_hdr* pTcpHdr = NULL; int iph_len = IPH_HL(p); int ip_len = ntohs(IPH_LEN(p)); /* Total IP packet's length. */ int chksum = 0; ip_addr_t src, dest; iph_len *= 4; /* Locate TCP header. */ pTcpHdr = (struct tcp_hdr*)((char*)p + iph_len); /* Validate pbuf object. */ if (pb->tot_len < (iph_len + sizeof(struct tcp_hdr))) { return; } /* Validate IP packet's total length. */ if (ip_len < (iph_len + sizeof(struct tcp_hdr))) { return; } /* * Reset TCP header's check sum since it's source address * or source port is changed after NATing. */ chksum = pTcpHdr->chksum; ip_addr_copy(src, p->src); ip_addr_copy(dest, p->dest); pbuf_header(pb, -iph_len); /* move to TCP header. */ pTcpHdr->chksum = 0; /* Reset the original check sum. */ pTcpHdr->chksum = inet_chksum_pseudo(pb, &src, &dest, IP_PROTO_TCP, ip_len - iph_len); pbuf_header(pb, iph_len); /* move back. */ __NATDEBUG("%s: TCP check sum updated[%X] -> [%X]\r\n", __func__, chksum, pTcpHdr->chksum); }
/* Initialize a new NAT entry giving the IP header. */ static void InitNatEntry(__EASY_NAT_ENTRY* pEntry, struct ip_hdr* pHdr, struct netif* pOutIf) { struct udp_hdr* pUdpHdr = NULL; struct tcp_hdr* pTcpHdr = NULL; int iph_len = 0; /* Set NAT entry according IP header. */ pEntry->srcAddr_bef.addr = pHdr->src.addr; pEntry->dstAddr_bef.addr = pHdr->dest.addr; pEntry->srcAddr_aft.addr = pOutIf->ip_addr.addr; /* Changed. */ pEntry->dstAddr_aft.addr = pHdr->dest.addr; pEntry->protocol = pHdr->_proto; pEntry->netif = pOutIf; pEntry->ms = 0; pEntry->match_times++; iph_len = IPH_HL(pHdr); iph_len *= 4; switch (pHdr->_proto) { case IP_PROTO_TCP: pTcpHdr = (struct tcp_hdr*)((char*)pHdr + iph_len); pEntry->srcPort_bef = ntohs(pTcpHdr->src); pEntry->srcPort_aft = ntohs(GetTCPSrcPort()); /* Changed. */ pEntry->dstPort_bef = ntohs(pTcpHdr->dest); pEntry->dstPort_aft = ntohs(pTcpHdr->dest); break; case IP_PROTO_UDP: pUdpHdr = (struct udp_hdr*)((char*)pHdr + iph_len); pEntry->srcPort_bef = ntohs(pUdpHdr->src); pEntry->srcPort_aft = ntohs(GetUDPSrcPort()); /* Changed. */ pEntry->dstPort_bef = ntohs(pUdpHdr->dest); pEntry->dstPort_aft = ntohs(pUdpHdr->dest); break; case IP_PROTO_ICMP: InitNatEntry_ICMP(pEntry, pHdr); break; default: break; } }
void ip_debug_print(struct pbuf *p) { struct ip_hdr *iphdr = p->payload; u8_t *payload; payload = (u8_t *)iphdr + IP_HLEN; LWIP_DEBUGF(IP_DEBUG, ("IP header:\n")); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" | 0x%02"X16_F" | %5"U16_F" | (v, hl, tos, len)\n", IPH_V(iphdr), IPH_HL(iphdr), IPH_TOS(iphdr), ntohs(IPH_LEN(iphdr)))); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n", ntohs(IPH_ID(iphdr)), ntohs(IPH_OFFSET(iphdr)) >> 15 & 1, ntohs(IPH_OFFSET(iphdr)) >> 14 & 1, ntohs(IPH_OFFSET(iphdr)) >> 13 & 1, ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\n", IPH_TTL(iphdr), IPH_PROTO(iphdr), ntohs(IPH_CHKSUM(iphdr)))); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n", ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src), ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src))); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n", ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest), ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest))); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); }
static void show_ip_pkt(struct pbuf *p) { struct ip_hdr *iphdr = (struct ip_hdr *)p->payload; u8_t *payload; payload = (u8_t *)iphdr + IP_HLEN; _hx_printf("[%s]IP header:\r\n",__func__); _hx_printf("+-------------------------------+\r\n"); _hx_printf("|%2"S16_F" |%2"S16_F" | 0x%02"X16_F" | %5"U16_F" | (v, hl, tos, len)\r\n", IPH_V(iphdr), IPH_HL(iphdr), IPH_TOS(iphdr), ntohs(IPH_LEN(iphdr))); _hx_printf("+-------------------------------+\r\n"); _hx_printf("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\r\n", ntohs(IPH_ID(iphdr)), ntohs(IPH_OFFSET(iphdr)) >> 15 & 1, ntohs(IPH_OFFSET(iphdr)) >> 14 & 1, ntohs(IPH_OFFSET(iphdr)) >> 13 & 1, ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK); _hx_printf("+-------------------------------+\r\n"); _hx_printf("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\r\n", IPH_TTL(iphdr), IPH_PROTO(iphdr), ntohs(IPH_CHKSUM(iphdr))); _hx_printf("+-------------------------------+\r\n"); _hx_printf("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\r\n", ip4_addr1_16(&iphdr->src), ip4_addr2_16(&iphdr->src), ip4_addr3_16(&iphdr->src), ip4_addr4_16(&iphdr->src)); _hx_printf("+-------------------------------+\r\n"); _hx_printf("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\r\n", ip4_addr1_16(&iphdr->dest), ip4_addr2_16(&iphdr->dest), ip4_addr3_16(&iphdr->dest), ip4_addr4_16(&iphdr->dest)); _hx_printf("+-------------------------------+\r\n"); }
/** * Reassembles incoming IP fragments into an IP datagram. * * @param p points to a pbuf chain of the fragment * @return NULL if reassembly is incomplete, ? otherwise */ struct pbuf * ip_reass(struct pbuf *p) { struct pbuf *r; struct ip_hdr *fraghdr; struct ip_reassdata *ipr; struct ip_reass_helper *iprh; u16_t offset, len; u8_t clen; struct ip_reassdata *ipr_prev = NULL; IPFRAG_STATS_INC(ip_frag.recv); snmp_inc_ipreasmreqds(); fraghdr = (struct ip_hdr*)p->payload; if ((IPH_HL(fraghdr) * 4) != IP_HLEN) { LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n")); IPFRAG_STATS_INC(ip_frag.err); goto nullreturn; } offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; /* Check if we are allowed to enqueue more datagrams. */ clen = pbuf_clen(p); if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) { #if IP_REASS_FREE_OLDEST if (!ip_reass_remove_oldest_datagram(fraghdr, clen) || ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS)) #endif /* IP_REASS_FREE_OLDEST */ { /* No datagram could be freed and still too many pbufs enqueued */ LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n", ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS)); IPFRAG_STATS_INC(ip_frag.memerr); /* @todo: send ICMP time exceeded here? */ /* drop this pbuf */ goto nullreturn; } } /* Look for the datagram the fragment belongs to in the current datagram queue, * remembering the previous in the queue for later dequeueing. */ for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) { /* Check if the incoming fragment matches the one currently present in the reassembly buffer. If so, we proceed with copying the fragment into the buffer. */ if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) { LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n", ntohs(IPH_ID(fraghdr)))); IPFRAG_STATS_INC(ip_frag.cachehit); break; } ipr_prev = ipr; } if (ipr == NULL) { /* Enqueue a new datagram into the datagram queue */ ipr = ip_reass_enqueue_new_datagram(fraghdr, clen); /* Bail if unable to enqueue */ if(ipr == NULL) { goto nullreturn; } } else { if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) && ((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) { /* ipr->iphdr is not the header from the first fragment, but fraghdr is * -> copy fraghdr into ipr->iphdr since we want to have the header * of the first fragment (for ICMP time exceeded and later, for copying * all options, if supported)*/ SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN); } } /* Track the current number of pbufs current 'in-flight', in order to limit the number of fragments that may be enqueued at any one time */ ip_reass_pbufcount += clen; /* At this point, we have either created a new entry or pointing * to an existing one */ /* check for 'no more fragments', and update queue entry*/ if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) { ipr->flags |= IP_REASS_FLAG_LASTFRAG; ipr->datagram_len = offset + len; LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: last fragment seen, total len %"S16_F"\n", ipr->datagram_len)); } /* find the right place to insert this pbuf */ /* @todo: trim pbufs if fragments are overlapping */ if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) { /* the totally last fragment (flag more fragments = 0) was received at least * once AND all fragments are received */ ipr->datagram_len += IP_HLEN; /* save the second pbuf before copying the header over the pointer */ r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf; /* copy the original ip header back to the first pbuf */ fraghdr = (struct ip_hdr*)(ipr->p->payload); SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN); IPH_LEN_SET(fraghdr, htons(ipr->datagram_len)); IPH_OFFSET_SET(fraghdr, 0); IPH_CHKSUM_SET(fraghdr, 0); /* @todo: do we need to set calculate the correct checksum? */ IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN)); p = ipr->p; /* chain together the pbufs contained within the reass_data list. */ while(r != NULL) { iprh = (struct ip_reass_helper*)r->payload; /* hide the ip header for every succeding fragment */ pbuf_header(r, -IP_HLEN); pbuf_cat(p, r); r = iprh->next_pbuf; } /* release the sources allocate for the fragment queue entry */ ip_reass_dequeue_datagram(ipr, ipr_prev); /* and adjust the number of pbufs currently queued for reassembly. */ ip_reass_pbufcount -= pbuf_clen(p); /* Return the pbuf chain */ return p; } /* the datagram is not (yet?) reassembled completely */ LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount)); return NULL; nullreturn: LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n")); IPFRAG_STATS_INC(ip_frag.drop); pbuf_free(p); return NULL; }
/** * 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). * @param root_p points to the 'root' pbuf for the current datagram being assembled. * @param new_p points to the pbuf for the current fragment * @return 0 if invalid, >0 otherwise */ static int ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p) { struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL; struct pbuf *q; u16_t offset,len; struct ip_hdr *fraghdr; int valid = 1; /* Extract length and fragment offset from current fragment */ fraghdr = (struct ip_hdr*)new_p->payload; len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; /* overwrite the fragment's ip header from the pbuf with our helper struct, * and setup the embedded helper structure. */ /* make sure the struct ip_reass_helper fits into the IP header */ LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN", sizeof(struct ip_reass_helper) <= IP_HLEN); iprh = (struct ip_reass_helper*)new_p->payload; iprh->next_pbuf = NULL; iprh->start = offset; iprh->end = offset + len; /* Iterate through until we either get to the end of the list (append), * or we find on with a larger offset (insert). */ for (q = ipr->p; q != NULL;) { iprh_tmp = (struct ip_reass_helper*)q->payload; if (iprh->start < iprh_tmp->start) { /* the new pbuf should be inserted before this */ iprh->next_pbuf = q; if (iprh_prev != NULL) { /* not the fragment with the lowest offset */ #if IP_REASS_CHECK_OVERLAP if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) { /* fragment overlaps with previous or following, throw away */ goto freepbuf; } #endif /* IP_REASS_CHECK_OVERLAP */ iprh_prev->next_pbuf = new_p; } else { /* fragment with the lowest offset */ ipr->p = new_p; } break; } else if(iprh->start == iprh_tmp->start) { /* received the same datagram twice: no need to keep the datagram */ goto freepbuf; #if IP_REASS_CHECK_OVERLAP } else if(iprh->start < iprh_tmp->end) { /* overlap: no need to keep the new datagram */ goto freepbuf; #endif /* IP_REASS_CHECK_OVERLAP */ } else { /* Check if the fragments received so far have no wholes. */ if (iprh_prev != NULL) { if (iprh_prev->end != iprh_tmp->start) { /* There is a fragment missing between the current * and the previous fragment */ valid = 0; } } } q = iprh_tmp->next_pbuf; iprh_prev = iprh_tmp; } /* If q is NULL, then we made it to the end of the list. Determine what to do now */ if (q == NULL) { if (iprh_prev != NULL) { /* this is (for now), the fragment with the highest offset: * chain it to the last fragment */ #if IP_REASS_CHECK_OVERLAP LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start); #endif /* IP_REASS_CHECK_OVERLAP */ iprh_prev->next_pbuf = new_p; if (iprh_prev->end != iprh->start) { valid = 0; } } else { #if IP_REASS_CHECK_OVERLAP LWIP_ASSERT("no previous fragment, this must be the first fragment!", ipr->p == NULL); #endif /* IP_REASS_CHECK_OVERLAP */ /* this is the first fragment we ever received for this ip datagram */ ipr->p = new_p; } } /* At this point, the validation part begins: */ /* If we already received the last fragment */ if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) { /* and had no wholes so far */ if (valid) { /* then check if the rest of the fragments is here */ /* Check if the queue starts with the first datagram */ if (((struct ip_reass_helper*)ipr->p->payload)->start != 0) { valid = 0; } else { /* and check that there are no wholes after this datagram */ iprh_prev = iprh; q = iprh->next_pbuf; while (q != NULL) { iprh = (struct ip_reass_helper*)q->payload; if (iprh_prev->end != iprh->start) { valid = 0; break; } iprh_prev = iprh; q = iprh->next_pbuf; } /* if still valid, all fragments are received * (because to the MF==0 already arrived */ if (valid) { LWIP_ASSERT("sanity check", ipr->p != NULL); LWIP_ASSERT("sanity check", ((struct ip_reass_helper*)ipr->p->payload) != iprh); LWIP_ASSERT("validate_datagram:next_pbuf!=NULL", iprh->next_pbuf == NULL); LWIP_ASSERT("validate_datagram:datagram end!=datagram len", iprh->end == ipr->datagram_len); } } } /* If valid is 0 here, there are some fragments missing in the middle * (since MF == 0 has already arrived). Such datagrams simply time out if * no more fragments are received... */ return valid; } /* If we come here, not all fragments were received, yet! */ return 0; /* not yet valid! */ #if IP_REASS_CHECK_OVERLAP freepbuf: ip_reass_pbufcount -= pbuf_clen(new_p); pbuf_free(new_p); return 0; #endif /* IP_REASS_CHECK_OVERLAP */ }
/** * Process an incoming UDP datagram. * * Given an incoming UDP datagram (as a chain of pbufs) this function * finds a corresponding UDP PCB and hands over the pbuf to the pcbs * recv function. If no pcb is found or the datagram is incorrect, the * pbuf is freed. * * @param p pbuf to be demultiplexed to a UDP PCB. * @param inp network interface on which the datagram was received. * */ void udp_input(struct pbuf *p, struct netif *inp) { struct udp_hdr *udphdr; struct udp_pcb *pcb, *prev; struct udp_pcb *uncon_pcb; struct ip_hdr *iphdr; u16_t src, dest; u8_t local_match; u8_t broadcast; PERF_START; UDP_STATS_INC(udp.recv); iphdr = (struct ip_hdr *)p->payload; /* Check minimum length (IP header + UDP header) * and move payload pointer to UDP header */ if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) { /* drop short packets */ LWIP_DEBUGF(UDP_DEBUG, ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len)); UDP_STATS_INC(udp.lenerr); UDP_STATS_INC(udp.drop); snmp_inc_udpinerrors(); pbuf_free(p); goto end; } udphdr = (struct udp_hdr *)p->payload; /* is broadcast packet ? */ broadcast = ip_addr_isbroadcast(¤t_iphdr_dest, inp); LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); /* convert src and dest ports to host byte order */ src = ntohs(udphdr->src); dest = ntohs(udphdr->dest); udp_debug_print(udphdr); /* print the UDP source and destination */ LWIP_DEBUGF(UDP_DEBUG, ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- " "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", ip4_addr1_16(&iphdr->dest), ip4_addr2_16(&iphdr->dest), ip4_addr3_16(&iphdr->dest), ip4_addr4_16(&iphdr->dest), ntohs(udphdr->dest), ip4_addr1_16(&iphdr->src), ip4_addr2_16(&iphdr->src), ip4_addr3_16(&iphdr->src), ip4_addr4_16(&iphdr->src), ntohs(udphdr->src))); #if LWIP_DHCP pcb = NULL; /* when LWIP_DHCP is active, packets to DHCP_CLIENT_PORT may only be processed by the dhcp module, no other UDP pcb may use the local UDP port DHCP_CLIENT_PORT */ if (dest == DHCP_CLIENT_PORT) { /* all packets for DHCP_CLIENT_PORT not coming from DHCP_SERVER_PORT are dropped! */ if (src == DHCP_SERVER_PORT) { if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) { /* accept the packe if (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY! - inp->dhcp->pcb->remote == ANY or iphdr->src */ if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) || ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), ¤t_iphdr_src))) { pcb = inp->dhcp->pcb; } } } } else #endif /* LWIP_DHCP */ { prev = NULL; local_match = 0; uncon_pcb = NULL; /* Iterate through the UDP pcb list for a matching pcb. * 'Perfect match' pcbs (connected to the remote port & ip address) are * preferred. If no perfect match is found, the first unconnected pcb that * matches the local port and ip address gets the datagram. */ for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { local_match = 0; /* print the PCB local and remote address */ LWIP_DEBUGF(UDP_DEBUG, ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- " "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip), ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), pcb->local_port, ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip), pcb->remote_port)); /* compare PCB local addr+port to UDP destination addr+port */ if (pcb->local_port == dest) { if ( (!broadcast && ip_addr_isany(&pcb->local_ip)) || ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest) || #if LWIP_IGMP ip_addr_ismulticast(¤t_iphdr_dest) || #endif /* LWIP_IGMP */ #if IP_SOF_BROADCAST_RECV (broadcast && ip_get_option(pcb, SOF_BROADCAST) && (ip_addr_isany(&pcb->local_ip) || ip_addr_netcmp(&pcb->local_ip, ip_current_dest_addr(), &inp->netmask)))) { #else /* IP_SOF_BROADCAST_RECV */ (broadcast && (ip_addr_isany(&pcb->local_ip) || ip_addr_netcmp(&pcb->local_ip, ip_current_dest_addr(), &inp->netmask)))) { #endif /* IP_SOF_BROADCAST_RECV */ local_match = 1; if ((uncon_pcb == NULL) && ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) { /* the first unconnected matching PCB */ uncon_pcb = pcb; } } } /* compare PCB remote addr+port to UDP source addr+port */ if ((local_match != 0) && (pcb->remote_port == src) && (ip_addr_isany(&pcb->remote_ip) || ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src))) { /* the first fully matching PCB */ if (prev != NULL) { /* move the pcb to the front of udp_pcbs so that is found faster next time */ prev->next = pcb->next; pcb->next = udp_pcbs; udp_pcbs = pcb; } else { UDP_STATS_INC(udp.cachehit); } break; } prev = pcb; } /* no fully matching pcb found? then look for an unconnected pcb */ if (pcb == NULL) { pcb = uncon_pcb; } } /* Check checksum if this is a match or if it was directed at us. */ if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, ¤t_iphdr_dest)) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n")); #if LWIP_UDPLITE if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) { /* Do the UDP Lite checksum */ #if CHECKSUM_CHECK_UDP u16_t chklen = ntohs(udphdr->len); if (chklen < sizeof(struct udp_hdr)) { if (chklen == 0) { /* For UDP-Lite, checksum length of 0 means checksum over the complete packet (See RFC 3828 chap. 3.1) */ chklen = p->tot_len; } else { /* At least the UDP-Lite header must be covered by the checksum! (Again, see RFC 3828 chap. 3.1) */ UDP_STATS_INC(udp.chkerr); UDP_STATS_INC(udp.drop); snmp_inc_udpinerrors(); pbuf_free(p); goto end; } } if (inet_chksum_pseudo_partial(p, ¤t_iphdr_src, ¤t_iphdr_dest, IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_input: UDP Lite datagram discarded due to failing checksum\n")); UDP_STATS_INC(udp.chkerr); UDP_STATS_INC(udp.drop); snmp_inc_udpinerrors(); pbuf_free(p); goto end; } #endif /* CHECKSUM_CHECK_UDP */ } else #endif /* LWIP_UDPLITE */ { #if CHECKSUM_CHECK_UDP if (udphdr->chksum != 0) { if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), IP_PROTO_UDP, p->tot_len) != 0) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_input: UDP datagram discarded due to failing checksum\n")); UDP_STATS_INC(udp.chkerr); UDP_STATS_INC(udp.drop); snmp_inc_udpinerrors(); pbuf_free(p); goto end; } } #endif /* CHECKSUM_CHECK_UDP */ } if(pbuf_header(p, -UDP_HLEN)) { /* Can we cope with this failing? Just assert for now */ LWIP_ASSERT("pbuf_header failed\n", 0); UDP_STATS_INC(udp.drop); snmp_inc_udpinerrors(); pbuf_free(p); goto end; } if (pcb != NULL) { snmp_inc_udpindatagrams(); #if SO_REUSE && SO_REUSE_RXTOALL if ((broadcast || ip_addr_ismulticast(¤t_iphdr_dest)) && ip_get_option(pcb, SOF_REUSEADDR)) { /* pass broadcast- or multicast packets to all multicast pcbs if SOF_REUSEADDR is set on the first match */ struct udp_pcb *mpcb; u8_t p_header_changed = 0; for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) { if (mpcb != pcb) { /* compare PCB local addr+port to UDP destination addr+port */ if ((mpcb->local_port == dest) && ((!broadcast && ip_addr_isany(&mpcb->local_ip)) || ip_addr_cmp(&(mpcb->local_ip), ¤t_iphdr_dest) || #if LWIP_IGMP ip_addr_ismulticast(¤t_iphdr_dest) || #endif /* LWIP_IGMP */ #if IP_SOF_BROADCAST_RECV (broadcast && ip_get_option(mpcb, SOF_BROADCAST)))) { #else /* IP_SOF_BROADCAST_RECV */ (broadcast))) { #endif /* IP_SOF_BROADCAST_RECV */ /* pass a copy of the packet to all local matches */ if (mpcb->recv != NULL) { struct pbuf *q; /* for that, move payload to IP header again */ if (p_header_changed == 0) { pbuf_header(p, (s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); p_header_changed = 1; } q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); if (q != NULL) { err_t err = pbuf_copy(q, p); if (err == ERR_OK) { /* move payload to UDP data */ pbuf_header(q, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src); } } } } } } if (p_header_changed) { /* and move payload to UDP data again */ pbuf_header(p, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); } } #endif /* SO_REUSE && SO_REUSE_RXTOALL */ /* callback */ if (pcb->recv != NULL) { /* now the recv function is responsible for freeing p */ pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src); } else { /* no recv function registered? then we have to free the pbuf! */ pbuf_free(p); goto end; } } else {
/** * This function is called by the network interface device driver when * an IP packet is received. The function does the basic checks of the * IP header such as packet size being at least larger than the header * size etc. If the packet was not destined for us, the packet is * forwarded (using ip_forward). The IP checksum is always checked. * * Finally, the packet is sent to the upper layer protocol input function. * * @param p the received IP packet (p->payload points to IP header) * @param inp the netif on which this packet was received * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't * processed, but currently always returns ERR_OK) */ err_t ip_input(struct pbuf *p, struct netif *inp) { struct ip_hdr *iphdr; struct netif *netif; u16_t iphdr_hlen; u16_t iphdr_len; #if LWIP_DHCP int check_ip_src=1; #endif /* LWIP_DHCP */ IP_STATS_INC(ip.recv); snmp_inc_ipinreceives(); /* identify the IP header */ iphdr = p->payload; if (IPH_V(iphdr) != 4) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr))); ip_debug_print(p); pbuf_free(p); IP_STATS_INC(ip.err); IP_STATS_INC(ip.drop); snmp_inc_ipinhdrerrors(); return ERR_OK; } /* obtain IP header length in number of 32-bit words */ iphdr_hlen = IPH_HL(iphdr); /* calculate IP header length in bytes */ iphdr_hlen *= 4; /* obtain ip length in bytes */ iphdr_len = ntohs(IPH_LEN(iphdr)); /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */ if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) { if (iphdr_hlen > p->len) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n", iphdr_hlen, p->len)); } if (iphdr_len > p->tot_len) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n", iphdr_len, p->tot_len)); } /* free (drop) packet pbufs */ pbuf_free(p); IP_STATS_INC(ip.lenerr); IP_STATS_INC(ip.drop); snmp_inc_ipindiscards(); return ERR_OK; } /* verify checksum */ #if CHECKSUM_CHECK_IP if (inet_chksum(iphdr, iphdr_hlen) != 0) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen))); ip_debug_print(p); pbuf_free(p); IP_STATS_INC(ip.chkerr); IP_STATS_INC(ip.drop); snmp_inc_ipinhdrerrors(); return ERR_OK; } #endif /* Trim pbuf. This should have been done at the netif layer, * but we'll do it anyway just to be sure that its done. */ pbuf_realloc(p, iphdr_len); /* match packet against an interface, i.e. is this packet for us? */ #if LWIP_IGMP if (ip_addr_ismulticast(&(iphdr->dest))) { if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &(iphdr->dest)))) { netif = inp; } else { netif = NULL; } } else #endif /* LWIP_IGMP */ { /* start trying with inp. if that's not acceptable, start walking the list of configured netifs. 'first' is used as a boolean to mark whether we started walking the list */ int first = 1; netif = inp; do { LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n", iphdr->dest.addr, netif->ip_addr.addr, iphdr->dest.addr & netif->netmask.addr, netif->ip_addr.addr & netif->netmask.addr, iphdr->dest.addr & ~(netif->netmask.addr))); /* interface is up and configured? */ if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) { /* unicast to this interface address? */ if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) || /* or broadcast on this interface network address? */ ip_addr_isbroadcast(&(iphdr->dest), netif)) { LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n", netif->name[0], netif->name[1])); /* break out of for loop */ break; } } if (first) { first = 0; netif = netif_list; } else { netif = netif->next; } if (netif == inp) { netif = netif->next; } } while(netif != NULL); } #if LWIP_DHCP /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed * using link layer addressing (such as Ethernet MAC) so we must not filter on IP. * According to RFC 1542 section 3.1.1, referred by RFC 2131). */ if (netif == NULL) { /* remote port is DHCP server? */ if (IPH_PROTO(iphdr) == IP_PROTO_UDP) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n", ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest))); if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n")); netif = inp; check_ip_src = 0; } } } #endif /* LWIP_DHCP */ /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */ #if LWIP_DHCP /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */ if (check_ip_src && (iphdr->src.addr != 0)) #endif /* LWIP_DHCP */ { if ((ip_addr_isbroadcast(&(iphdr->src), inp)) || (ip_addr_ismulticast(&(iphdr->src)))) { /* packet source is not valid */ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n")); /* free (drop) packet pbufs */ pbuf_free(p); IP_STATS_INC(ip.drop); snmp_inc_ipinaddrerrors(); snmp_inc_ipindiscards(); return ERR_OK; } } /* packet not for us? */ if (netif == NULL) { /* packet not for us, route or discard */ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n")); #if IP_FORWARD /* non-broadcast packet? */ if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) { /* try to forward IP packet on (other) interfaces */ ip_forward(p, iphdr, inp); } else #endif /* IP_FORWARD */ { snmp_inc_ipinaddrerrors(); snmp_inc_ipindiscards(); } pbuf_free(p); return ERR_OK; } /* packet consists of multiple fragments? */ if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) { #if IP_REASSEMBLY /* packet fragment reassembly code present? */ LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n", ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)); /* reassemble the packet*/ p = ip_reass(p); /* packet not fully reassembled yet? */ if (p == NULL) { return ERR_OK; } iphdr = p->payload; #else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */ pbuf_free(p); LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n", ntohs(IPH_OFFSET(iphdr)))); IP_STATS_INC(ip.opterr); IP_STATS_INC(ip.drop); /* unsupported protocol feature */ snmp_inc_ipinunknownprotos(); return ERR_OK; #endif /* IP_REASSEMBLY */ } #if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */ #if LWIP_IGMP /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */ if((iphdr_hlen > IP_HLEN && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) { #else if (iphdr_hlen > IP_HLEN) { #endif /* LWIP_IGMP */ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n")); pbuf_free(p); IP_STATS_INC(ip.opterr); IP_STATS_INC(ip.drop); /* unsupported protocol feature */ snmp_inc_ipinunknownprotos(); return ERR_OK; } #endif /* IP_OPTIONS_ALLOWED == 0 */ /* send to upper layers */ LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n")); ip_debug_print(p); LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); current_netif = inp; current_header = iphdr; #if LWIP_RAW /* raw input did not eat the packet? */ if (raw_input(p, inp) == 0) #endif /* LWIP_RAW */ { switch (IPH_PROTO(iphdr)) { #if LWIP_UDP case IP_PROTO_UDP: #if LWIP_UDPLITE case IP_PROTO_UDPLITE: #endif /* LWIP_UDPLITE */ snmp_inc_ipindelivers(); udp_input(p, inp); break; #endif /* LWIP_UDP */ #if LWIP_TCP case IP_PROTO_TCP: snmp_inc_ipindelivers(); tcp_input(p, inp); break; #endif /* LWIP_TCP */ #if LWIP_ICMP case IP_PROTO_ICMP: snmp_inc_ipindelivers(); icmp_input(p, inp); break; #endif /* LWIP_ICMP */ #if LWIP_IGMP case IP_PROTO_IGMP: igmp_input(p,inp,&(iphdr->dest)); break; #endif /* LWIP_IGMP */ default: #if LWIP_ICMP /* send ICMP destination protocol unreachable unless is was a broadcast */ if (!ip_addr_isbroadcast(&(iphdr->dest), inp) && !ip_addr_ismulticast(&(iphdr->dest))) { p->payload = iphdr; icmp_dest_unreach(p, ICMP_DUR_PROTO); } #endif /* LWIP_ICMP */ pbuf_free(p); LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr))); IP_STATS_INC(ip.proterr); IP_STATS_INC(ip.drop); snmp_inc_ipinunknownprotos(); } } current_netif = NULL; current_header = NULL; return ERR_OK; } /** * Sends an IP packet on a network interface. This function constructs * the IP header and calculates the IP header checksum. If the source * IP address is NULL, the IP address of the outgoing network * interface is filled in as source address. * If the destination IP address is IP_HDRINCL, p is assumed to already * include an IP header and p->payload points to it instead of the data. * * @param p the packet to send (p->payload points to the data, e.g. next protocol header; if dest == IP_HDRINCL, p already includes an IP header and p->payload points to that IP header) * @param src the source IP address to send from (if src == IP_ADDR_ANY, the * IP address of the netif used to send is used as source address) * @param dest the destination IP address to send the packet to * @param ttl the TTL value to be set in the IP header * @param tos the TOS value to be set in the IP header * @param proto the PROTOCOL to be set in the IP header * @param netif the netif on which to send this packet * @return ERR_OK if the packet was sent OK * ERR_BUF if p doesn't have enough space for IP/LINK headers * returns errors returned by netif->output * * @note ip_id: RFC791 "some host may be able to simply use * unique identifiers independent of destination" */ err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif) { #if IP_OPTIONS_SEND return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0); } /** * Same as ip_output_if() but with the possibility to include IP options: * * @ param ip_options pointer to the IP options, copied into the IP header * @ param optlen length of ip_options */ err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, u16_t optlen) { #endif /* IP_OPTIONS_SEND */ struct ip_hdr *iphdr; static u16_t ip_id = 0; snmp_inc_ipoutrequests(); /* Should the IP header be generated or is it already included in p? */ if (dest != IP_HDRINCL) { u16_t ip_hlen = IP_HLEN; #if IP_OPTIONS_SEND u16_t optlen_aligned = 0; if (optlen != 0) { /* round up to a multiple of 4 */ optlen_aligned = ((optlen + 3) & ~3); ip_hlen += optlen_aligned; /* First write in the IP options */ if (pbuf_header(p, optlen_aligned)) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n")); IP_STATS_INC(ip.err); snmp_inc_ipoutdiscards(); return ERR_BUF; } MEMCPY(p->payload, ip_options, optlen); if (optlen < optlen_aligned) { /* zero the remaining bytes */ memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen); } } #endif /* IP_OPTIONS_SEND */ /* generate IP header */ if (pbuf_header(p, IP_HLEN)) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n")); IP_STATS_INC(ip.err); snmp_inc_ipoutdiscards(); return ERR_BUF; } iphdr = p->payload; LWIP_ASSERT("check that first pbuf can hold struct ip_hdr", (p->len >= sizeof(struct ip_hdr))); IPH_TTL_SET(iphdr, ttl); IPH_PROTO_SET(iphdr, proto); ip_addr_set(&(iphdr->dest), dest); IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos); IPH_LEN_SET(iphdr, htons(p->tot_len)); IPH_OFFSET_SET(iphdr, 0); IPH_ID_SET(iphdr, htons(ip_id)); ++ip_id; if (ip_addr_isany(src)) { ip_addr_set(&(iphdr->src), &(netif->ip_addr)); } else { ip_addr_set(&(iphdr->src), src); } IPH_CHKSUM_SET(iphdr, 0); #if CHECKSUM_GEN_IP IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); #endif } else { /* IP header already included in p */ iphdr = p->payload; dest = &(iphdr->dest); } IP_STATS_INC(ip.xmit); LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num)); ip_debug_print(p); #if ENABLE_LOOPBACK if (ip_addr_cmp(dest, &netif->ip_addr)) { /* Packet to self, enqueue it for loopback */ LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()")); return netif_loop_output(netif, p, dest); } #endif /* ENABLE_LOOPBACK */ #if IP_FRAG /* don't fragment if interface has mtu set to 0 [loopif] */ if (netif->mtu && (p->tot_len > netif->mtu)) { return ip_frag(p,netif,dest); } #endif LWIP_DEBUGF(IP_DEBUG, ("netif->output()")); return netif->output(netif, p, dest); } /** * Simple interface to ip_output_if. It finds the outgoing network * interface and calls upon ip_output_if to do the actual work. * * @param p the packet to send (p->payload points to the data, e.g. next protocol header; if dest == IP_HDRINCL, p already includes an IP header and p->payload points to that IP header) * @param src the source IP address to send from (if src == IP_ADDR_ANY, the * IP address of the netif used to send is used as source address) * @param dest the destination IP address to send the packet to * @param ttl the TTL value to be set in the IP header * @param tos the TOS value to be set in the IP header * @param proto the PROTOCOL to be set in the IP header * * @return ERR_RTE if no route is found * see ip_output_if() for more return values */ err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t tos, u8_t proto) { struct netif *netif; if ((netif = ip_route(dest)) == NULL) { LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr)); IP_STATS_INC(ip.rterr); return ERR_RTE; } return ip_output_if(p, src, dest, ttl, tos, proto, netif); } #if LWIP_NETIF_HWADDRHINT /** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint * before calling ip_output_if. * * @param p the packet to send (p->payload points to the data, e.g. next protocol header; if dest == IP_HDRINCL, p already includes an IP header and p->payload points to that IP header) * @param src the source IP address to send from (if src == IP_ADDR_ANY, the * IP address of the netif used to send is used as source address) * @param dest the destination IP address to send the packet to * @param ttl the TTL value to be set in the IP header * @param tos the TOS value to be set in the IP header * @param proto the PROTOCOL to be set in the IP header * @param addr_hint address hint pointer set to netif->addr_hint before * calling ip_output_if() * * @return ERR_RTE if no route is found * see ip_output_if() for more return values */ err_t ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint) { struct netif *netif; err_t err; if ((netif = ip_route(dest)) == NULL) { LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr)); IP_STATS_INC(ip.rterr); return ERR_RTE; } netif->addr_hint = addr_hint; err = ip_output_if(p, src, dest, ttl, tos, proto, netif); netif->addr_hint = NULL; return err; } #endif /* LWIP_NETIF_HWADDRHINT*/ #if IP_DEBUG /* Print an IP header by using LWIP_DEBUGF * @param p an IP packet, p->payload pointing to the IP header */ void ip_debug_print(struct pbuf *p) { struct ip_hdr *iphdr = p->payload; u8_t *payload; payload = (u8_t *)iphdr + IP_HLEN; LWIP_DEBUGF(IP_DEBUG, ("IP header:\n")); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" | 0x%02"X16_F" | %5"U16_F" | (v, hl, tos, len)\n", IPH_V(iphdr), IPH_HL(iphdr), IPH_TOS(iphdr), ntohs(IPH_LEN(iphdr)))); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n", ntohs(IPH_ID(iphdr)), ntohs(IPH_OFFSET(iphdr)) >> 15 & 1, ntohs(IPH_OFFSET(iphdr)) >> 14 & 1, ntohs(IPH_OFFSET(iphdr)) >> 13 & 1, ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\n", IPH_TTL(iphdr), IPH_PROTO(iphdr), ntohs(IPH_CHKSUM(iphdr)))); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n", ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src), ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src))); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n", ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest), ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest))); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); }
/** * Called from ip_input() if a new IGMP packet is received. * * @param p received igmp packet, p->payload pointing to the ip header * @param inp network interface on which the packet was received * @param dest destination ip address of the igmp packet */ void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest) { struct ip_hdr * iphdr; struct igmp_msg* igmp; struct igmp_group* group; struct igmp_group* groupref; IGMP_STATS_INC(igmp.recv); /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */ iphdr = (struct ip_hdr *)p->payload; if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) { pbuf_free(p); IGMP_STATS_INC(igmp.lenerr); LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n")); return; } LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from ")); ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src)); LWIP_DEBUGF(IGMP_DEBUG, (" to address ")); ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest)); LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp)); /* Now calculate and check the checksum */ igmp = (struct igmp_msg *)p->payload; if (inet_chksum(igmp, p->len)) { pbuf_free(p); IGMP_STATS_INC(igmp.chkerr); LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n")); return; } /* Packet is ok so find an existing group */ group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */ /* If group can be found or create... */ if (!group) { pbuf_free(p); IGMP_STATS_INC(igmp.drop); LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n")); return; } /* NOW ACT ON THE INCOMING MESSAGE TYPE... */ switch (igmp->igmp_msgtype) { case IGMP_MEMB_QUERY: { /* IGMP_MEMB_QUERY to the "all systems" address ? */ if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) { /* THIS IS THE GENERAL QUERY */ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); if (igmp->igmp_maxresp == 0) { IGMP_STATS_INC(igmp.rx_v1); LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n")); igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR; } else { IGMP_STATS_INC(igmp.rx_general); } groupref = igmp_group_list; while (groupref) { /* Do not send messages on the all systems group address! */ if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) { igmp_delaying_member(groupref, igmp->igmp_maxresp); } groupref = groupref->next; } } else { /* IGMP_MEMB_QUERY to a specific group ? */ if (!ip_addr_isany(&igmp->igmp_group_address)) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group ")); ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address); if (ip_addr_cmp(dest, &allsystems)) { ip_addr_t groupaddr; LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); /* we first need to re-look for the group since we used dest last time */ ip_addr_copy(groupaddr, igmp->igmp_group_address); group = igmp_lookfor_group(inp, &groupaddr); } else { LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); } if (group != NULL) { IGMP_STATS_INC(igmp.rx_group); igmp_delaying_member(group, igmp->igmp_maxresp); } else { IGMP_STATS_INC(igmp.drop); } } else { IGMP_STATS_INC(igmp.proterr); } } break; } case IGMP_V2_MEMB_REPORT: { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n")); IGMP_STATS_INC(igmp.rx_report); if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { /* This is on a specific group we have already looked up */ group->timer = 0; /* stopped */ group->group_state = IGMP_GROUP_IDLE_MEMBER; group->last_reporter_flag = 0; } break; } default: { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n", igmp->igmp_msgtype, group->group_state, &group, group->netif)); IGMP_STATS_INC(igmp.proterr); break; } } pbuf_free(p); return; }
/** * Processes ICMP input packets, called from ip_input(). * * Currently only processes icmp echo requests and sends * out the echo response. * * @param p the icmp echo request packet, p->payload pointing to the ip header * @param inp the netif on which this packet was received */ void icmp_input(struct pbuf *p, struct netif *inp) { u8_t type; #ifdef LWIP_DEBUG u8_t code; #endif /* LWIP_DEBUG */ struct icmp_echo_hdr *iecho; struct ip_hdr *iphdr; struct ip_addr tmpaddr; s16_t hlen; u8_t iptxt[20]; volatile u8_t iptab[4]; u32_t IPaddress; ICMP_STATS_INC(icmp.recv); snmp_inc_icmpinmsgs(); iphdr = p->payload; hlen = IPH_HL(iphdr) * 4; if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len)); goto lenerr; } IPaddress = iphdr->src.addr; /* read its IP address */ iptab[0] = (u8_t)(IPaddress >> 24); iptab[1] = (u8_t)(IPaddress >> 16); iptab[2] = (u8_t)(IPaddress >> 8); iptab[3] = (u8_t)(IPaddress); sprintf((char*)iptxt, "Ping: %d.%d.%d.%d ", iptab[3], iptab[2], iptab[1], iptab[0]); LCD_DisplayStringLine(Line4, iptxt); printf("\n\r%s", iptxt); type = *((u8_t *)p->payload); #ifdef LWIP_DEBUG code = *(((u8_t *)p->payload)+1); #endif /* LWIP_DEBUG */ switch (type) { case ICMP_ECHO: #if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING { int accepted = 1; #if !LWIP_MULTICAST_PING /* multicast destination address? */ if (ip_addr_ismulticast(&iphdr->dest)) { accepted = 0; } #endif /* LWIP_MULTICAST_PING */ #if !LWIP_BROADCAST_PING /* broadcast destination address? */ if (ip_addr_isbroadcast(&iphdr->dest, inp)) { accepted = 0; } #endif /* LWIP_BROADCAST_PING */ /* broadcast or multicast destination address not acceptd? */ if (!accepted) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n")); ICMP_STATS_INC(icmp.err); pbuf_free(p); return; } } #endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */ LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); if (p->tot_len < sizeof(struct icmp_echo_hdr)) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); goto lenerr; } if (inet_chksum_pbuf(p) != 0) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); pbuf_free(p); ICMP_STATS_INC(icmp.chkerr); snmp_inc_icmpinerrors(); return; } #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) { /* p is not big enough to contain link headers * allocate a new one and copy p into it */ struct pbuf *r; /* switch p->payload to ip header */ if (pbuf_header(p, hlen)) { LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0); goto memerr; } /* allocate new packet buffer with space for link headers */ r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); if (r == NULL) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n")); goto memerr; } LWIP_ASSERT("check that first pbuf can hold struct the ICMP header", (r->len >= hlen + sizeof(struct icmp_echo_hdr))); /* copy the whole packet including ip header */ if (pbuf_copy(r, p) != ERR_OK) { LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0); goto memerr; } iphdr = r->payload; /* switch r->payload back to icmp header */ if (pbuf_header(r, -hlen)) { LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); goto memerr; } /* free the original p */ pbuf_free(p); /* we now have an identical copy of p that has room for link headers */ p = r; } else { /* restore p->payload to point to icmp header */ if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) { LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); goto memerr; } } #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ /* At this point, all checks are OK. */ /* We generate an answer by switching the dest and src ip addresses, * setting the icmp type to ECHO_RESPONSE and updating the checksum. */ iecho = p->payload; tmpaddr.addr = iphdr->src.addr; iphdr->src.addr = iphdr->dest.addr; iphdr->dest.addr = tmpaddr.addr; ICMPH_TYPE_SET(iecho, ICMP_ER); /* This part of code has been modified by ST's MCD Application Team */ /* To use the Checksum Offload Engine for the putgoing ICMP packets, the ICMP checksum field should be set to 0, this is required only for Tx ICMP*/ #ifdef CHECKSUM_BY_HARDWARE iecho->chksum = 0; #else /* adjust the checksum */ if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) { iecho->chksum += htons(ICMP_ECHO << 8) + 1; } else { iecho->chksum += htons(ICMP_ECHO << 8); } #endif /* Set the correct TTL and recalculate the header checksum. */ IPH_TTL_SET(iphdr, ICMP_TTL); IPH_CHKSUM_SET(iphdr, 0); #if CHECKSUM_GEN_IP IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); #endif /* CHECKSUM_GEN_IP */ ICMP_STATS_INC(icmp.xmit); /* increase number of messages attempted to send */ snmp_inc_icmpoutmsgs(); /* increase number of echo replies attempted to send */ snmp_inc_icmpoutechoreps(); if(pbuf_header(p, hlen)) { LWIP_ASSERT("Can't move over header in packet", 0); } else { err_t ret; ret = ip_output_if(p, &(iphdr->src), IP_HDRINCL, ICMP_TTL, 0, IP_PROTO_ICMP, inp); if (ret != ERR_OK) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret)); } } break; default: LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n", (s16_t)type, (s16_t)code)); ICMP_STATS_INC(icmp.proterr); ICMP_STATS_INC(icmp.drop); } pbuf_free(p); return; lenerr: pbuf_free(p); ICMP_STATS_INC(icmp.lenerr); snmp_inc_icmpinerrors(); return; #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN memerr: pbuf_free(p); ICMP_STATS_INC(icmp.err); snmp_inc_icmpinerrors(); return; #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ }
/** * Reassembles incoming IP fragments into an IP datagram. * * @param p points to a pbuf chain of the fragment * @return NULL if reassembly is incomplete, ? otherwise */ struct pbuf * ip_reass(struct pbuf *p) { struct pbuf *q; struct ip_hdr *fraghdr, *iphdr; u16_t offset, len; u16_t i; IPFRAG_STATS_INC(ip_frag.recv); iphdr = (struct ip_hdr *) ip_reassbuf; fraghdr = (struct ip_hdr *) p->payload; /* 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. */ if (ip_reasstmr == 0) { LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: new packet\n")); memcpy(iphdr, fraghdr, IP_HLEN); ip_reasstmr = IP_REASS_MAXAGE; ip_reassflags = 0; /* Clear the bitmap. */ memset(ip_reassbitmap, 0, sizeof(ip_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->dest, &fraghdr->dest) && IPH_ID(iphdr) == IPH_ID(fraghdr)) { LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n", ntohs(IPH_ID(fraghdr)))); IPFRAG_STATS_INC(ip_frag.cachehit); /* Find out the offset in the reassembly buffer where we should copy the fragment. */ len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; /* If the offset or the offset + fragment length overflows the reassembly buffer, we discard the entire packet. */ if (offset > IP_REASS_BUFSIZE || offset + len > IP_REASS_BUFSIZE) { LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: fragment outside of buffer (%"S16_F":%"S16_F"/%"S16_F").\n", offset, offset + len, IP_REASS_BUFSIZE)); ip_reasstmr = 0; goto nullreturn; } /* Copy the fragment into the reassembly buffer, at the right offset. */ LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: copying with offset %"S16_F" into %"S16_F":%"S16_F"\n", offset, IP_HLEN + offset, IP_HLEN + offset + len)); i = IPH_HL(fraghdr) * 4; copy_from_pbuf(p, &i, &ip_reassbuf[IP_HLEN + offset], len); /* Update the bitmap. */ if (offset / (8 * 8) == (offset + len) / (8 * 8)) { LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: updating single byte in bitmap.\n")); /* If the two endpoints are in the same byte, we only update that byte. */ LWIP_ASSERT("offset / (8 * 8) < sizeof(ip_reassbitmap)", offset / (8 * 8) < sizeof(ip_reassbitmap)); ip_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. */ LWIP_ASSERT("offset / (8 * 8) < sizeof(ip_reassbitmap)", offset / (8 * 8) < sizeof(ip_reassbitmap)); ip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8) & 7]; LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: updating many bytes in bitmap (%"S16_F":%"S16_F").\n", 1 + offset / (8 * 8), (offset + len) / (8 * 8))); for (i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) { ip_reassbitmap[i] = 0xff; } LWIP_ASSERT("(offset + len) / (8 * 8) < sizeof(ip_reassbitmap)", (offset + len) / (8 * 8) < sizeof(ip_reassbitmap)); ip_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(IPH_OFFSET(fraghdr)) & IP_MF) == 0) { ip_reassflags |= IP_REASS_FLAG_LASTFRAG; ip_reasslen = offset + len; LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: last fragment seen, total len %"S16_F"\n", ip_reasslen)); } /* 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 (ip_reassflags & IP_REASS_FLAG_LASTFRAG) { /* Check all bytes up to and including all but the last byte in the bitmap. */ LWIP_ASSERT("ip_reasslen / (8 * 8) - 1 < sizeof(ip_reassbitmap)", ip_reasslen / (8 * 8) - 1 < sizeof(ip_reassbitmap)); for (i = 0; i < ip_reasslen / (8 * 8) - 1; ++i) { if (ip_reassbitmap[i] != 0xff) { LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: last fragment seen, bitmap %"S16_F"/%"S16_F" failed (%"X16_F")\n", i, ip_reasslen / (8 * 8) - 1, ip_reassbitmap[i])); goto nullreturn; } } /* Check the last byte in the bitmap. It should contain just the right amount of bits. */ LWIP_ASSERT("ip_reasslen / (8 * 8) < sizeof(ip_reassbitmap)", ip_reasslen / (8 * 8) < sizeof(ip_reassbitmap)); if (ip_reassbitmap[ip_reasslen / (8 * 8)] != (u8_t) ~ bitmap_bits[ip_reasslen / 8 & 7]) { LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: last fragment seen, bitmap %"S16_F" didn't contain %"X16_F" (%"X16_F")\n", ip_reasslen / (8 * 8), ~bitmap_bits[ip_reasslen / 8 & 7], ip_reassbitmap[ip_reasslen / (8 * 8)])); goto nullreturn; } /* Pretend to be a "normal" (i.e., not fragmented) IP packet from now on. */ ip_reasslen += IP_HLEN; IPH_LEN_SET(iphdr, htons(ip_reasslen)); IPH_OFFSET_SET(iphdr, 0); IPH_CHKSUM_SET(iphdr, 0); IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, 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. */ ip_reasstmr = 0; pbuf_free(p); p = pbuf_alloc(PBUF_LINK, ip_reasslen, PBUF_POOL); if (p != NULL) { i = 0; for (q = p; q != NULL; q = q->next) { /* Copy enough bytes to fill this pbuf in the chain. The available data in the pbuf is given by the q->len variable. */ LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: memcpy from %p (%"S16_F") to %p, %"S16_F" bytes\n", (void *)&ip_reassbuf[i], i, q->payload, q->len > ip_reasslen - i ? ip_reasslen - i : q->len)); memcpy(q->payload, &ip_reassbuf[i], q->len > ip_reasslen - i ? ip_reasslen - i : q->len); i += q->len; } IPFRAG_STATS_INC(ip_frag.fw); } else { IPFRAG_STATS_INC(ip_frag.memerr); } LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: p %p\n", (void*)p)); return p; } } nullreturn: IPFRAG_STATS_INC(ip_frag.drop); pbuf_free(p); return NULL; }
err_t ip_input(struct pbuf *p, struct netif *inp) { struct ip_hdr *iphdr; struct netif *netif; u16_t iphdrlen; IP_STATS_INC(ip.recv); snmp_inc_ipinreceives(); /* identify the IP header */ iphdr = p->payload; if (IPH_V(iphdr) != 4) { LWIP_DEBUGF(IP_DEBUG | 1, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr))); ip_debug_print(p); pbuf_free(p); IP_STATS_INC(ip.err); IP_STATS_INC(ip.drop); snmp_inc_ipinhdrerrors(); return ERR_OK; } /* obtain IP header length in number of 32-bit words */ iphdrlen = IPH_HL(iphdr); /* calculate IP header length in bytes */ iphdrlen *= 4; /* header length exceeds first pbuf length? */ if (iphdrlen > p->len) { LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet droppped.\n", iphdrlen, p->len)); /* free (drop) packet pbufs */ pbuf_free(p); IP_STATS_INC(ip.lenerr); IP_STATS_INC(ip.drop); snmp_inc_ipindiscards(); return ERR_OK; } /* verify checksum */ #if CHECKSUM_CHECK_IP if (inet_chksum(iphdr, iphdrlen) != 0) { LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdrlen))); ip_debug_print(p); pbuf_free(p); IP_STATS_INC(ip.chkerr); IP_STATS_INC(ip.drop); snmp_inc_ipinhdrerrors(); return ERR_OK; } #endif /* Trim pbuf. This should have been done at the netif layer, * but we'll do it anyway just to be sure that its done. */ pbuf_realloc(p, ntohs(IPH_LEN(iphdr))); /* match packet against an interface, i.e. is this packet for us? */ for (netif = netif_list; netif != NULL; netif = netif->next) { LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n", iphdr->dest.addr, netif->ip_addr.addr, iphdr->dest.addr & netif->netmask.addr, netif->ip_addr.addr & netif->netmask.addr, iphdr->dest.addr & ~(netif->netmask.addr))); /* interface is up and configured? */ if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) { /* unicast to this interface address? */ if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) || /* or broadcast on this interface network address? */ ip_addr_isbroadcast(&(iphdr->dest), netif)) { LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n", netif->name[0], netif->name[1])); /* break out of for loop */ break; } } } #if LWIP_DHCP /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed * using link layer addressing (such as Ethernet MAC) so we must not filter on IP. * According to RFC 1542 section 3.1.1, referred by RFC 2131). */ if (netif == NULL) { /* remote port is DHCP server? */ if (IPH_PROTO(iphdr) == IP_PROTO_UDP) { LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %"U16_F"\n", ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdrlen))->dest))); if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdrlen))->dest) == DHCP_CLIENT_PORT) { LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n")); netif = inp; } } } #endif /* LWIP_DHCP */ /* packet not for us? */ if (netif == NULL) { /* packet not for us, route or discard */ LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: packet not for us.\n")); #if IP_FORWARD /* non-broadcast packet? */ if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) { /* try to forward IP packet on (other) interfaces */ ip_forward(p, iphdr, inp); } else #endif /* IP_FORWARD */ { snmp_inc_ipinaddrerrors(); snmp_inc_ipindiscards(); } pbuf_free(p); return ERR_OK; } /* packet consists of multiple fragments? */ if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) { #if IP_REASSEMBLY /* packet fragment reassembly code present? */ LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n", ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)); /* reassemble the packet*/ p = ip_reass(p); /* packet not fully reassembled yet? */ if (p == NULL) { return ERR_OK; } iphdr = p->payload; #else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */ pbuf_free(p); LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n", ntohs(IPH_OFFSET(iphdr)))); IP_STATS_INC(ip.opterr); IP_STATS_INC(ip.drop); /* unsupported protocol feature */ snmp_inc_ipinunknownprotos(); return ERR_OK; #endif /* IP_REASSEMBLY */ } #if IP_OPTIONS == 0 /* no support for IP options in the IP header? */ if (iphdrlen > IP_HLEN) { LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS == 0).\n")); pbuf_free(p); IP_STATS_INC(ip.opterr); IP_STATS_INC(ip.drop); /* unsupported protocol feature */ snmp_inc_ipinunknownprotos(); return ERR_OK; } #endif /* IP_OPTIONS == 0 */ /* send to upper layers */ LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n")); ip_debug_print(p); LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); #if LWIP_RAW /* raw input did not eat the packet? */ if (raw_input(p, inp) == 0) { #endif /* LWIP_RAW */ switch (IPH_PROTO(iphdr)) { #if LWIP_UDP case IP_PROTO_UDP: case IP_PROTO_UDPLITE: snmp_inc_ipindelivers(); udp_input(p, inp); break; #endif /* LWIP_UDP */ #if LWIP_TCP case IP_PROTO_TCP: snmp_inc_ipindelivers(); tcp_input(p, inp); break; #endif /* LWIP_TCP */ case IP_PROTO_ICMP: snmp_inc_ipindelivers(); icmp_input(p, inp); break; default: /* send ICMP destination protocol unreachable unless is was a broadcast */ if (!ip_addr_isbroadcast(&(iphdr->dest), inp) && !ip_addr_ismulticast(&(iphdr->dest))) { p->payload = iphdr; icmp_dest_unreach(p, ICMP_DUR_PROTO); } pbuf_free(p); LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr))); IP_STATS_INC(ip.proterr); IP_STATS_INC(ip.drop); snmp_inc_ipinunknownprotos(); } #if LWIP_RAW } /* LWIP_RAW */ #endif return ERR_OK; }
/** * Processes ICMP input packets, called from ip_input(). * * Currently only processes icmp echo requests and sends * out the echo response. * * @param p the icmp echo request packet, p->payload pointing to the ip header * @param inp the netif on which this packet was received */ void icmp_input(PBUF *p, NETIF *inp) { uint8 type; ICMP_ECHO_HDR *iecho; IP_HDR *iphdr; IP_ADDR tmpaddr; int16 hlen; iphdr = p->payload; hlen = IPH_HL(iphdr) * 4; if (pbuf_header(p, -hlen) == 0) return; type = *((uint8 *)p->payload); iecho = p->payload; printf("icmp_input %d %d\n", iecho->type, iecho->code); switch (type) { case ICMP_ECHO: { int accepted = 1; /* multicast destination address? */ if (ip_addr_ismulticast(&iphdr->dest)) { accepted = 0; } /* broadcast destination address? */ if (ip_addr_isbroadcast(&iphdr->dest, inp)) { accepted = 0; } /* broadcast or multicast destination address not acceptd? */ if (!accepted) { pbuf_free(p); return; } if (p->len < sizeof(ICMP_ECHO_HDR)) goto lenerr; if (inet_chksum_pbuf(p) != 0) { pbuf_free(p); return; } /* At this point, all checks are OK. */ /* We generate an answer by switching the dest and src ip addresses, * setting the icmp type to ECHO_RESPONSE and updating the checksum. */ tmpaddr.addr = iphdr->src.addr; iphdr->src.addr = iphdr->dest.addr; iphdr->dest.addr = tmpaddr.addr; iecho = p->payload; ICMPH_TYPE_SET(iecho, ICMP_ER); /* adjust the checksum */ if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) { iecho->chksum += htons(ICMP_ECHO << 8) + 1; } else { iecho->chksum += htons(ICMP_ECHO << 8); } if (pbuf_header(p, hlen) == 0) return; ip_output_if(p, &(iphdr->src), IP_HDRINCL, ICMP_TTL, 0, IP_PROTO_ICMP, inp); break; } default: break; } lenerr: pbuf_free(p); return; }
err_t udp_input(struct pbuf *p, struct netif *inp) { struct udp_hdr *udphdr; struct udp_pcb *pcb; struct ip_hdr *iphdr; unsigned short src, dest; stats.udp.recv++; iphdr = p->payload; if (pbuf_header(p, -(IPH_HL(iphdr) * 4)) < 0 || p->tot_len < sizeof(struct udp_hdr)) { kprintf(KERN_WARNING "udp_input: short packet (%u bytes) discarded\n", p->tot_len); stats.udp.lenerr++; stats.udp.drop++; return -EPROTO; } udphdr = p->payload; //udp_debug_print(udphdr); #ifdef CHECK_UDP_CHECKSUM // Check checksum if ((inp->flags & NETIF_UDP_RX_CHECKSUM_OFFLOAD) == 0) { if (udphdr->chksum != 0) { if (inet_chksum_pseudo(p, &iphdr->src, &iphdr->dest, IP_PROTO_UDP, p->tot_len) != 0) { kprintf(KERN_WARNING "udp_input: UDP datagram discarded due to failing checksum\n"); stats.udp.chkerr++; stats.udp.drop++; return -ECHKSUM; } } } #endif src = NTOHS(udphdr->src); dest = NTOHS(udphdr->dest); // Demultiplex packet. First, go for a perfect match for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { if (pcb->remote_port == src && pcb->local_port == dest && (ip_addr_isany(&pcb->remote_ip) || ip_addr_cmp(&pcb->remote_ip, &iphdr->src)) && (ip_addr_isany(&pcb->local_ip) || ip_addr_cmp(&pcb->local_ip, &iphdr->dest))) { break; } } if (pcb == NULL) { // No fully matching pcb found, look for an unconnected pcb for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { if (!(pcb->flags & UDP_FLAGS_CONNECTED) && pcb->local_port == dest && (ip_addr_isany(&pcb->remote_ip) || ip_addr_cmp(&pcb->remote_ip, &iphdr->src)) && (ip_addr_isany(&pcb->local_ip) || ip_addr_cmp(&pcb->local_ip, &iphdr->dest))) { break; } } } if (pcb == NULL) { // No match was found, send ICMP destination port unreachable unless // destination address was broadcast/multicast. if (!ip_addr_isbroadcast(&iphdr->dest, &inp->netmask) && !ip_addr_ismulticast(&iphdr->dest)) { // Adjust pbuf pointer p->payload = iphdr; icmp_dest_unreach(p, ICMP_DUR_PORT); } ++stats.udp.proterr; ++stats.udp.drop; return -EHOSTUNREACH; } pbuf_header(p, -UDP_HLEN); return pcb->recv(pcb->recv_arg, pcb, p, &iphdr->src, src); }
/** * Processes ICMP input packets, called from ip_input(). * * Currently only processes icmp echo requests and sends * out the echo response. * * @param p the icmp echo request packet, p->payload pointing to the icmp header * @param inp the netif on which this packet was received */ void icmp_input(struct pbuf *p, struct netif *inp) { u8_t type; #ifdef LWIP_DEBUG u8_t code; #endif /* LWIP_DEBUG */ struct icmp_echo_hdr *iecho; struct ip_hdr *iphdr; s16_t hlen; ICMP_STATS_INC(icmp.recv); snmp_inc_icmpinmsgs(); iphdr = (struct ip_hdr *)ip_current_header(); hlen = IPH_HL(iphdr) * 4; if (p->len < sizeof(u16_t)*2) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len)); goto lenerr; } type = *((u8_t *)p->payload); #ifdef LWIP_DEBUG code = *(((u8_t *)p->payload)+1); #endif /* LWIP_DEBUG */ switch (type) { case ICMP_ER: /* This is OK, echo reply might have been parsed by a raw PCB (as obviously, an echo request has been sent, too). */ break; case ICMP_ECHO: #if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING { int accepted = 1; #if !LWIP_MULTICAST_PING /* multicast destination address? */ if (ip_addr_ismulticast(ip_current_dest_addr())) { accepted = 0; } #endif /* LWIP_MULTICAST_PING */ #if !LWIP_BROADCAST_PING /* broadcast destination address? */ if (ip_addr_isbroadcast(ip_current_dest_addr(), inp)) { accepted = 0; } #endif /* LWIP_BROADCAST_PING */ /* broadcast or multicast destination address not acceptd? */ if (!accepted) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n")); ICMP_STATS_INC(icmp.err); pbuf_free(p); return; } } #endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */ LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); if (p->tot_len < sizeof(struct icmp_echo_hdr)) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); goto lenerr; } #if CHECKSUM_CHECK_ICMP if (inet_chksum_pbuf(p) != 0) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); pbuf_free(p); ICMP_STATS_INC(icmp.chkerr); snmp_inc_icmpinerrors(); return; } #endif #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) { /* p is not big enough to contain link headers * allocate a new one and copy p into it */ struct pbuf *r; /* switch p->payload to ip header */ if (pbuf_header(p, hlen)) { LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0); goto memerr; } /* allocate new packet buffer with space for link headers */ r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); if (r == NULL) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n")); goto memerr; } LWIP_ASSERT("check that first pbuf can hold struct the ICMP header", (r->len >= hlen + sizeof(struct icmp_echo_hdr))); /* copy the whole packet including ip header */ if (pbuf_copy(r, p) != ERR_OK) { LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0); goto memerr; } iphdr = (struct ip_hdr *)r->payload; /* switch r->payload back to icmp header */ if (pbuf_header(r, -hlen)) { LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); goto memerr; } /* free the original p */ pbuf_free(p); /* we now have an identical copy of p that has room for link headers */ p = r; } else { /* restore p->payload to point to icmp header */ if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) { LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); goto memerr; } } #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ /* At this point, all checks are OK. */ /* We generate an answer by switching the dest and src ip addresses, * setting the icmp type to ECHO_RESPONSE and updating the checksum. */ iecho = (struct icmp_echo_hdr *)p->payload; ip_addr_copy(iphdr->src, *ip_current_dest_addr()); ip_addr_copy(iphdr->dest, *ip_current_src_addr()); ICMPH_TYPE_SET(iecho, ICMP_ER); #if CHECKSUM_GEN_ICMP /* adjust the checksum */ if (iecho->chksum > PP_HTONS(0xffffU - (ICMP_ECHO << 8))) { iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1; } else { iecho->chksum += PP_HTONS(ICMP_ECHO << 8); } #else /* CHECKSUM_GEN_ICMP */ iecho->chksum = 0; #endif /* CHECKSUM_GEN_ICMP */ /* Set the correct TTL and recalculate the header checksum. */ IPH_TTL_SET(iphdr, ICMP_TTL); IPH_CHKSUM_SET(iphdr, 0); #if CHECKSUM_GEN_IP IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); #endif /* CHECKSUM_GEN_IP */ ICMP_STATS_INC(icmp.xmit); /* increase number of messages attempted to send */ snmp_inc_icmpoutmsgs(); /* increase number of echo replies attempted to send */ snmp_inc_icmpoutechoreps(); if(pbuf_header(p, hlen)) { LWIP_ASSERT("Can't move over header in packet", 0); } else { err_t ret; /* send an ICMP packet, src addr is the dest addr of the curren packet */ ret = ip_output_if(p, ip_current_dest_addr(), IP_HDRINCL, ICMP_TTL, 0, IP_PROTO_ICMP, inp); if (ret != ERR_OK) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret)); } } break; default: LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n", (s16_t)type, (s16_t)code)); ICMP_STATS_INC(icmp.proterr); ICMP_STATS_INC(icmp.drop); } pbuf_free(p); return; lenerr: pbuf_free(p); ICMP_STATS_INC(icmp.lenerr); snmp_inc_icmpinerrors(); return; #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN memerr: pbuf_free(p); ICMP_STATS_INC(icmp.err); snmp_inc_icmpinerrors(); return; #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ }
/** * This function is called by the network interface device driver when * an IP packet is received. The function does the basic checks of the * IP header such as packet size being at least larger than the header * size etc. If the packet was not destined for us, the packet is * forwarded (using ip_forward). The IP checksum is always checked. * * Finally, the packet is sent to the upper layer protocol input function. * * @param p the received IP packet (p->payload points to IP header) * @param inp the netif on which this packet was received * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't * processed, but currently always returns ERR_OK) */ uint8 ip_input(PBUF *p, NETIF *inp) { IP_HDR *iphdr; NETIF *netif; uint16 iphdr_hlen; uint16 iphdr_len; /* identify the IP header */ iphdr = p->payload; if (IPH_V(iphdr) != 4) { pbuf_free(p);//this packet is not ipv4 return ERR_OK; } /* obtain IP header length in number of 32-bit words */ iphdr_hlen = IPH_HL(iphdr); /* calculate IP header length in bytes */ iphdr_hlen *= 4; /* obtain ip pocket total length in bytes */ iphdr_len = ntohs(IPH_LEN(iphdr)); /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */ if ((iphdr_hlen > p->len) || (iphdr_len > p->len)) { /* free (drop) packet pbufs */ pbuf_free(p); return ERR_OK; } if (inet_chksum(iphdr, iphdr_hlen) != 0) { pbuf_free(p);//ip header checksum error! return ERR_OK; } netif = inp; /* interface is up and configured? */ if (ip_addr_isany(&(netif->ip_addr))) { netif = NULL; } else { /* unicast to this interface address? */ if (!ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr))) { netif = NULL; } } /* packet consists of multiple fragments? */ if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) { printf("received splited IP packet!! \n"); pbuf_free(p); return ERR_OK; } if (iphdr_hlen > IP_HLEN) { pbuf_free(p); return ERR_OK; } switch (IPH_PROTO(iphdr)) { case IP_PROTO_TCP://(6) //printf("get a tcp packet\n"); tcp_input(p, inp); break; case IP_PROTO_UDP://(17) printf("UDP\n"); udp_input(p, inp); break; case IP_PROTO_ICMP://(1) printf("gICMP\n"); icmp_input(p, inp); break; default: /* send ICMP destination protocol unreachable unless is was a broadcast */ printf("gerr\n"); if (!ip_addr_isbroadcast(&(iphdr->dest), inp) && !ip_addr_ismulticast(&(iphdr->dest))) { p->payload = iphdr; icmp_dest_unreach(p, ICMP_DUR_PROTO); } pbuf_free(p); } return ERR_OK; }
/** * This function does the actual transmission of a packet. The packet is * contained in the pbuf that is passed to the function. This pbuf * can be chained. * * @param netif * the lwip network interface structure for this netfrontif * @param p * the packet to send (e.g. IP packet including MAC addresses and type) * @return * ERR_OK when the packet could be enqueued for sending; an err_t value otherwise */ static inline err_t netfrontif_transmit(struct netif *netif, struct pbuf *p) { struct netfrontif *nfi = netif->state; #if LWIP_CHECKSUM_PARTIAL || defined CONFIG_LWIP_BATCHTX s16_t ip_hdr_offset; const struct eth_hdr *ethhdr; const struct ip_hdr *iphdr; #endif /* LWIP_CHECKSUM_PARTIAL || defined CONFIG_LWIP_BATCHTX */ #ifdef CONFIG_LWIP_BATCHTX const struct tcp_hdr *tcphdr; #endif /* CONFIG_LWIP_BATCHTX */ int tso = 0; int push = 1; err_t err; LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_transmit: %c%c: " "Transmitting %u bytes\n", netif->name[0], netif->name[1], p->tot_len)); #if LWIP_CHECKSUM_PARTIAL || defined CONFIG_LWIP_BATCHTX /* detect if payload contains a TCP packet */ /* NOTE: We assume here that all protocol headers are in the first pbuf of a pbuf chain! */ ip_hdr_offset = SIZEOF_ETH_HDR; ethhdr = (struct eth_hdr *) p->payload; #if ETHARP_SUPPORT_VLAN if (type == PP_HTONS(ETHTYPE_VLAN)) { type = ((struct eth_vlan_hdr*)(((uintptr_t)ethhdr) + SIZEOF_ETH_HDR))->tpid; ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR; } #endif /* ETHARP_SUPPORT_VLAN */ /* TODO: PPP support? */ switch (ethhdr->type) { case PP_HTONS(ETHTYPE_IP): iphdr = (struct ip_hdr *)((uintptr_t) p->payload + ip_hdr_offset); if (IPH_PROTO(iphdr) != IP_PROTO_TCP) { goto xmit; /* IPv4 but not TCP */ } #if LWIP_CHECKSUM_PARTIAL tso = XEN_NETIF_GSO_TYPE_TCPV4; /* TCPv4 segmentation and checksum offloading */ #endif /* LWIP_CHECKSUM_PARTIAL */ #ifdef CONFIG_LWIP_BATCHTX /* push only when FIN, RST, PSH, or URG flag is set */ tcphdr = (struct tcp_hdr *)((uintptr_t) p->payload + ip_hdr_offset + (IPH_HL(iphdr) * 4)); push = (TCPH_FLAGS(tcphdr) & (TCP_FIN | TCP_RST | TCP_PSH | TCP_URG)); #endif /* CONFIG_LWIP_BATCHTX */ break; #if IPV6_SUPPORT case PP_HTONS(ETHTYPE_IPV6): if (IP6H_NEXTH((struct ip6_hdr *)((uintptr_t) p->payload + ip_hdr_offset)) != IP6_NEXTH_TCP) goto xmit; /* IPv6 but not TCP */ #if LWIP_CHECKSUM_PARTIAL tso = XEN_NETIF_GSO_TYPE_TCPV6; /* TCPv6 segmentation and checksum offloading */ #endif /* LWIP_CHECKSUM_PARTIAL */ #ifdef CONFIG_LWIP_BATCHTX /* push only when FIN, RST, PSH, or URG flag is set */ #error "TSOv6 is not yet supported. Please add it" tcphdr = NULL; push = (TCPH_FLAGS(tcphdr) & (TCP_FIN | TCP_RST | TCP_PSH | TCP_URG)); #endif /* CONFIG_LWIP_BATCHTX */ break; #endif /* IPV6_SUPPORT */ default: break; /* non-IP packet */ } #endif /* LWIP_CHECKSUM_PARTIAL || defined CONFIG_LWIP_BATCHTX */ xmit: #if ETH_PAD_SIZE pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ #endif err = netfront_xmit_pbuf(nfi->dev, p, tso, push); if (likely(err == ERR_OK)) { LINK_STATS_INC(link.xmit); } else { LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_transmit: transmission failed, dropping packet: %d\n", err)); LINK_STATS_INC(link.drop); } #if ETH_PAD_SIZE pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ #endif return err; }
/*-----------------------------------------------------------------------------------*/ void icmp_input(struct pbuf *p, struct netif *inp) { unsigned char type; struct icmp_echo_hdr *iecho; struct ip_hdr *iphdr; struct ip_addr tmpaddr; uint16_t hlen; #ifdef ICMP_STATS ++stats.icmp.recv; #endif /* ICMP_STATS */ iphdr = p->payload; hlen = IPH_HL(iphdr) * 4/sizeof(uint8_t); pbuf_header(p, -hlen); type = *((uint8_t *)p->payload); switch(type) { case ICMP_ECHO: if(ip_addr_isbroadcast(&iphdr->dest, &inp->netmask) || ip_addr_ismulticast(&iphdr->dest)) { DEBUGF(ICMP_DEBUG, ("Smurf.\n")); #ifdef ICMP_STATS ++stats.icmp.err; #endif /* ICMP_STATS */ pbuf_free(p); return; } DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); DEBUGF(DEMO_DEBUG, ("Pong!\n")); if(p->tot_len < sizeof(struct icmp_echo_hdr)) { DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); pbuf_free(p); #ifdef ICMP_STATS ++stats.icmp.lenerr; #endif /* ICMP_STATS */ return; } iecho = p->payload; if(inet_chksum_pbuf(p) != 0) { DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); pbuf_free(p); #ifdef ICMP_STATS ++stats.icmp.chkerr; #endif /* ICMP_STATS */ return; } tmpaddr.addr = iphdr->src.addr; iphdr->src.addr = iphdr->dest.addr; iphdr->dest.addr = tmpaddr.addr; ICMPH_TYPE_SET(iecho, ICMP_ER); /* adjust the checksum */ if(iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) { iecho->chksum += htons(ICMP_ECHO << 8) + 1; } else { iecho->chksum += htons(ICMP_ECHO << 8); } #ifdef ICMP_STATS ++stats.icmp.xmit; #endif /* ICMP_STATS */ pbuf_header(p, hlen); /* XXX .mc */ assert(0); /*sr_lwip_output(p, IP_HDRINCL, IP_PROTO_ICMP);*/ break; default: DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type not supported.\n")); #ifdef ICMP_STATS ++stats.icmp.proterr; ++stats.icmp.drop; #endif /* ICMP_STATS */ } pbuf_free(p); }
/*-----------------------------------------------------------------------------------*/ void udp_input(struct pbuf *p, struct netif *inp) { struct udp_hdr *udphdr; struct udp_pcb *pcb; struct ip_hdr *iphdr; uint16_t src, dest; #ifdef UDP_STATS ++stats.udp.recv; #endif /* UDP_STATS */ iphdr = (struct ip_hdr *)p->payload; pbuf_header(p, -(UDP_HLEN + IPH_HL(iphdr) * 4)); udphdr = (struct udp_hdr *)((uint8_t *)p->payload - UDP_HLEN); DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %d\n", p->tot_len)); src = NTOHS(udphdr->src); dest = NTOHS(udphdr->dest); #if UDP_DEBUG udp_debug_print(udphdr); #endif /* UDP_DEBUG */ /* Demultiplex packet. First, go for a perfect match. */ for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { DEBUGF(UDP_DEBUG, ("udp_input: pcb local port %d (dgram %d)\n", pcb->local_port, ntohs(udphdr->dest))); if(pcb->remote_port == src && pcb->local_port == dest && (ip_addr_isany(&pcb->remote_ip) || ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) && (ip_addr_isany(&pcb->local_ip) || ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { break; } } if(pcb == NULL) { for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { DEBUGF(UDP_DEBUG, ("udp_input: pcb local port %d (dgram %d)\n", pcb->local_port, dest)); if(pcb->local_port == dest && (ip_addr_isany(&pcb->remote_ip) || ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) && (ip_addr_isany(&pcb->local_ip) || ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { break; } } } /* Check checksum if this is a match or if it was directed at us. */ /* if(pcb != NULL || ip_addr_cmp(&inp->ip_addr, &iphdr->dest)) {*/ if(pcb != NULL) { DEBUGF(UDP_DEBUG, ("udp_input: calculating checksum\n")); pbuf_header(p, UDP_HLEN); #ifdef IPv6 if(iphdr->nexthdr == IP_PROTO_UDPLITE) { #else if(IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) { #endif /* IPv4 */ /* Do the UDP Lite checksum */ if(inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), (struct ip_addr *)&(iphdr->dest), IP_PROTO_UDPLITE, ntohs(udphdr->len)) != 0) { DEBUGF(UDP_DEBUG, ("udp_input: UDP Lite datagram discarded due to failing checksum\n")); #ifdef UDP_STATS ++stats.udp.chkerr; ++stats.udp.drop; #endif /* UDP_STATS */ pbuf_free(p); goto end; } } else { if(udphdr->chksum != 0) { if(inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), (struct ip_addr *)&(iphdr->dest), IP_PROTO_UDP, p->tot_len) != 0) { DEBUGF(UDP_DEBUG, ("udp_input: UDP datagram discarded due to failing checksum\n")); #ifdef UDP_STATS ++stats.udp.chkerr; ++stats.udp.drop; #endif /* UDP_STATS */ pbuf_free(p); goto end; } } } pbuf_header(p, -UDP_HLEN); if(pcb != NULL) { pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src); } else { DEBUGF(UDP_DEBUG, ("udp_input: not for us.\n")); /* No match was found, send ICMP destination port unreachable unless destination address was broadcast/multicast. */ if(!ip_addr_isbroadcast(&iphdr->dest, &inp->netmask) && !ip_addr_ismulticast(&iphdr->dest)) { /* deconvert from host to network byte order */ udphdr->src = htons(udphdr->src); udphdr->dest = htons(udphdr->dest); /* adjust pbuf pointer */ p->payload = iphdr; icmp_dest_unreach(p, ICMP_DUR_PORT); } #ifdef UDP_STATS ++stats.udp.proterr; ++stats.udp.drop; #endif /* UDP_STATS */ pbuf_free(p); } } else { pbuf_free(p); } end: while(0); /* hack to remove compiler warning */ } /*-----------------------------------------------------------------------------------*/ err_t udp_send(struct udp_pcb *pcb, struct pbuf *p) { struct udp_hdr *udphdr; struct ip_addr *src_ip; err_t err; struct pbuf *q; if(pbuf_header(p, UDP_HLEN)) { q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM); if(q == NULL) { return ERR_MEM; } pbuf_chain(q, p); p = q; } udphdr = (struct udp_hdr *)p->payload; udphdr->src = htons(pcb->local_port); udphdr->dest = htons(pcb->remote_port); udphdr->chksum = 0x0000; src_ip = &(pcb->local_ip); DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %d\n", p->tot_len)); if(pcb->flags & UDP_FLAGS_UDPLITE) { udphdr->len = htons(pcb->chksum_len); /* calculate checksum */ udphdr->chksum = inet_chksum_pseudo(p, src_ip, &(pcb->remote_ip), IP_PROTO_UDP, pcb->chksum_len); if(udphdr->chksum == 0x0000) { udphdr->chksum = 0xffff; } err = sr_lwip_output(p, &pcb->local_ip, &pcb->remote_ip, IP_PROTO_UDPLITE); } else { udphdr->len = htons(p->tot_len); /* calculate checksum */ if((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { udphdr->chksum = inet_chksum_pseudo(p, src_ip, &pcb->remote_ip, IP_PROTO_UDP, p->tot_len); if(udphdr->chksum == 0x0000) { udphdr->chksum = 0xffff; } } err = sr_lwip_output(p,&pcb->local_ip, &pcb->remote_ip, IP_PROTO_UDP); } #ifdef UDP_STATS ++stats.udp.xmit; #endif /* UDP_STATS */ return err; } /*-----------------------------------------------------------------------------------*/ err_t udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, uint16_t port) { struct udp_pcb *ipcb; ip_addr_set(&pcb->local_ip, ipaddr); pcb->local_port = port; /* Insert UDP PCB into the list of active UDP PCBs. */ for(ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { if(pcb == ipcb) { /* Already on the list, just return. */ return ERR_OK; } } /* We need to place the PCB on the list. */ pcb->next = udp_pcbs; udp_pcbs = pcb; DEBUGF(UDP_DEBUG, ("udp_bind: bound to port %d\n", port)); return ERR_OK; } /*-----------------------------------------------------------------------------------*/ err_t udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, uint16_t port) { struct udp_pcb *ipcb; ip_addr_set(&pcb->remote_ip, ipaddr); pcb->remote_port = port; /* Insert UDP PCB into the list of active UDP PCBs. */ for(ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { if(pcb == ipcb) { /* Already on the list, just return. */ return ERR_OK; } } /* We need to place the PCB on the list. */ pcb->next = udp_pcbs; udp_pcbs = pcb; return ERR_OK; } /*-----------------------------------------------------------------------------------*/ void udp_recv(struct udp_pcb *pcb, void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr, uint16_t port), void *recv_arg) { pcb->recv = recv; pcb->recv_arg = recv_arg; }