void uip_igmpsend(FAR struct uip_driver_s *dev, FAR struct igmp_group_s *group, FAR uip_ipaddr_t *destipaddr) { nllvdbg("msgid: %02x destipaddr: %08x\n", group->msgid, (int)*destipaddr); /* The total length to send is the size of the IP and IGMP headers and 4 * bytes for the ROUTER ALERT (and, eventually, the ethernet header) */ dev->d_len = UIP_IPIGMPH_LEN; /* The total size of the data is the size of the IGMP header */ dev->d_sndlen = UIP_IGMPH_LEN; /* Add the router alert option */ IGMPBUF->ra[0] = HTONS(IPOPT_RA >> 16); IGMPBUF->ra[1] = HTONS(IPOPT_RA & 0xffff); /* Initialize the IPv4 header */ IGMPBUF->vhl = 0x46; /* 4->IP; 6->24 bytes */ IGMPBUF->tos = 0; IGMPBUF->len[0] = (dev->d_len >> 8); IGMPBUF->len[1] = (dev->d_len & 0xff); ++g_ipid; IGMPBUF->ipid[0] = g_ipid >> 8; IGMPBUF->ipid[1] = g_ipid & 0xff; IGMPBUF->ipoffset[0] = UIP_TCPFLAG_DONTFRAG >> 8; IGMPBUF->ipoffset[1] = UIP_TCPFLAG_DONTFRAG & 0xff; IGMPBUF->ttl = IGMP_TTL; IGMPBUF->proto = UIP_PROTO_IGMP; uiphdr_ipaddr_copy(IGMPBUF->srcipaddr, &dev->d_ipaddr); uiphdr_ipaddr_copy(IGMPBUF->destipaddr, destipaddr); /* Calculate IP checksum. */ IGMPBUF->ipchksum = 0; IGMPBUF->ipchksum = ~uip_igmpchksum((FAR uint8_t *)IGMPBUF, UIP_IPH_LEN + RASIZE); /* Set up the IGMP message */ IGMPBUF->type = group->msgid; IGMPBUF->maxresp = 0; uiphdr_ipaddr_copy(IGMPBUF->grpaddr, &group->grpaddr); /* Calculate the IGMP checksum. */ IGMPBUF->chksum = 0; IGMPBUF->chksum = ~uip_igmpchksum(&IGMPBUF->type, UIP_IPIGMPH_LEN); IGMP_STATINCR(uip_stat.igmp.poll_send); IGMP_STATINCR(uip_stat.ip.sent); nllvdbg("Outgoing IGMP packet length: %d (%d)\n", dev->d_len, (IGMPBUF->len[0] << 8) | IGMPBUF->len[1]); igmp_dumppkt(RA, UIP_IPIGMPH_LEN + RASIZE); }
static void uip_tcpsendcommon(struct uip_driver_s *dev, struct uip_conn *conn) { struct uip_tcpip_hdr *pbuf = BUF; memcpy(pbuf->ackno, conn->rcvseq, 4); memcpy(pbuf->seqno, conn->sndseq, 4); pbuf->proto = UIP_PROTO_TCP; pbuf->srcport = conn->lport; pbuf->destport = conn->rport; uiphdr_ipaddr_copy(pbuf->srcipaddr, &dev->d_ipaddr); uiphdr_ipaddr_copy(pbuf->destipaddr, &conn->ripaddr); if (conn->tcpstateflags & UIP_STOPPED) { /* If the connection has issued uip_stop(), we advertise a zero * window so that the remote host will stop sending data. */ pbuf->wnd[0] = 0; pbuf->wnd[1] = 0; } else { pbuf->wnd[0] = ((CONFIG_NET_RECEIVE_WINDOW) >> 8); pbuf->wnd[1] = ((CONFIG_NET_RECEIVE_WINDOW) & 0xff); } /* Finish the IP portion of the message, calculate checksums and send * the message. */ uip_tcpsendcomplete(dev); }
void uip_icmpsend(struct uip_driver_s *dev, uip_ipaddr_t *destaddr) { struct uip_icmpip_hdr *picmp = ICMPBUF; if (dev->d_sndlen > 0) { /* The total length to send is the size of the application data plus * the IP and ICMP headers (and, eventually, the ethernet header) */ dev->d_len = dev->d_sndlen + UIP_IPICMPH_LEN; /* The total size of the data (for ICMP checksum calculation) includes * the size of the ICMP header */ dev->d_sndlen += UIP_ICMPH_LEN; /* Initialize the IP header. Note that for IPv6, the IP length field * does not include the IPv6 IP header length. */ #ifdef CONFIG_NET_IPv6 picmp->vtc = 0x60; picmp->tcf = 0x00; picmp->flow = 0x00; picmp->len[0] = (dev->d_sndlen >> 8); picmp->len[1] = (dev->d_sndlen & 0xff); picmp->nexthdr = UIP_PROTO_ICMP; picmp->hoplimit = UIP_TTL; uip_ipaddr_copy(picmp->srcipaddr, &dev->d_ipaddr); uip_ipaddr_copy(picmp->destipaddr, destaddr); #else /* CONFIG_NET_IPv6 */ picmp->vhl = 0x45; picmp->tos = 0; picmp->len[0] = (dev->d_len >> 8); picmp->len[1] = (dev->d_len & 0xff); ++g_ipid; picmp->ipid[0] = g_ipid >> 8; picmp->ipid[1] = g_ipid & 0xff; picmp->ipoffset[0] = UIP_TCPFLAG_DONTFRAG >> 8; picmp->ipoffset[1] = UIP_TCPFLAG_DONTFRAG & 0xff; picmp->ttl = UIP_TTL; picmp->proto = UIP_PROTO_ICMP; uiphdr_ipaddr_copy(picmp->srcipaddr, &dev->d_ipaddr); uiphdr_ipaddr_copy(picmp->destipaddr, destaddr); /* Calculate IP checksum. */ picmp->ipchksum = 0; picmp->ipchksum = ~(uip_ipchksum(dev)); #endif /* CONFIG_NET_IPv6 */ /* Calculate the ICMP checksum. */ picmp->icmpchksum = 0; picmp->icmpchksum = ~(uip_icmpchksum(dev, dev->d_sndlen)); if (picmp->icmpchksum == 0) { picmp->icmpchksum = 0xffff; } nllvdbg("Outgoing ICMP packet length: %d (%d)\n", dev->d_len, (picmp->len[0] << 8) | picmp->len[1]); #ifdef CONFIG_NET_STATISTICS uip_stat.icmp.sent++; uip_stat.ip.sent++; #endif }
void uip_icmpinput(struct uip_driver_s *dev) { struct uip_icmpip_hdr *picmp = ICMPBUF; #ifdef CONFIG_NET_STATISTICS uip_stat.icmp.recv++; #endif #ifndef CONFIG_NET_IPv6 /* ICMPv4 processing code follows. */ /* ICMP echo (i.e., ping) processing. This is simple, we only change the * ICMP type from ECHO to ECHO_REPLY and adjust the ICMP checksum before * we return the packet. */ if (picmp->type == ICMP_ECHO_REQUEST) { /* If we are configured to use ping IP address assignment, we use * the destination IP address of this ping packet and assign it to * ourself. */ #ifdef CONFIG_NET_PINGADDRCONF if (dev->d_ipaddr == 0) { dev->d_ipaddr = picmp->destipaddr; } #endif /* Change the ICMP type */ picmp->type = ICMP_ECHO_REPLY; /* Swap IP addresses. */ uiphdr_ipaddr_copy(picmp->destipaddr, picmp->srcipaddr); uiphdr_ipaddr_copy(picmp->srcipaddr, &dev->d_ipaddr); /* Recalculate the ICMP checksum */ #if 0 /* The slow way... sum over the ICMP message */ picmp->icmpchksum = 0; picmp->icmpchksum = ~uip_icmpchksum(dev, (((uint16_t)picmp->len[0] << 8) | (uint16_t)picmp->len[1]) - UIP_IPH_LEN); if (picmp->icmpchksum == 0) { picmp->icmpchksum = 0xffff; } #else /* The quick way -- Since only the type has changed, just adjust the * checksum for the change of type */ if (picmp->icmpchksum >= HTONS(0xffff - (ICMP_ECHO_REQUEST << 8))) { picmp->icmpchksum += HTONS(ICMP_ECHO_REQUEST << 8) + 1; } else { picmp->icmpchksum += HTONS(ICMP_ECHO_REQUEST << 8); } #endif nllvdbg("Outgoing ICMP packet length: %d (%d)\n", dev->d_len, (picmp->len[0] << 8) | picmp->len[1]); #ifdef CONFIG_NET_STATISTICS uip_stat.icmp.sent++; uip_stat.ip.sent++; #endif } /* If an ICMP echo reply is received then there should also be * a thread waiting to received the echo response. */ #ifdef CONFIG_NET_ICMP_PING else if (picmp->type == ICMP_ECHO_REPLY && g_echocallback) { (void)uip_callbackexecute(dev, picmp, UIP_ECHOREPLY, g_echocallback); } #endif /* Otherwise the ICMP input was not processed */ else { nlldbg("Unknown ICMP cmd: %d\n", picmp->type); goto typeerr; } return; typeerr: #ifdef CONFIG_NET_STATISTICS uip_stat.icmp.typeerr++; uip_stat.icmp.drop++; #endif dev->d_len = 0; #else /* !CONFIG_NET_IPv6 */ /* If we get a neighbor solicitation for our address we should send * a neighbor advertisement message back. */ if (picmp->type == ICMP6_NEIGHBOR_SOLICITATION) { if (uip_ipaddr_cmp(picmp->icmp6data, dev->d_ipaddr)) { if (picmp->options[0] == ICMP6_OPTION_SOURCE_LINK_ADDRESS) { /* Save the sender's address in our neighbor list. */ uiphdr_neighbor_add(picmp->srcipaddr, &(picmp->options[2])); } /* We should now send a neighbor advertisement back to where the * neighbor solicitation came from. */ picmp->type = ICMP6_NEIGHBOR_ADVERTISEMENT; picmp->flags = ICMP6_FLAG_S; /* Solicited flag. */ picmp->reserved1 = picmp->reserved2 = picmp->reserved3 = 0; uiphdr_ipaddr_copy(picmp->destipaddr, picmp->srcipaddr); uiphdr_ipaddr_copy(picmp->srcipaddr, &dev->d_ipaddr); picmp->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS; picmp->options[1] = 1; /* Options length, 1 = 8 bytes. */ memcpy(&(picmp->options[2]), &dev->d_mac, IFHWADDRLEN); picmp->icmpchksum = 0; picmp->icmpchksum = ~uip_icmp6chksum(dev); } else { goto drop; } } else if (picmp->type == ICMP6_ECHO_REQUEST) { /* ICMP echo (i.e., ping) processing. This is simple, we only * change the ICMP type from ECHO to ECHO_REPLY and update the * ICMP checksum before we return the packet. */ picmp->type = ICMP6_ECHO_REPLY; uiphdr_ipaddr_copy(picmp->destipaddr, picmp->srcipaddr); uiphdr_ipaddr_copy(picmp->srcipaddr, &dev->d_ipaddr); picmp->icmpchksum = 0; picmp->icmpchksum = ~uip_icmp6chksum(dev); } /* If an ICMP echo reply is received then there should also be * a thread waiting to received the echo response. */ #ifdef CONFIG_NET_ICMP_PING else if (picmp->type == ICMP6_ECHO_REPLY && g_echocallback) { uint16_t flags = UIP_ECHOREPLY; if (g_echocallback) { /* Dispatch the ECHO reply to the waiting thread */ flags = uip_callbackexecute(dev, picmp, flags, g_echocallback); } /* If the ECHO reply was not handled, then drop the packet */ if (flags == UIP_ECHOREPLY) { /* The ECHO reply was not handled */ goto drop; } } #endif else { nlldbg("Unknown ICMP6 cmd: %d\n", picmp->type); goto typeerr; } nllvdbg("Outgoing ICMP6 packet length: %d (%d)\n", dev->d_len, (picmp->len[0] << 8) | picmp->len[1]); #ifdef CONFIG_NET_STATISTICS uip_stat.icmp.sent++; uip_stat.ip.sent++; #endif return; typeerr: #ifdef CONFIG_NET_STATISTICS uip_stat.icmp.typeerr++; #endif drop: #ifdef CONFIG_NET_STATISTICS uip_stat.icmp.drop++; #endif dev->d_len = 0; #endif /* !CONFIG_NET_IPv6 */ }
void uip_tcpreset(struct uip_driver_s *dev) { struct uip_tcpip_hdr *pbuf = BUF; uint16_t tmp16; uint8_t seqbyte; #ifdef CONFIG_NET_STATISTICS uip_stat.tcp.rst++; #endif pbuf->flags = TCP_RST | TCP_ACK; dev->d_len = UIP_IPTCPH_LEN; pbuf->tcpoffset = 5 << 4; /* Flip the seqno and ackno fields in the TCP header. */ seqbyte = pbuf->seqno[3]; pbuf->seqno[3] = pbuf->ackno[3]; pbuf->ackno[3] = seqbyte; seqbyte = pbuf->seqno[2]; pbuf->seqno[2] = pbuf->ackno[2]; pbuf->ackno[2] = seqbyte; seqbyte = pbuf->seqno[1]; pbuf->seqno[1] = pbuf->ackno[1]; pbuf->ackno[1] = seqbyte; seqbyte = pbuf->seqno[0]; pbuf->seqno[0] = pbuf->ackno[0]; pbuf->ackno[0] = seqbyte; /* We also have to increase the sequence number we are * acknowledging. If the least significant byte overflowed, we need * to propagate the carry to the other bytes as well. */ if (++(pbuf->ackno[3]) == 0) { if (++(pbuf->ackno[2]) == 0) { if (++(pbuf->ackno[1]) == 0) { ++(pbuf->ackno[0]); } } } /* Swap port numbers. */ tmp16 = pbuf->srcport; pbuf->srcport = pbuf->destport; pbuf->destport = tmp16; /* Swap IP addresses. */ uiphdr_ipaddr_copy(pbuf->destipaddr, pbuf->srcipaddr); uiphdr_ipaddr_copy(pbuf->srcipaddr, &dev->d_ipaddr); /* And send out the RST packet */ uip_tcpsendcomplete(dev); }
void uip_udpsend(struct uip_driver_s *dev, struct uip_udp_conn *conn) { struct uip_udpip_hdr *pudpbuf = UDPBUF; if (dev->d_sndlen > 0) { /* The total lenth to send is the size of the application data plus * the IP and UDP headers (and, eventually, the ethernet header) */ dev->d_len = dev->d_sndlen + UIP_IPUDPH_LEN; /* Initialize the IP header. Note that for IPv6, the IP length field * does not include the IPv6 IP header length. */ #ifdef CONFIG_NET_IPv6 pudpbuf->vtc = 0x60; pudpbuf->tcf = 0x00; pudpbuf->flow = 0x00; pudpbuf->len[0] = (dev->d_sndlen >> 8); pudpbuf->len[1] = (dev->d_sndlen & 0xff); pudpbuf->nexthdr = UIP_PROTO_UDP; pudpbuf->hoplimit = conn->ttl; uip_ipaddr_copy(pudpbuf->srcipaddr, &dev->d_ipaddr); uip_ipaddr_copy(pudpbuf->destipaddr, &conn->ripaddr); #else /* CONFIG_NET_IPv6 */ pudpbuf->vhl = 0x45; pudpbuf->tos = 0; pudpbuf->len[0] = (dev->d_len >> 8); pudpbuf->len[1] = (dev->d_len & 0xff); ++g_ipid; pudpbuf->ipid[0] = g_ipid >> 8; pudpbuf->ipid[1] = g_ipid & 0xff; pudpbuf->ipoffset[0] = 0; pudpbuf->ipoffset[1] = 0; pudpbuf->ttl = conn->ttl; pudpbuf->proto = UIP_PROTO_UDP; uiphdr_ipaddr_copy(pudpbuf->srcipaddr, &dev->d_ipaddr); uiphdr_ipaddr_copy(pudpbuf->destipaddr, &conn->ripaddr); /* Calculate IP checksum. */ pudpbuf->ipchksum = 0; pudpbuf->ipchksum = ~(uip_ipchksum(dev)); #endif /* CONFIG_NET_IPv6 */ /* Initialize the UDP header */ pudpbuf->srcport = conn->lport; pudpbuf->destport = conn->rport; pudpbuf->udplen = HTONS(dev->d_sndlen + UIP_UDPH_LEN); #ifdef CONFIG_NET_UDP_CHECKSUMS /* Calculate UDP checksum. */ pudpbuf->udpchksum = 0; pudpbuf->udpchksum = ~(uip_udpchksum(dev)); if (pudpbuf->udpchksum == 0) { pudpbuf->udpchksum = 0xffff; } #else pudpbuf->udpchksum = 0; #endif nllvdbg("Outgoing UDP packet length: %d (%d)\n", dev->d_len, (pudpbuf->len[0] << 8) | pudpbuf->len[1]); #ifdef CONFIG_NET_STATISTICS uip_stat.udp.sent++; uip_stat.ip.sent++; #endif }