/*-----------------------------------------------------------------------------------*/ void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) { struct pbuf *q; struct ip_hdr *iphdr; struct icmp_te_hdr *tehdr; q = pbuf_alloc(PBUF_TRANSPORT, 8 + IP_HLEN + 8, PBUF_RAM); iphdr = p->payload; #if ICMP_DEBUG DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); ip_addr_debug_print(&(iphdr->src)); DEBUGF(ICMP_DEBUG, (" to ")); ip_addr_debug_print(&(iphdr->dest)); DEBUGF(ICMP_DEBUG, ("\n")); #endif /* ICMP_DEBNUG */ tehdr = q->payload; ICMPH_TYPE_SET(tehdr, ICMP_TE); ICMPH_CODE_SET(tehdr, t); /* copy fields from original packet */ bcopy((char *)p->payload, (char *)q->payload + 8, IP_HLEN + 8); /* calculate checksum */ tehdr->chksum = 0; tehdr->chksum = inet_chksum(tehdr, q->len); #ifdef ICMP_STATS ++stats.icmp.xmit; #endif /* ICMP_STATS */ sr_lwip_output(q, &(iphdr->dest), &(iphdr->src), IP_PROTO_ICMP); pbuf_free(q); }
/*-----------------------------------------------------------------------------------*/ void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) { struct pbuf *q; struct ip_hdr *iphdr; struct icmp_dur_hdr *idur; q = pbuf_alloc(PBUF_TRANSPORT, 8 + IP_HLEN + 8, PBUF_RAM); /* ICMP header + IP header + 8 bytes of data */ iphdr = p->payload; idur = q->payload; ICMPH_TYPE_SET(idur, ICMP_DUR); ICMPH_CODE_SET(idur, t); bcopy(p->payload, (char *)q->payload + 8, IP_HLEN + 8); /* calculate checksum */ idur->chksum = 0; idur->chksum = inet_chksum(idur, q->len); #ifdef ICMP_STATS ++stats.icmp.xmit; #endif /* ICMP_STATS */ sr_lwip_output(q,&(iphdr->dest), &(iphdr->src), IP_PROTO_ICMP); pbuf_free(q); }
/*-----------------------------------------------------------------------------------*/ 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; }