static inline int tcp_ipv4_bind(FAR struct tcp_conn_s *conn, FAR const struct sockaddr_in *addr) { int port; int ret; /* Verify or select a local port and address */ net_lock(); /* Verify or select a local port (host byte order) */ #ifdef CONFIG_NETDEV_MULTINIC port = tcp_selectport(PF_INET, (FAR const union ip_addr_u *)&addr->sin_addr.s_addr, ntohs(addr->sin_port)); #else port = tcp_selectport(ntohs(addr->sin_port)); #endif if (port < 0) { nerr("ERROR: tcp_selectport failed: %d\n", port); return port; } /* Save the local address in the connection structure (network byte order). */ conn->lport = htons(port); #ifdef CONFIG_NETDEV_MULTINIC net_ipv4addr_copy(conn->u.ipv4.laddr, addr->sin_addr.s_addr); #endif /* Find the device that can receive packets on the network associated with * this local address. */ ret = tcp_local_ipv4_device(conn); if (ret < 0) { /* If no device is found, then the address is not reachable */ nerr("ERROR: tcp_local_ipv4_device failed: %d\n", ret); /* Back out the local address setting */ conn->lport = 0; #ifdef CONFIG_NETDEV_MULTINIC net_ipv4addr_copy(conn->u.ipv4.laddr, INADDR_ANY); #endif return ret; } net_unlock(); return OK; }
int localhost_initialize(void) { FAR struct lo_driver_s *priv; /* Get the interface structure associated with this interface number. */ priv = &g_loopback; /* Initialize the driver structure */ memset(priv, 0, sizeof(struct lo_driver_s)); priv->lo_dev.d_ifup = lo_ifup; /* I/F up (new IP address) callback */ priv->lo_dev.d_ifdown = lo_ifdown; /* I/F down callback */ priv->lo_dev.d_txavail = lo_txavail; /* New TX data callback */ #ifdef CONFIG_NET_IGMP priv->lo_dev.d_addmac = lo_addmac; /* Add multicast MAC address */ priv->lo_dev.d_rmmac = lo_rmmac; /* Remove multicast MAC address */ #endif #ifdef CONFIG_NET_MULTIBUFFER priv->lo_dev.d_buf = g_iobuffer; /* Attach the IO buffer */ #endif priv->lo_dev.d_private = (FAR void *)priv; /* Used to recover private state from dev */ /* Create a watchdog for timing polling for and timing of transmissions */ priv->lo_polldog = wd_create(); /* Create periodic poll timer */ /* Register the loopabck device with the OS so that socket IOCTLs can b * performed. */ (void)netdev_register(&priv->lo_dev, NET_LL_LOOPBACK); /* Set the local loopback IP address */ #ifdef CONFIG_NET_IPv4 net_ipv4addr_copy(priv->lo_dev.d_ipaddr, g_lo_ipv4addr); net_ipv4addr_copy(priv->lo_dev.d_draddr, g_lo_ipv4addr); net_ipv4addr_copy(priv->lo_dev.d_netmask, g_lo_ipv4mask); #endif #ifdef CONFIG_NET_IPv6 net_ipv6addr_copy(priv->lo_dev.d_ipv6addr, g_lo_ipv6addr); net_ipv6addr_copy(priv->lo_dev.d_ipv6draddr, g_lo_ipv6addr); net_ipv6addr_copy(priv->lo_dev.d_ipv6netmask, g_ipv6_alloneaddr); #endif /* Put the network in the UP state */ priv->lo_dev.d_flags = IFF_UP; return lo_ifup(&priv->lo_dev); }
int net_delroute(in_addr_t target, in_addr_t netmask) { struct route_match_s match; /* Set up the comparison structure */ match.prev = NULL; net_ipv4addr_copy(match.target, target); net_ipv4addr_copy(match.netmask, netmask); /* Then remove the entry from the routing table */ return net_foreachroute(net_match, &match) ? OK : -ENOENT; }
void smtp_configure(FAR void *handle, FAR const char *lhostname, FAR const in_addr_t *paddr) { FAR struct smtp_state *psmtp = (FAR struct smtp_state *)handle; psmtp->localhostname = lhostname; net_ipv4addr_copy(psmtp->smtpserver, paddr); }
ssize_t psock_udp_send(FAR struct socket *psock, FAR const void *buf, size_t len) { FAR struct udp_conn_s *conn; union { struct sockaddr addr; #ifdef CONFIG_NET_IPv4 struct sockaddr_in addr4; #endif #ifdef CONFIG_NET_IPv6 struct sockaddr_in6 addr6; #endif } to; socklen_t tolen; DEBUGASSERT(psock != NULL && psock->s_crefs > 0); DEBUGASSERT(psock->s_type != SOCK_DGRAM); conn = (FAR struct udp_conn_s *)psock->s_conn; DEBUGASSERT(conn); /* Was the UDP socket connected via connect()? */ if (!_SS_ISCONNECTED(psock->s_flags)) { /* No, then it is not legal to call send() with this socket. */ return -ENOTCONN; } /* Yes, then let psock_sendto to the work */ #ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv6 if (conn->domain == PF_INET) #endif { tolen = sizeof(struct sockaddr_in); to.addr4.sin_family = AF_INET; to.addr4.sin_port = conn->rport; net_ipv4addr_copy(to.addr4.sin_addr.s_addr, conn->u.ipv4.raddr); } #endif /* CONFIG_NET_IPv4 */ #ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv4 else #endif { tolen = sizeof(struct sockaddr_in6); to.addr6.sin6_family = AF_INET6; to.addr6.sin6_port = conn->rport; net_ipv6addr_copy(to.addr6.sin6_addr.s6_addr, conn->u.ipv6.raddr); } #endif /* CONFIG_NET_IPv6 */ return psock_udp_sendto(psock, buf, len, 0, &to.addr, tolen); }
FAR struct igmp_group_s *igmp_grpalloc(FAR struct net_driver_s *dev, FAR const in_addr_t *addr) { FAR struct igmp_group_s *group; net_lock_t flags; nllvdbg("addr: %08x dev: %p\n", *addr, dev); if (up_interrupt_context()) { #if CONFIG_PREALLOC_IGMPGROUPS > 0 grplldbg("Use a pre-allocated group entry\n"); group = igmp_grpprealloc(); #else grplldbg("Cannot allocate from interrupt handler\n"); group = NULL; #endif } else { grplldbg("Allocate from the heap\n"); group = igmp_grpheapalloc(); } grplldbg("group: %p\n", group); /* Check if we successfully allocated a group structure */ if (group) { /* Initialize the non-zero elements of the group structure */ net_ipv4addr_copy(group->grpaddr, *addr); sem_init(&group->sem, 0, 0); /* Initialize the group timer (but don't start it yet) */ group->wdog = wd_create(); DEBUGASSERT(group->wdog); /* Interrupts must be disabled in order to modify the group list */ flags = net_lock(); /* Add the group structure to the list in the device structure */ sq_addfirst((FAR sq_entry_t *)group, &dev->grplist); net_unlock(flags); } return group; }
static inline void accept_tcpsender(FAR struct socket *psock, FAR struct tcp_conn_s *conn, FAR struct sockaddr *addr, socklen_t *addrlen) { if (addr) { /* If an address is provided, then the length must also be provided. */ DEBUGASSERT(addrlen); #ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv6 /* If both IPv4 and IPv6 support are enabled, then we will need to * select which one to use when obtaining the sender's IP address. */ if (psock->s_domain == PF_INET) #endif /* CONFIG_NET_IPv6 */ { FAR struct sockaddr_in *inaddr = (FAR struct sockaddr_in *)addr; inaddr->sin_family = AF_INET; inaddr->sin_port = conn->rport; net_ipv4addr_copy(inaddr->sin_addr.s_addr, conn->u.ipv4.raddr); *addrlen = sizeof(struct sockaddr_in); } #endif /* CONFIG_NET_IPv4 */ #ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv4 /* Otherwise, this the IPv6 address is needed */ else #endif /* CONFIG_NET_IPv4 */ { FAR struct sockaddr_in6 *inaddr = (FAR struct sockaddr_in6 *)addr; DEBUGASSERT(psock->s_domain == PF_INET6); inaddr->sin6_family = AF_INET6; inaddr->sin6_port = conn->rport; net_ipv6addr_copy(inaddr->sin6_addr.s6_addr, conn->u.ipv6.raddr); *addrlen = sizeof(struct sockaddr_in6); } #endif /* CONFIG_NET_IPv6 */ } }
int arp_send(in_addr_t ipaddr) { FAR struct net_driver_s *dev; struct arp_notify_s notify; struct timespec delay; struct arp_send_s state; int ret; /* First check if destination is a local broadcast. */ if (ipaddr == INADDR_BROADCAST) { /* We don't need to send the ARP request */ return OK; } #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 (NTOHL(ipaddr) >= 0xe0000000 && NTOHL(ipaddr) <= 0xefffffff) { /* We don't need to send the ARP request */ return OK; } #endif /* Get the device that can route this request */ dev = netdev_findby_ipv4addr(INADDR_ANY, ipaddr); if (!dev) { nerr("ERROR: Unreachable: %08lx\n", (unsigned long)ipaddr); ret = -EHOSTUNREACH; goto errout; } /* ARP support is only built if the Ethernet data link is supported. * Continue and send the ARP request only if this device uses the * Ethernet data link protocol. */ if (dev->d_lltype != NET_LL_ETHERNET) { return OK; } /* Check if the destination address is on the local network. */ if (!net_ipv4addr_maskcmp(ipaddr, dev->d_ipaddr, dev->d_netmask)) { in_addr_t dripaddr; /* 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, ipaddr, &dripaddr); #else /* Use the device's default router IP address instead of the * destination address when determining the MAC address. */ net_ipv4addr_copy(dripaddr, dev->d_draddr); #endif ipaddr = dripaddr; } /* The destination address is on the local network. Check if it is * the sub-net broadcast address. */ else if (net_ipv4addr_broadcast(ipaddr, dev->d_netmask)) { /* Yes.. We don't need to send the ARP request */ return OK; } /* Allocate resources to receive a callback. This and the following * initialization is performed with the network lock because we don't * want anything to happen until we are ready. */ net_lock(); state.snd_cb = arp_callback_alloc(dev); if (!state.snd_cb) { nerr("ERROR: Failed to allocate a callback\n"); ret = -ENOMEM; goto errout_with_lock; } /* This semaphore is used for signaling and, hence, should not have * priority inheritance enabled. */ (void)nxsem_init(&state.snd_sem, 0, 0); /* Doesn't really fail */ nxsem_setprotocol(&state.snd_sem, SEM_PRIO_NONE); state.snd_retries = 0; /* No retries yet */ state.snd_ipaddr = ipaddr; /* IP address to query */ /* Remember the routing device name */ strncpy((FAR char *)state.snd_ifname, (FAR const char *)dev->d_ifname, IFNAMSIZ); /* Now loop, testing if the address mapping is in the ARP table and re- * sending the ARP request if it is not. */ ret = -ETIMEDOUT; /* Assume a timeout failure */ while (state.snd_retries < CONFIG_ARP_SEND_MAXTRIES) { /* Check if the address mapping is present in the ARP table. This * is only really meaningful on the first time through the loop. * * NOTE: If the ARP table is large than this could be a performance * issue. */ if (arp_find(ipaddr, NULL) >= 0) { /* We have it! Break out with success */ ret = OK; break; } /* Set up the ARP response wait BEFORE we send the ARP request */ arp_wait_setup(ipaddr, ¬ify); /* Arm/re-arm the callback */ state.snd_sent = false; state.snd_result = -EBUSY; state.snd_cb->flags = (ARP_POLL | NETDEV_DOWN); state.snd_cb->priv = (FAR void *)&state; state.snd_cb->event = arp_send_eventhandler; /* Notify the device driver that new TX data is available. * NOTES: This is in essence what netdev_ipv4_txnotify() does, which * is not possible to call since it expects a in_addr_t as * its single argument to lookup the network interface. */ if (dev->d_txavail) { dev->d_txavail(dev); } /* Wait for the send to complete or an error to occur. * net_lockedwait will also terminate if a signal is received. */ do { (void)net_lockedwait(&state.snd_sem); } while (!state.snd_sent); /* Check the result of the send operation */ ret = state.snd_result; if (ret < 0) { /* Break out on a send failure */ nerr("ERROR: Send failed: %d\n", ret); break; } /* Now wait for response to the ARP response to be received. The * optimal delay would be the work case round trip time. * NOTE: The network is locked. */ delay.tv_sec = CONFIG_ARP_SEND_DELAYSEC; delay.tv_nsec = CONFIG_ARP_SEND_DELAYNSEC; ret = arp_wait(¬ify, &delay); /* arp_wait will return OK if and only if the matching ARP response * is received. Otherwise, it will return -ETIMEDOUT. */ if (ret >= OK) { /* Break out if arp_wait() fails */ break; } /* Increment the retry count */ state.snd_retries++; nerr("ERROR: arp_wait failed: %d\n", ret); } nxsem_destroy(&state.snd_sem); arp_callback_free(dev, state.snd_cb); errout_with_lock: net_unlock(); errout: return ret; }
int net_delroute_ipv4(in_addr_t target, in_addr_t netmask) { struct route_match_ipv4_s match; struct net_route_ipv4_s route; struct file fshandle; off_t filesize; ssize_t nwritten; ssize_t nread; off_t pos; int nentries; int index; int ret; /* We must lock out other accesses to the routing table while we remove * entry */ ret = net_lockroute_ipv4(); if (ret < 0) { nerr("ERROR: net_lockroute_ipv4 failed: %d\n", ret); return ret; } /* Get the size of the routing table (in entries) */ nentries = net_routesize_ipv4(); if (nentries < 0) { ret = nentries; goto errout_with_lock; } else if (nentries == 0) { ret = -ENOENT; goto errout_with_lock; } /* Set up the comparison structure */ net_ipv4addr_copy(match.target, target); net_ipv4addr_copy(match.netmask, netmask); match.index = 0; /* Then find the index into the routing table where the match can be found */ ret = net_foreachroute_ipv4(net_match_ipv4, &match); if (ret < 0) { /* And error occurred */ goto errout_with_lock; } else if (ret == 0) { /* No match found */ ret = -ENOENT; goto errout_with_lock; } /* Open the routing table for read/write access */ ret = net_openroute_ipv4(O_RDWR, &fshandle); if (ret < 0) { nerr("ERROR: Could not open IPv4 routing table: %d\n", ret); goto errout_with_lock; } #ifdef CONFIG_ROUTE_IPv4_CACHEROUTE /* We are committed to modifying the routing table. Flush the in-memory * routing table cache. */ net_flushcache_ipv4(); #endif /* Loop, copying each entry, to the previous entry thus removing the entry * to be deleted. */ for (index = match.index + 1; index < nentries; index++) { /* Seek to the current entry to be moved */ pos = net_seekroute_ipv4(&fshandle, index); if (pos < 0) { nerr("ERROR: net_readroute_ipv4 failed: %ld\n", (long)pos); ret =(int)pos; goto errout_with_fshandle; } /* Read the routing table entry at this position */ nread = net_readroute_ipv4(&fshandle, &route); if (nread < 0) { nerr("ERROR: net_readroute_ipv4 failed: %ld\n", (long)nread); ret = (int)nread; goto errout_with_fshandle; } else if (nread == 0) { nerr("ERROR: Unexpected end of file\n"); ret = -EINVAL; goto errout_with_fshandle; } /* Seek to the previous entry to be replaced */ pos = net_seekroute_ipv4(&fshandle, index - 1); if (pos < 0) { nerr("ERROR: net_readroute_ipv4 failed: %ld\n", (long)pos); ret =(int)pos; goto errout_with_fshandle; } /* Now write the record to its new location */ nwritten = net_writeroute_ipv4(&fshandle, &route); if (nwritten < 0) { nerr("ERROR: net_readroute_ipv4 failed: %ld\n", (long)nwritten); ret = (int)nwritten; goto errout_with_fshandle; } } /* Now truncate the one duplicate entry at the end of the file. This may * result in a zero length file. */ filesize = (nentries - 1) * sizeof(struct net_route_ipv4_s); ret = file_truncate(&fshandle, filesize); errout_with_fshandle: (void)net_closeroute_ipv4(&fshandle); errout_with_lock: (void)net_unlockroute_ipv4(); return ret; }
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; }
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; }
int tcp_connect(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr) { int port; int ret; /* The connection is expected to be in the TCP_ALLOCATED state.. i.e., * allocated via up_tcpalloc(), but not yet put into the active connections * list. */ if (!conn || conn->tcpstateflags != TCP_ALLOCATED) { return -EISCONN; } /* If the TCP port has not already been bound to a local port, then select * one now. We assume that the IP address has been bound to a local device, * but the port may still be INPORT_ANY. */ net_lock(); #ifdef CONFIG_NETDEV_MULTINIC /* If there are multiple network devices, then we need to pass the local, * bound address. This is needed because port unique-ness is only for a * given network. * * This is complicated by the fact that the local address may be either an * IPv4 or an IPv6 address. */ #ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv6 if (conn->domain == PF_INET) #endif { /* Select a port that is unique for this IPv4 local address (host * order). */ port = tcp_selectport(PF_INET, (FAR const union ip_addr_u *)&conn->u.ipv4.laddr, ntohs(conn->lport)); } #endif /* CONFIG_NET_IPv4 */ #ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv4 else #endif { /* Select a port that is unique for this IPv6 local address (host * order). */ port = tcp_selectport(PF_INET6, (FAR const union ip_addr_u *)conn->u.ipv6.laddr, ntohs(conn->lport)); } #endif /* CONFIG_NET_IPv6 */ #else /* CONFIG_NETDEV_MULTINIC */ /* Select the next available port number. This is only one network device * so we do not have to bother with all of the IPv4/IPv6 local address * silliness. */ port = tcp_selectport(ntohs(conn->lport)); #endif /* CONFIG_NETDEV_MULTINIC */ /* Did we have a port assignment? */ if (port < 0) { ret = port; goto errout_with_lock; } /* Set up the local address (laddr) and the remote address (raddr) that * describes the TCP connection. */ #ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv6 if (conn->domain == PF_INET) #endif { FAR const struct sockaddr_in *inaddr = (FAR const struct sockaddr_in *)addr; /* Save MSS and the port from the sockaddr (already in network order) */ conn->mss = MIN_IPv4_TCP_INITIAL_MSS; conn->rport = inaddr->sin_port; /* The sockaddr address is 32-bits in network order. */ net_ipv4addr_copy(conn->u.ipv4.raddr, inaddr->sin_addr.s_addr); /* Find the device that can receive packets on the network associated * with this remote address. */ ret = tcp_remote_ipv4_device(conn); } #endif /* CONFIG_NET_IPv4 */ #ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv4 else #endif { FAR const struct sockaddr_in6 *inaddr = (FAR const struct sockaddr_in6 *)addr; /* Save MSS and the port from the sockaddr (already in network order) */ conn->mss = MIN_IPv6_TCP_INITIAL_MSS; conn->rport = inaddr->sin6_port; /* The sockaddr address is 128-bits in network order. */ net_ipv6addr_copy(conn->u.ipv6.raddr, inaddr->sin6_addr.s6_addr16); /* 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 */ /* 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); goto errout_with_lock; } /* Initialize and return the connection structure, bind it to the port * number. At this point, we do not know the size of the initial MSS We * know the total size of the packet buffer, but we don't yet know the * size of link layer header. */ conn->tcpstateflags = TCP_SYN_SENT; tcp_initsequence(conn->sndseq); conn->unacked = 1; /* TCP length of the SYN is one. */ conn->nrtx = 0; conn->timer = 1; /* Send the SYN next time around. */ conn->rto = TCP_RTO; conn->sa = 0; conn->sv = 16; /* Initial value of the RTT variance. */ conn->lport = htons((uint16_t)port); #ifdef CONFIG_NET_TCP_WRITE_BUFFERS conn->expired = 0; conn->isn = 0; conn->sent = 0; conn->sndseq_max = 0; #endif #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 TCP write buffer lists */ sq_init(&conn->write_q); sq_init(&conn->unacked_q); #endif /* And, finally, put the connection structure into the active list. */ dq_addlast(&conn->node, &g_active_tcp_connections); ret = OK; errout_with_lock: net_unlock(); return ret; }