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; }
FAR struct tcp_conn_s *tcp_active(struct tcp_iphdr_s *buf) { FAR struct tcp_conn_s *conn = (struct tcp_conn_s *)g_active_tcp_connections.head; in_addr_t srcipaddr = net_ip4addr_conv32(buf->srcipaddr); while (conn) { /* Find an open connection matching the tcp input */ if (conn->tcpstateflags != TCP_CLOSED && buf->destport == conn->lport && buf->srcport == conn->rport && net_ipaddr_cmp(srcipaddr, conn->ripaddr)) { /* 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; }
void arp_hdr_update(FAR uint16_t *pipaddr, FAR uint8_t *ethaddr) { in_addr_t ipaddr = net_ip4addr_conv32(pipaddr); /* Update the ARP table */ (void)arp_update(ipaddr, ethaddr); }
FAR struct tcp_conn_s *tcp_alloc_accept(FAR struct tcp_iphdr_s *buf) { FAR struct tcp_conn_s *conn = tcp_alloc(); if (conn) { /* Fill in the necessary fields for the new connection. */ conn->rto = TCP_RTO; conn->timer = TCP_RTO; conn->sa = 0; conn->sv = 4; conn->nrtx = 0; conn->lport = buf->destport; conn->rport = buf->srcport; conn->mss = TCP_INITIAL_MSS; net_ipaddr_copy(conn->ripaddr, net_ip4addr_conv32(buf->srcipaddr)); conn->tcpstateflags = TCP_SYN_RCVD; tcp_initsequence(conn->sndseq); conn->unacked = 1; #ifdef CONFIG_NET_TCP_WRITE_BUFFERS conn->expired = 0; conn->isn = 0; conn->sent = 0; #endif /* rcvseq should be the seqno from the incoming packet + 1. */ memcpy(conn->rcvseq, buf->seqno, 4); #ifdef CONFIG_NET_TCP_READAHEAD /* Initialize the list of TCP read-ahead buffers */ IOB_QINIT(&conn->readahead); #endif #ifdef CONFIG_NET_TCP_WRITE_BUFFERS /* Initialize the write buffer lists */ sq_init(&conn->write_q); sq_init(&conn->unacked_q); #endif /* And, finally, put the connection structure into the active list. * Interrupts should already be disabled in this context. */ dq_addlast(&conn->node, &g_active_tcp_connections); } return conn; }
void arp_ipin(FAR struct net_driver_s *dev) { in_addr_t srcipaddr; /* Only insert/update an entry if the source IP address of the incoming IP * packet comes from a host on the local network. */ srcipaddr = net_ip4addr_conv32(IPBUF->eh_srcipaddr); if (net_ipv4addr_maskcmp(srcipaddr, dev->d_ipaddr, dev->d_netmask)) { arp_hdr_update(IPBUF->eh_srcipaddr, ETHBUF->src); } }
static uint16_t udp_datahandler(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn, FAR uint8_t *buffer, uint16_t buflen) { FAR struct iob_s *iob; int ret; #ifdef CONFIG_NET_IPv6 FAR struct sockaddr_in6 src_addr6; #endif #ifdef CONFIG_NET_IPv4 FAR struct sockaddr_in src_addr4; #endif FAR void *src_addr; uint8_t src_addr_size; /* Allocate on I/O buffer to start the chain (throttling as necessary). * We will not wait for an I/O buffer to become available in this context. */ iob = iob_tryalloc(true); if (iob == NULL) { nerr("ERROR: Failed to create new I/O buffer chain\n"); return 0; } #ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv4 if (IFF_IS_IPv6(dev->d_flags)) #endif { FAR struct udp_hdr_s *udp = UDPIPv6BUF; FAR struct ipv6_hdr_s *ipv6 = IPv6BUF; src_addr6.sin6_family = AF_INET6; src_addr6.sin6_port = udp->srcport; net_ipv6addr_copy(src_addr6.sin6_addr.s6_addr, ipv6->srcipaddr); src_addr_size = sizeof(src_addr6); src_addr = &src_addr6; } #endif /* CONFIG_NET_IPv6 */ #ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv6 else #endif { #ifdef CONFIG_NET_IPv6 /* Hybrid dual-stack IPv6/IPv4 implementations recognize a special * class of addresses, the IPv4-mapped IPv6 addresses. */ if (conn->domain == PF_INET6) { FAR struct udp_hdr_s *udp = UDPIPv6BUF; FAR struct ipv6_hdr_s *ipv6 = IPv6BUF; in_addr_t ipv4addr; /* Encode the IPv4 address as an IPv-mapped IPv6 address */ src_addr6.sin6_family = AF_INET6; src_addr6.sin6_port = udp->srcport; ipv4addr = net_ip4addr_conv32(ipv6->srcipaddr); ip6_map_ipv4addr(ipv4addr, src_addr6.sin6_addr.s6_addr16); src_addr_size = sizeof(src_addr6); src_addr = &src_addr6; } else #endif { FAR struct udp_hdr_s *udp = UDPIPv4BUF; FAR struct ipv4_hdr_s *ipv4 = IPv4BUF; src_addr4.sin_family = AF_INET; src_addr4.sin_port = udp->srcport; net_ipv4addr_copy(src_addr4.sin_addr.s_addr, net_ip4addr_conv32(ipv4->srcipaddr)); src_addr_size = sizeof(src_addr4); src_addr = &src_addr4; } } #endif /* CONFIG_NET_IPv4 */ /* Copy the src address info into the I/O buffer chain. We will not wait * for an I/O buffer to become available in this context. It there is * any failure to allocated, the entire I/O buffer chain will be discarded. */ ret = iob_trycopyin(iob, (FAR const uint8_t *)&src_addr_size, sizeof(uint8_t), 0, true); if (ret < 0) { /* On a failure, iob_trycopyin return a negated error value but does * not free any I/O buffers. */ nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret); (void)iob_free_chain(iob); return 0; } ret = iob_trycopyin(iob, (FAR const uint8_t *)src_addr, src_addr_size, sizeof(uint8_t), true); if (ret < 0) { /* On a failure, iob_trycopyin return a negated error value but does * not free any I/O buffers. */ nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret); (void)iob_free_chain(iob); return 0; } if (buflen > 0) { /* Copy the new appdata into the I/O buffer chain */ ret = iob_trycopyin(iob, buffer, buflen, src_addr_size + sizeof(uint8_t), true); if (ret < 0) { /* On a failure, iob_trycopyin return a negated error value but * does not free any I/O buffers. */ nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret); (void)iob_free_chain(iob); return 0; } } /* Add the new I/O buffer chain to the tail of the read-ahead queue */ ret = iob_tryadd_queue(iob, &conn->readahead); if (ret < 0) { nerr("ERROR: Failed to queue the I/O buffer chain: %d\n", ret); (void)iob_free_chain(iob); return 0; } #ifdef CONFIG_UDP_READAHEAD_NOTIFIER /* Provided notification(s) that additional UDP read-ahead data is * available. */ udp_notifier_signal(conn); #endif ninfo("Buffered %d bytes\n", buflen); return buflen; }
void arp_out(FAR struct net_driver_s *dev) { struct ether_addr ethaddr; FAR struct eth_hdr_s *peth = ETHBUF; FAR struct arp_iphdr_s *pip = IPBUF; in_addr_t ipaddr; in_addr_t destipaddr; int ret; #if defined(CONFIG_NET_PKT) || defined(CONFIG_NET_ARP_SEND) /* Skip sending ARP requests when the frame to be transmitted was * written into a packet socket. */ if (IFF_IS_NOARP(dev->d_flags)) { /* Clear the indication and let the packet continue on its way. */ IFF_CLR_NOARP(dev->d_flags); return; } #endif /* Find the destination IP address in the ARP table and construct * the Ethernet header. If the destination IP address isn't on the * local network, we use the default router's IP address instead. * * If not ARP table entry is found, we overwrite the original IP * packet with an ARP request for the IP address. */ /* First check if destination is a local broadcast. */ if (net_ipv4addr_hdrcmp(pip->eh_destipaddr, g_broadcast_ipaddr)) { memcpy(peth->dest, g_broadcast_ethaddr.ether_addr_octet, ETHER_ADDR_LEN); goto finish_header; } #ifdef CONFIG_NET_IGMP /* Check if the destination address is a multicast address * * - IPv4: multicast addresses lie in the class D group -- The address range * 224.0.0.0 to 239.255.255.255 (224.0.0.0/4) * * - IPv6 multicast addresses are have the high-order octet of the * addresses=0xff (ff00::/8.) */ if (NTOHS(pip->eh_destipaddr[0]) >= 0xe000 && NTOHS(pip->eh_destipaddr[0]) <= 0xefff) { /* Build the well-known IPv4 IGMP Ethernet address. The first * three bytes are fixed; the final three variable come from the * last three bytes of the IPv4 address (network order). * * Address range : 01:00:5e:00:00:00 to 01:00:5e:7f:ff:ff */ FAR const uint8_t *ip = (FAR uint8_t *)pip->eh_destipaddr; peth->dest[0] = g_multicast_ethaddr[0]; peth->dest[1] = g_multicast_ethaddr[1]; peth->dest[2] = g_multicast_ethaddr[2]; peth->dest[3] = ip[1] & 0x7f; peth->dest[4] = ip[2]; peth->dest[5] = ip[3]; goto finish_header; } #endif /* Check if the destination address is on the local network. */ destipaddr = net_ip4addr_conv32(pip->eh_destipaddr); if (!net_ipv4addr_maskcmp(destipaddr, dev->d_ipaddr, dev->d_netmask)) { /* Destination address is not on the local network */ #ifdef CONFIG_NET_ROUTE /* We have a routing table.. find the correct router to use in * this case (or, as a fall-back, use the device's default router * address). We will use the router IP address instead of the * destination address when determining the MAC address. */ netdev_ipv4_router(dev, destipaddr, &ipaddr); #else /* Use the device's default router IP address instead of the * destination address when determining the MAC address. */ net_ipv4addr_copy(ipaddr, dev->d_draddr); #endif } /* The destination address is on the local network. Check if it is * the sub-net broadcast address. */ else if (net_ipv4addr_broadcast(destipaddr, dev->d_netmask)) { /* Yes.. then we won't need to know the destination MAC address */ memcpy(peth->dest, g_broadcast_ethaddr.ether_addr_octet, ETHER_ADDR_LEN); goto finish_header; } else { /* Else, we use the destination IP address. */ net_ipv4addr_copy(ipaddr, destipaddr); } /* Check if we already have this destination address in the ARP table */ ret = arp_find(ipaddr, ðaddr); if (ret < 0) { ninfo("ARP request for IP %08lx\n", (unsigned long)ipaddr); /* The destination address was not in our ARP table, so we overwrite * the IP packet with an ARP request. */ arp_format(dev, ipaddr); arp_dump(ARPBUF); return; } /* Build an Ethernet header. */ memcpy(peth->dest, ethaddr.ether_addr_octet, ETHER_ADDR_LEN); /* Finish populating the Ethernet header */ finish_header: memcpy(peth->src, dev->d_mac.ether.ether_addr_octet, ETHER_ADDR_LEN); peth->type = HTONS(ETHTYPE_IP); dev->d_len += ETH_HDRLEN; }
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; }
FAR struct tcp_conn_s *tcp_alloc_accept(FAR struct net_driver_s *dev, FAR struct tcp_hdr_s *tcp) { FAR struct tcp_conn_s *conn; uint8_t domain; int ret; /* Get the appropriate IP domain */ #if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv4) bool ipv6 = IFF_IS_IPv6(dev->d_flags); domain = ipv6 ? PF_INET6 : PF_INET; #elif defined(CONFIG_NET_IPv4) domain = PF_INET; #else /* defined(CONFIG_NET_IPv6) */ domain = PF_INET6; #endif /* Allocate the connection structure */ conn = tcp_alloc(domain); if (conn) { /* Set up the local address (laddr) and the remote address (raddr) * that describes the TCP connection. */ #ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv4 if (ipv6) #endif { FAR struct ipv6_hdr_s *ip = IPv6BUF; /* Set the IPv6 specific MSS and the IPv6 locally bound address */ conn->mss = TCP_IPv6_INITIAL_MSS(dev); net_ipv6addr_copy(conn->u.ipv6.raddr, ip->srcipaddr); #ifdef CONFIG_NETDEV_MULTINIC net_ipv6addr_copy(conn->u.ipv6.laddr, ip->destipaddr); /* We now have to filter all outgoing transfers so that they use * only the MSS of this device. */ DEBUGASSERT(conn->dev == NULL || conn->dev == dev); conn->dev = dev; #endif /* Find the device that can receive packets on the network * associated with this local address. */ ret = tcp_remote_ipv6_device(conn); } #endif /* CONFIG_NET_IPv6 */ #ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv6 else #endif { FAR struct ipv4_hdr_s *ip = IPv4BUF; /* Set the IPv6 specific MSS and the IPv4 bound remote address. */ conn->mss = TCP_IPv4_INITIAL_MSS(dev); net_ipv4addr_copy(conn->u.ipv4.raddr, net_ip4addr_conv32(ip->srcipaddr)); #ifdef CONFIG_NETDEV_MULTINIC /* Set the local address as well */ net_ipv4addr_copy(conn->u.ipv4.laddr, net_ip4addr_conv32(ip->destipaddr)); /* We now have to filter all outgoing transfers so that they use * only the MSS of this device. */ DEBUGASSERT(conn->dev == NULL || conn->dev == dev); conn->dev = dev; #endif /* Find the device that can receive packets on the network * associated with this local address. */ ret = tcp_remote_ipv4_device(conn); } #endif /* CONFIG_NET_IPv4 */ /* Verify that a network device that can provide packets to this * local address was found. */ if (ret < 0) { /* If no device is found, then the address is not reachable. * That should be impossible in this context and we should * probably really just assert here. */ nerr("ERROR: Failed to find network device: %d\n", ret); tcp_free(conn); return NULL; } /* Fill in the necessary fields for the new connection. */ conn->rto = TCP_RTO; conn->timer = TCP_RTO; conn->sa = 0; conn->sv = 4; conn->nrtx = 0; conn->lport = tcp->destport; conn->rport = tcp->srcport; conn->tcpstateflags = TCP_SYN_RCVD; tcp_initsequence(conn->sndseq); conn->unacked = 1; #ifdef CONFIG_NET_TCP_WRITE_BUFFERS conn->expired = 0; conn->isn = 0; conn->sent = 0; conn->sndseq_max = 0; #endif /* rcvseq should be the seqno from the incoming packet + 1. */ memcpy(conn->rcvseq, tcp->seqno, 4); #ifdef CONFIG_NET_TCP_READAHEAD /* Initialize the list of TCP read-ahead buffers */ IOB_QINIT(&conn->readahead); #endif #ifdef CONFIG_NET_TCP_WRITE_BUFFERS /* Initialize the write buffer lists */ sq_init(&conn->write_q); sq_init(&conn->unacked_q); #endif /* And, finally, put the connection structure into the active list. * Interrupts should already be disabled in this context. */ dq_addlast(&conn->node, &g_active_tcp_connections); } return conn; }
void arp_arpin(FAR struct net_driver_s *dev) { FAR struct arp_hdr_s *parp = ARPBUF; in_addr_t ipaddr; if (dev->d_len < (sizeof(struct arp_hdr_s) + NET_LL_HDRLEN)) { nlldbg("Too small\n"); dev->d_len = 0; return; } dev->d_len = 0; ipaddr = net_ip4addr_conv32(parp->ah_dipaddr); switch(parp->ah_opcode) { case HTONS(ARP_REQUEST): nllvdbg("ARP request for IP %04lx\n", (long)ipaddr); /* ARP request. If it asked for our address, we send out a reply. */ if (net_ipaddr_cmp(ipaddr, dev->d_ipaddr)) { struct eth_hdr_s *peth = ETHBUF; /* First, we register the one who made the request in our ARP * table, since it is likely that we will do more communication * with this host in the future. */ arp_update(parp->ah_sipaddr, parp->ah_shwaddr); parp->ah_opcode = HTONS(ARP_REPLY); memcpy(parp->ah_dhwaddr, parp->ah_shwaddr, ETHER_ADDR_LEN); memcpy(parp->ah_shwaddr, dev->d_mac.ether_addr_octet, ETHER_ADDR_LEN); memcpy(peth->src, dev->d_mac.ether_addr_octet, ETHER_ADDR_LEN); memcpy(peth->dest, parp->ah_dhwaddr, ETHER_ADDR_LEN); parp->ah_dipaddr[0] = parp->ah_sipaddr[0]; parp->ah_dipaddr[1] = parp->ah_sipaddr[1]; net_ipaddr_hdrcopy(parp->ah_sipaddr, &dev->d_ipaddr); arp_dump(parp); peth->type = HTONS(ETHTYPE_ARP); dev->d_len = sizeof(struct arp_hdr_s) + NET_LL_HDRLEN; } break; case HTONS(ARP_REPLY): nllvdbg("ARP reply for IP %04lx\n", (long)ipaddr); /* ARP reply. We insert or update the ARP table if it was meant * for us. */ if (net_ipaddr_cmp(ipaddr, dev->d_ipaddr)) { /* Yes... Insert the address mapping in the ARP table */ arp_update(parp->ah_sipaddr, parp->ah_shwaddr); /* Then notify any logic waiting for the ARP result */ arp_notify(net_ip4addr_conv32(parp->ah_sipaddr)); } break; } }