static inline FAR struct tcp_conn_s * tcp_ipv4_active(FAR struct net_driver_s *dev, FAR struct tcp_hdr_s *tcp) { FAR struct ipv4_hdr_s *ip = IPv4BUF; FAR struct tcp_conn_s *conn; in_addr_t srcipaddr; #ifdef CONFIG_NETDEV_MULTINIC in_addr_t destipaddr; #endif conn = (FAR struct tcp_conn_s *)g_active_tcp_connections.head; srcipaddr = net_ip4addr_conv32(ip->srcipaddr); #ifdef CONFIG_NETDEV_MULTINIC destipaddr = net_ip4addr_conv32(ip->destipaddr); #endif while (conn) { /* Find an open connection matching the TCP input. The following * checks are performed: * * - The local port number is checked against the destination port * number in the received packet. * - The remote port number is checked if the connection is bound * to a remote port. * - If multiple network interfaces are supported, then the local * IP address is available and we will insist that the * destination IP matches the bound address. If a socket is * bound to INADDRY_ANY, then it should receive all packets * directed to the port. * - Finally, if the connection is bound to a remote IP address, * the source IP address of the packet is checked. * * If all of the above are true then the newly received TCP packet * is destined for this TCP connection. */ if (conn->tcpstateflags != TCP_CLOSED && tcp->destport == conn->lport && tcp->srcport == conn->rport && #ifdef CONFIG_NETDEV_MULTINIC (net_ipv4addr_cmp(conn->u.ipv4.laddr, INADDR_ANY) || net_ipv4addr_cmp(destipaddr, conn->u.ipv4.laddr)) && #endif net_ipv4addr_cmp(srcipaddr, conn->u.ipv4.raddr)) { /* Matching connection found.. break out of the loop and return a * reference to it. */ break; } /* Look at the next active connection */ conn = (FAR struct tcp_conn_s *)conn->node.flink; } return conn; }
static int net_match_ipv4(FAR struct net_route_ipv4_s *route, FAR void *arg) { FAR struct route_match_ipv4_s *match = (FAR struct route_match_ipv4_s *)arg; /* To match, the masked target address must be the same, and the masks * must be the same. */ net_ipv4_dumproute("Comparing", route); ninfo("With:\n"); ninfo(" target=%08lx netmask=%08lx\n", htonl(match->target), htonl(match->netmask)); if (net_ipv4addr_maskcmp(route->target, match->target, match->netmask) && net_ipv4addr_cmp(route->netmask, match->netmask)) { /* They match.. a non-zero value to terminate the traversal. The last * value of index is the index to the matching entry. */ return 1; } /* Next time we are here, this will be the routing table index */ match->index++; return 0; }
FAR struct igmp_group_s *igmp_grpfind(FAR struct net_driver_s *dev, FAR const in_addr_t *addr) { FAR struct igmp_group_s *group; net_lock_t flags; grplldbg("Searching for addr %08x\n", (int)*addr); /* We must disable interrupts because we don't which context we were * called from. */ flags = net_lock(); for (group = (FAR struct igmp_group_s *)dev->grplist.head; group; group = group->next) { grplldbg("Compare: %08x vs. %08x\n", group->grpaddr, *addr); if (net_ipv4addr_cmp(group->grpaddr, *addr)) { grplldbg("Match!\n"); break; } } net_unlock(flags); return group; }
static inline FAR struct tcp_conn_s *tcp_ipv4_listener(in_addr_t ipaddr, uint16_t portno) { FAR struct tcp_conn_s *conn; int i; /* Check if this port number is in use by any active UIP TCP connection */ for (i = 0; i < CONFIG_NET_TCP_CONNS; i++) { conn = &g_tcp_connections[i]; /* Check if this connection is open and the local port assignment * matches the requested port number. */ if (conn->tcpstateflags != TCP_CLOSED && conn->lport == portno) { /* If there are multiple interface devices, then the local IP * address of the connection must also match. INADDR_ANY is a * special case: There can only be instance of a port number * with INADDR_ANY. */ if (net_ipv4addr_cmp(conn->u.ipv4.laddr, ipaddr) || net_ipv4addr_cmp(conn->u.ipv4.laddr, INADDR_ANY)) { /* The port number is in use, return the connection */ return conn; } } } return NULL; }
FAR struct arp_entry *arp_find(in_addr_t ipaddr) { FAR struct arp_entry *tabptr; int i; for (i = 0; i < CONFIG_NET_ARPTAB_SIZE; ++i) { tabptr = &g_arptable[i]; if (net_ipv4addr_cmp(ipaddr, tabptr->at_ipaddr)) { return tabptr; } } return NULL; }
static int tcp_find_ipv4_device(FAR struct tcp_conn_s *conn, in_addr_t addr) { #ifdef CONFIG_NETDEV_MULTINIC /* Do nothing if a device is already bound to the connection */ if (conn->dev != NULL) { return OK; } /* Return success without using device notification if the locally bound * address is INADDR_ANY. In this case, there may be multiple devices * that can provide data so the exceptional events from any particular * device are not important. */ if (net_ipv4addr_cmp(addr, INADDR_ANY)) { return OK; } /* There are multiple network devices. We need to select the device that * is going to route the TCP packet based on the provided IP address. */ conn->dev = netdev_findby_ipv4addr(addr, addr); /* Return success if we found the device */ return conn->dev != NULL ? OK : -ENETUNREACH; #else /* There is only a single network device... the one at the head of the * g_netdevices list. */ return (g_netdevices != NULL) ? OK : -ENETUNREACH; #endif }
static int net_match(FAR struct net_route_s *route, FAR void *arg) { FAR struct route_match_s *match = ( FAR struct route_match_s *)arg; /* To match, the masked target address must be the same, and the masks * must be the same. */ if (net_ipv4addr_maskcmp(route->target, match->target, match->netmask) && net_ipv4addr_cmp(route->netmask, match->netmask)) { /* They match.. Remove the entry from the routing table */ if (match->prev) { (void)sq_remafter((FAR sq_entry_t *)match->prev, (FAR sq_queue_t *)&g_routes); } else { (void)sq_remfirst((FAR sq_queue_t *)&g_routes); } /* And free the routing table entry by adding it to the free list */ net_freeroute(route); /* Return a non-zero value to terminate the traversal */ return 1; } /* Next time we are here, this will be the previous entry */ match->prev = route; return 0; }
int arp_update(in_addr_t ipaddr, FAR uint8_t *ethaddr) { struct arp_entry *tabptr = NULL; int i; /* Walk through the ARP mapping table and try to find an entry to * update. If none is found, the IP -> MAC address mapping is * inserted in the ARP table. */ for (i = 0; i < CONFIG_NET_ARPTAB_SIZE; ++i) { tabptr = &g_arptable[i]; /* Only check those entries that are actually in use. */ if (tabptr->at_ipaddr != 0) { /* Check if the source IP address of the incoming packet matches * the IP address in this ARP table entry. */ if (net_ipv4addr_cmp(ipaddr, tabptr->at_ipaddr)) { /* An old entry found, update this and return. */ memcpy(tabptr->at_ethaddr.ether_addr_octet, ethaddr, ETHER_ADDR_LEN); tabptr->at_time = g_arptime; return OK; } } } /* If we get here, no existing ARP table entry was found, so we create one. */ /* First, we try to find an unused entry in the ARP table. */ for (i = 0; i < CONFIG_NET_ARPTAB_SIZE; ++i) { tabptr = &g_arptable[i]; if (tabptr->at_ipaddr == 0) { break; } } /* If no unused entry is found, we try to find the oldest entry and * throw it away. */ if (i == CONFIG_NET_ARPTAB_SIZE) { uint8_t tmpage = 0; int j = 0; for (i = 0; i < CONFIG_NET_ARPTAB_SIZE; ++i) { tabptr = &g_arptable[i]; if (g_arptime - tabptr->at_time > tmpage) { tmpage = g_arptime - tabptr->at_time; j = i; } } i = j; tabptr = &g_arptable[i]; } /* Now, i is the ARP table entry which we will fill with the new * information. */ tabptr->at_ipaddr = ipaddr; memcpy(tabptr->at_ethaddr.ether_addr_octet, ethaddr, ETHER_ADDR_LEN); tabptr->at_time = g_arptime; return OK; }
int ipv4_input(FAR struct net_driver_s *dev) { FAR struct ipv4_hdr_s *pbuf = BUF; uint16_t iplen; /* This is where the input processing starts. */ #ifdef CONFIG_NET_STATISTICS g_netstats.ipv4.recv++; #endif /* Start of IP input header processing code. */ /* Check validity of the IP header. */ if (pbuf->vhl != 0x45) { /* IP version and header length. */ #ifdef CONFIG_NET_STATISTICS g_netstats.ipv4.drop++; g_netstats.ipv4.vhlerr++; #endif nlldbg("Invalid IP version or header length: %02x\n", pbuf->vhl); goto drop; } /* Check the size of the packet. If the size reported to us in d_len is * smaller the size reported in the IP header, we assume that the packet * has been corrupted in transit. If the size of d_len is larger than the * size reported in the IP packet header, the packet has been padded and * we set d_len to the correct value. */ iplen = (pbuf->len[0] << 8) + pbuf->len[1]; if (iplen <= dev->d_len) { dev->d_len = iplen; } else { nlldbg("IP packet shorter than length in IP header\n"); goto drop; } /* Check the fragment flag. */ if ((pbuf->ipoffset[0] & 0x3f) != 0 || pbuf->ipoffset[1] != 0) { #if defined(CONFIG_NET_TCP_REASSEMBLY) dev->d_len = devif_reassembly(); if (dev->d_len == 0) { goto drop; } #else /* CONFIG_NET_TCP_REASSEMBLY */ #ifdef CONFIG_NET_STATISTICS g_netstats.ipv4.drop++; g_netstats.ipv4.fragerr++; #endif nlldbg("IP fragment dropped\n"); goto drop; #endif /* CONFIG_NET_TCP_REASSEMBLY */ } /* If IP broadcast support is configured, we check for a broadcast * UDP packet, which may be destined to us (even if there is no IP * address yet assigned to the device as is the case when we are * negotiating over DHCP for an address). */ #if defined(CONFIG_NET_BROADCAST) && defined(CONFIG_NET_UDP_STACK) if (pbuf->proto == IP_PROTO_UDP && net_ipv4addr_cmp(net_ip4addr_conv32(pbuf->destipaddr), g_ipv4_alloneaddr)) { return udp_ipv4_input(dev); } /* In most other cases, the device must be assigned a non-zero IP * address. Another exception is when CONFIG_NET_PINGADDRCONF is * enabled... */ else #endif #ifdef CONFIG_NET_ICMP if (net_ipv4addr_cmp(dev->d_ipaddr, g_ipv4_allzeroaddr)) { /* If we are configured to use ping IP address configuration and * hasn't been assigned an IP address yet, we accept all ICMP * packets. */ #ifdef CONFIG_NET_PINGADDRCONF if (pbuf->proto == IP_PROTO_ICMP) { nlldbg("Possible ping config packet received\n"); icmp_input(dev); goto drop; } else #endif { nlldbg("No IP address assigned\n"); goto drop; } } /* Check if the packet is destined for out IP address */ else #endif { /* Check if the packet is destined for our IP address. */ if (!net_ipv4addr_cmp(net_ip4addr_conv32(pbuf->destipaddr), dev->d_ipaddr)) { #ifdef CONFIG_NET_IGMP in_addr_t destip = net_ip4addr_conv32(pbuf->destipaddr); if (igmp_grpfind(dev, &destip) == NULL) #endif { #ifdef CONFIG_NET_STATISTICS g_netstats.ipv4.drop++; #endif goto drop; } } } if (ipv4_chksum(dev) != 0xffff) { /* Compute and check the IP header checksum. */ #ifdef CONFIG_NET_STATISTICS g_netstats.ipv4.drop++; g_netstats.ipv4.chkerr++; #endif nlldbg("Bad IP checksum\n"); goto drop; } /* Make sure that all packet processing logic knows that there is an IPv4 * packet in the device buffer. */ IFF_SET_IPv4(dev->d_flags); /* Now process the incoming packet according to the protocol. */ switch (pbuf->proto) { #ifdef CONFIG_NET_TCP_STACK case IP_PROTO_TCP: /* TCP input */ tcp_ipv4_input(dev); break; #endif #ifdef CONFIG_NET_UDP_STACK case IP_PROTO_UDP: /* UDP input */ udp_ipv4_input(dev); break; #endif /* Check for ICMP input */ #ifdef CONFIG_NET_ICMP case IP_PROTO_ICMP: /* ICMP input */ icmp_input(dev); break; #endif /* Check for IGMP input */ #ifdef CONFIG_NET_IGMP case IP_PROTO_IGMP: /* IGMP input */ igmp_input(dev); break; #endif default: /* Unrecognized/unsupported protocol */ #ifdef CONFIG_NET_STATISTICS g_netstats.ipv4.drop++; g_netstats.ipv4.protoerr++; #endif nlldbg("Unrecognized IP protocol\n"); goto drop; } /* Return and let the caller do any pending transmission. */ return OK; /* Drop the packet. NOTE that OK is returned meaning that the * packet has been processed (although processed unsuccessfully). */ drop: dev->d_len = 0; return OK; }