uint16_t tcp_callback(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, uint16_t flags) { /* Preserve the TCP_ACKDATA, TCP_CLOSE, and TCP_ABORT in the response. * These is needed by uIP to handle responses and buffer state. The * TCP_NEWDATA indication will trigger the ACK response, but must be * explicitly set in the callback. */ nllvdbg("flags: %04x\n", flags); /* Perform the data callback. When a data callback is executed from 'list', * the input flags are normally returned, however, the implementation * may set one of the following: * * TCP_CLOSE - Gracefully close the current connection * TCP_ABORT - Abort (reset) the current connection on an error that * prevents TCP_CLOSE from working. * * And/Or set/clear the following: * * TCP_NEWDATA - May be cleared to indicate that the data was consumed * and that no further process of the new data should be * attempted. * TCP_SNDACK - If TCP_NEWDATA is cleared, then TCP_SNDACK may be set * to indicate that an ACK should be included in the response. * (In TCP_NEWDATA is cleared but TCP_SNDACK is not set, then * dev->d_len should also be cleared). */ flags = devif_callback_execute(dev, conn, flags, conn->list); /* There may be no new data handler in place at them moment that the new * incoming data is received. If the new incoming data was not handled, then * either (1) put the unhandled incoming data in the read-ahead buffer (if * enabled) or (2) suppress the ACK to the data in the hope that it will * be re-transmitted at a better time. */ if ((flags & TCP_NEWDATA) != 0) { /* Data was not handled.. dispose of it appropriately */ flags = tcp_data_event(dev, conn, flags); } /* Check if there is a connection-related event and a connection * callback. */ if (((flags & TCP_CONN_EVENTS) != 0) && conn->connection_event) { /* Perform the callback */ conn->connection_event(conn, flags); } return flags; }
void icmpv6_poll(FAR struct net_driver_s *dev) { /* Setup for the application callback */ dev->d_appdata = &dev->d_buf[NET_LL_HDRLEN(dev) + IPICMPv6_HDRLEN]; dev->d_len = 0; dev->d_sndlen = 0; /* Perform the application callback */ (void)devif_callback_execute(dev, NULL, ICMPv6_POLL, g_icmpv6_conn.list); }
void icmp_input(FAR struct net_driver_s *dev) { FAR struct icmp_iphdr_s *picmp = ICMPBUF; #ifdef CONFIG_NET_STATISTICS g_netstats.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. */ net_ipaddr_hdrcopy(picmp->destipaddr, picmp->srcipaddr); net_ipaddr_hdrcopy(picmp->srcipaddr, &dev->d_ipaddr); /* Recalculate the ICMP checksum */ #if 0 /* The slow way... sum over the ICMP message */ picmp->icmpchksum = 0; picmp->icmpchksum = ~icmp_chksum(dev, (((uint16_t)picmp->len[0] << 8) | (uint16_t)picmp->len[1]) - IP_HDRLEN); 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 g_netstats.icmp.sent++; g_netstats.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)devif_callback_execute(dev, picmp, ICMP_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 g_netstats.icmp.typeerr++; g_netstats.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 (net_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. */ net_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; net_ipaddr_hdrcopy(picmp->destipaddr, picmp->srcipaddr); net_ipaddr_hdrcopy(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 = ~icmp_6chksum(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; net_ipaddr_hdrcopy(picmp->destipaddr, picmp->srcipaddr); net_ipaddr_hdrcopy(picmp->srcipaddr, &dev->d_ipaddr); picmp->icmpchksum = 0; picmp->icmpchksum = ~icmp_6chksum(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 = ICMP_ECHOREPLY; if (g_echocallback) { /* Dispatch the ECHO reply to the waiting thread */ flags = devif_callback_execute(dev, picmp, flags, g_echocallback); } /* If the ECHO reply was not handled, then drop the packet */ if (flags == ICMP_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 g_netstats.icmp.sent++; g_netstats.ip.sent++; #endif return; typeerr: #ifdef CONFIG_NET_STATISTICS g_netstats.icmp.typeerr++; #endif drop: #ifdef CONFIG_NET_STATISTICS g_netstats.icmp.drop++; #endif dev->d_len = 0; #endif /* !CONFIG_NET_IPv6 */ }