static uint16_t ack_interrupt(FAR struct net_driver_s *dev, FAR void *pvconn, FAR void *pvpriv, uint16_t flags) { FAR struct sendfile_s *pstate = (FAR struct sendfile_s *)pvpriv; nllvdbg("flags: %04x\n", flags); if ((flags & TCP_ACKDATA) != 0) { #ifdef CONFIG_NET_SOCKOPTS /* Update the timeout */ pstate->snd_time = clock_systimer(); #endif /* The current acknowledgement number number is the (relative) offset * of the of the next byte needed by the receiver. The snd_isn is the * offset of the first byte to send to the receiver. The difference * is the number of bytes to be acknowledged. */ pstate->snd_acked = tcp_getsequence(TCPBUF->ackno) - pstate->snd_isn; nllvdbg("ACK: acked=%d sent=%d flen=%d\n", pstate->snd_acked, pstate->snd_sent, pstate->snd_flen); dev->d_sndlen = 0; flags &= ~TCP_ACKDATA; } else if ((flags & TCP_REXMIT) != 0) { nlldbg("REXMIT\n"); /* Yes.. in this case, reset the number of bytes that have been sent * to the number of bytes that have been ACKed. */ pstate->snd_sent = pstate->snd_acked; } /* Check for a loss of connection */ else if ((flags & (TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT)) != 0) { /* Report not connected */ nlldbg("Lost connection\n"); net_lostconnection(pstate->snd_sock, flags); pstate->snd_sent = -ENOTCONN; } /* Wake up the waiting thread */ sem_post(&pstate->snd_sem); return flags; }
int netdev_unregister(FAR struct uip_driver_s *dev) { struct uip_driver_s *prev; struct uip_driver_s *curr; if (dev) { netdev_semtake(); /* Find the device in the list of known network devices */ for (prev = NULL, curr = g_netdevices; curr && curr != dev; prev = curr, curr = curr->flink); /* Remove the device to the list of known network devices */ if (curr) { /* Where was the entry */ if (prev) { /* The entry was in the middle or at the end of the list */ prev->flink = curr->flink; } else { /* The entry was at the beginning of the list */ g_netdevices = curr; } curr->flink = NULL; } netdev_semgive(); #ifdef CONFIG_NET_ETHERNET nlldbg("Unregistered MAC: %02x:%02x:%02x:%02x:%02x:%02x as dev: %s\n", dev->d_mac.ether_addr_octet[0], dev->d_mac.ether_addr_octet[1], dev->d_mac.ether_addr_octet[2], dev->d_mac.ether_addr_octet[3], dev->d_mac.ether_addr_octet[4], dev->d_mac.ether_addr_octet[5], dev->d_ifname); #else nlldbg("Registered dev: %s\n", dev->d_ifname); #endif return OK; } return -EINVAL; }
static void *unsoliced_thread_func(void *parameter) { char buff[QUEUE_NAMELEN]; int status = 0; int nbytes = 0; int minor = 0; ioctl(spiconf.cc3000fd, CC3000IOC_GETQUESEMID, (unsigned long)&minor); snprintf(buff, QUEUE_NAMELEN, QUEUE_FORMAT, minor); spiconf.queue = mq_open(buff,O_RDONLY); DEBUGASSERT(spiconf.queue != (mqd_t) -1); DEBUGASSERT(SEM_NAMELEN == QUEUE_NAMELEN); snprintf(buff, SEM_NAMELEN, SEM_FORMAT, minor); spiconf.done = sem_open(buff,O_RDONLY); DEBUGASSERT(spiconf.done != (sem_t *)-1); sem_post(&spiconf.unsoliced_thread_wakesem); while (spiconf.run) { memset(&spiconf.rx_buffer,0,sizeof(spiconf.rx_buffer)); nbytes = mq_receive(spiconf.queue, &spiconf.rx_buffer, sizeof(spiconf.rx_buffer), 0); if (nbytes > 0) { nlldbg("%d Processed\n",nbytes); spiconf.pfRxHandler(spiconf.rx_buffer.pbuffer); } } mq_close(spiconf.queue); sem_close(spiconf.done); pthread_exit((pthread_addr_t)status); return (pthread_addr_t)status; }
void pkt_poll(FAR struct net_driver_s *dev, FAR struct pkt_conn_s *conn) { nlldbg("IN\n"); /* Verify that the packet connection is valid */ if (conn) { /* Setup for the application callback */ dev->d_appdata = &dev->d_buf[NET_LL_HDRLEN + IPUDP_HDRLEN]; dev->d_snddata = &dev->d_buf[NET_LL_HDRLEN + IPUDP_HDRLEN]; dev->d_len = 0; dev->d_sndlen = 0; /* Perform the application callback */ (void)pkt_callback(dev, conn, PKT_POLL); /* If the application has data to send, setup the UDP/IP header */ if (dev->d_sndlen > 0) { // devif_pkt_send(dev, conn); return; } } /* Make sure that d_len is zero meaning that there is nothing to be sent */ dev->d_len = 0; }
uint16_t tcp_datahandler(FAR struct tcp_conn_s *conn, FAR uint8_t *buffer, uint16_t buflen) { FAR struct iob_s *iob; int ret; /* Try to allocate on I/O buffer to start the chain without waiting (and * throttling as necessary). If we would have to wait, then drop the * packet. */ iob = iob_tryalloc(true); if (iob == NULL) { nlldbg("ERROR: Failed to create new I/O buffer chain\n"); return 0; } /* Copy the new appdata into the I/O buffer chain (without waiting) */ ret = iob_trycopyin(iob, buffer, buflen, 0, true); if (ret < 0) { /* On a failure, iob_copyin return a negated error value but does * not free any I/O buffers. */ nlldbg("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 (again * without waiting). */ ret = iob_tryadd_queue(iob, &conn->readahead); if (ret < 0) { nlldbg("ERROR: Failed to queue the I/O buffer chain: %d\n", ret); (void)iob_free_chain(iob); return 0; } nllvdbg("Buffered %d bytes\n", buflen); return buflen; }
void ftpc_timeout(int argc, uint32_t arg1, ...) { FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)arg1; nlldbg("Timeout!\n"); DEBUGASSERT(argc == 1 && session); kill(session->pid, CONFIG_FTP_SIGNAL); }
void arp_dump(FAR struct arp_hdr_s *arp) { nlldbg(" HW type: %04x Protocol: %04x\n", arp->ah_hwtype, arp->ah_protocol); nlldbg(" HW len: %02x Proto len: %02x Operation: %04x\n", arp->ah_hwlen, arp->ah_protolen, arp->ah_opcode); nlldbg(" Sender MAC: %02x:%02x:%02x:%02x:%02x:%02x IP: %d.%d.%d.%d\n", arp->ah_shwaddr[0], arp->ah_shwaddr[1], arp->ah_shwaddr[2], arp->ah_shwaddr[3], arp->ah_shwaddr[4], arp->ah_shwaddr[5], arp->ah_sipaddr[0] & 0xff, arp->ah_sipaddr[0] >> 8, arp->ah_sipaddr[1] & 0xff, arp->ah_sipaddr[1] >> 8); nlldbg(" Dest MAC: %02x:%02x:%02x:%02x:%02x:%02x IP: %d.%d.%d.%d\n", arp->ah_dhwaddr[0], arp->ah_dhwaddr[1], arp->ah_dhwaddr[2], arp->ah_dhwaddr[3], arp->ah_dhwaddr[4], arp->ah_dhwaddr[5], arp->ah_dipaddr[0] & 0xff, arp->ah_dipaddr[0] >> 8, arp->ah_dipaddr[1] & 0xff, arp->ah_dipaddr[1] >> 8); }
int uip_backlogdelete(FAR struct uip_conn *conn, FAR struct uip_conn *blconn) { FAR struct uip_backlog_s *bls; FAR struct uip_blcontainer_s *blc; FAR struct uip_blcontainer_s *prev; nllvdbg("conn=%p blconn=%p\n", conn, blconn); #ifdef CONFIG_DEBUG if (!conn) { return -EINVAL; } #endif bls = conn->backlog; if (bls) { /* Find the container hold the connection */ for (blc = (FAR struct uip_blcontainer_s *)sq_peek(&bls->bl_pending), prev = NULL; blc; prev = blc, blc = (FAR struct uip_blcontainer_s *)sq_next(&blc->bc_node)) { if (blc->bc_conn == blconn) { if (prev) { /* Remove the a container from the middle of the list of * pending connections */ (void)sq_remafter(&prev->bc_node, &bls->bl_pending); } else { /* Remove the a container from the head of the list of * pending connections */ (void)sq_remfirst(&bls->bl_pending); } /* Put container in the free list */ blc->bc_conn = NULL; sq_addlast(&blc->bc_node, &bls->bl_free); return OK; } } nlldbg("Failed to find pending connection\n"); return -EINVAL; } return OK; }
void up_netinitialize(void) { FAR struct spi_dev_s *spi; uint16_t reg16; int ret; /* Get the SPI port */ spi = up_spiinitialize(ENC28J60_SPI_PORTNO); if (!spi) { nlldbg("Failed to initialize SPI port %d\n", ENC28J60_SPI_PORTNO); return; } /* Configure the XTI for the ENC28J60 interrupt. */ ret = str71x_xticonfig(ENC28J60_IRQ, false); if (ret < 0) { nlldbg("Failed configure interrupt for IRQ %d: %d\n", ENC28J60_IRQ, ret); return; } /* Take ENC28J60 out of reset (active low)*/ reg16 = getreg16(STR71X_GPIO0_PD); reg16 &= ~ENC_GPIO0_NETRST; putreg16(reg16, STR71X_GPIO0_PD); /* Bind the SPI port to the ENC28J60 driver */ ret = enc_initialize(spi, ENC28J60_DEVNO, ENC28J60_IRQ); if (ret < 0) { nlldbg("Failed to bind SPI port %d ENC28J60 device %d: %d\n", ENC28J60_SPI_PORTNO, ENC28J60_DEVNO, ret); return; } nllvdbg("Bound SPI port %d to ENC28J60 device %d\n", ENC28J60_SPI_PORTNO, ENC28J60_DEVNO); }
int usrsock_setsockopt(FAR struct usrsock_conn_s *conn, int level, int option, FAR const void *value, FAR socklen_t value_len) { struct usrsock_reqstate_s state = {}; net_lock_t save; ssize_t ret; DEBUGASSERT(conn); save = net_lock(); if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED || conn->state == USRSOCK_CONN_STATE_ABORTED) { /* Invalid state or closed by daemon. */ nlldbg("usockid=%d; connect() with uninitialized usrsock.\n", conn->usockid); ret = (conn->state == USRSOCK_CONN_STATE_ABORTED) ? -EPIPE : -ECONNRESET; goto errout_unlock; } /* Set up event callback for usrsock. */ ret = usrsock_setup_request_callback(conn, &state, setsockopt_event, USRSOCK_EVENT_ABORT | USRSOCK_EVENT_REQ_COMPLETE); if (ret < 0) { ndbg("usrsock_setup_request_callback failed: %d\n", ret); goto errout_unlock; } /* Request user-space daemon to close socket. */ ret = do_setsockopt_request(conn, level, option, value, value_len); if (ret >= 0) { /* Wait for completion of request. */ while (net_lockedwait(&state.recvsem) != OK) { DEBUGASSERT(*get_errno_ptr() == EINTR); } ret = state.result; } usrsock_teardown_request_callback(&state); errout_unlock: net_unlock(save); return ret; }
static uint32_t arp_send_interrupt(FAR struct net_driver_s *dev, FAR void *pvconn, FAR void *priv, uint32_t flags) { FAR struct arp_send_s *state = (FAR struct arp_send_s *)priv; nllvdbg("flags: %04x sent: %d\n", flags, state->snd_sent); if (state) { /* Check if the network is still up */ if ((flags & NETDEV_DOWN) != 0) { nlldbg("ERROR: Interface is down\n"); arp_send_terminate(state, -ENETUNREACH); return flags; } /* Check if the outgoing packet is available. It may have been claimed * by a send interrupt serving a different thread -OR- if the output * buffer currently contains unprocessed incoming data. In these cases * we will just have to wait for the next polling cycle. */ if (dev->d_sndlen > 0 || (flags & PKT_NEWDATA) != 0) { /* Another thread has beat us sending data or the buffer is busy, * Check for a timeout. If not timed out, wait for the next * polling cycle and check again. */ /* REVISIT: No timeout. Just wait for the next polling cycle */ return flags; } /* It looks like we are good to send the data */ /* Copy the packet data into the device packet buffer and send it */ arp_format(dev, state->snd_ipaddr); /* Make sure no ARP request overwrites this ARP request. This * flag will be cleared in arp_out(). */ IFF_SET_NOARP(dev->d_flags); /* Don't allow any further call backs. */ arp_send_terminate(state, OK); } return flags; }
static void telnetd_sendopt(FAR struct telnetd_dev_s *priv, uint8_t option, uint8_t value) { uint8_t optbuf[4]; optbuf[0] = TELNET_IAC; optbuf[1] = option; optbuf[2] = value; optbuf[3] = 0; telnetd_dumpbuffer("Send optbuf", optbuf, 4); if (send(priv->td_psock, optbuf, 4, 0) < 0) { nlldbg("Failed to send TELNET_IAC\n"); } }
struct uip_neighbor_addr *uip_neighbor_lookup(uip_ipaddr_t ipaddr) { struct neighbor_entry *e; e = find_entry(ipaddr); if (e != NULL) { nlldbg("Lookup neighbor: %02x:%02x:%02x:%02x:%02x:%02x\n", e->addr.addr.ether_addr_octet[0], e->addr.addr.ether_addr_octet[1], e->addr.addr.ether_addr_octet[2], e->addr.addr.ether_addr_octet[3], e->addr.addr.ether_addr_octet[4], e->addr.addr.ether_addr_octet[5]); return &e->addr; } return NULL; }
void uip_neighbor_add(uip_ipaddr_t ipaddr, struct uip_neighbor_addr *addr) { uint8_t oldest_time; int oldest; int i; nlldbg("Add neighbor: %02x:%02x:%02x:%02x:%02x:%02x\n", addr->addr.ether_addr_octet[0], addr->addr.ether_addr_octet[1], addr->addr.ether_addr_octet[2], addr->addr.ether_addr_octet[3], addr->addr.ether_addr_octet[4], addr->addr.ether_addr_octet[5]); /* Find the first unused entry or the oldest used entry. */ oldest_time = 0; oldest = 0; for (i = 0; i < ENTRIES; ++i) { if (entries[i].time == MAX_TIME) { oldest = i; break; } if (uip_ipaddr_cmp(entries[i].ipaddr, addr)) { oldest = i; break; } if (entries[i].time > oldest_time) { oldest = i; oldest_time = entries[i].time; } } /* Use the oldest or first free entry (either pointed to by the * "oldest" variable). */ entries[oldest].time = 0; uip_ipaddr_copy(entries[oldest].ipaddr, ipaddr); memcpy(&entries[oldest].addr, addr, sizeof(struct uip_neighbor_addr)); }
int pkt_input(struct net_driver_s *dev) { FAR struct pkt_conn_s *conn; FAR struct eth_hdr_s *pbuf = (struct eth_hdr_s *)dev->d_buf; int ret = OK; conn = pkt_active(pbuf); if (conn) { uint16_t flags; /* Setup for the application callback */ dev->d_appdata = dev->d_buf; dev->d_sndlen = 0; /* Perform the application callback */ flags = pkt_callback(dev, conn, PKT_NEWDATA); /* If the operation was successful, the PKT_NEWDATA flag is removed * and thus the packet can be deleted (OK will be returned). */ if ((flags & PKT_NEWDATA) != 0) { /* No.. the packet was not processed now. Return ERROR so * that the driver may retry again later. */ ret = ERROR; } } else { nlldbg("No listener\n"); } return ret; }
int uip_backlogadd(FAR struct uip_conn *conn, FAR struct uip_conn *blconn) { FAR struct uip_backlog_s *bls; FAR struct uip_blcontainer_s *blc; int ret = -EINVAL; nllvdbg("conn=%p blconn=%p\n", conn, blconn); #ifdef CONFIG_DEBUG if (!conn) { return -EINVAL; } #endif bls = conn->backlog; if (bls && blconn) { /* Allocate a container for the connection from the free list */ blc = (FAR struct uip_blcontainer_s *)sq_remfirst(&bls->bl_free); if (!blc) { nlldbg("Failed to allocate container\n"); ret = -ENOMEM; } else { /* Save the connection reference in the container and put the * container at the end of the pending connection list (FIFO). */ blc->bc_conn = blconn; sq_addlast(&blc->bc_node, &bls->bl_pending); ret = OK; } } return ret; }
void lm3s_ethernetmac(struct ether_addr *ethaddr) { uint32_t user0; uint32_t user1; /* Get the current value of the user registers */ user0 = getreg32(LM3S_FLASH_USERREG0); user1 = getreg32(LM3S_FLASH_USERREG1); nlldbg("user: %06x:%06x\n", user1 & 0x00ffffff, user0 & 0x00ffffff); DEBUGASSERT(user0 != 0xffffffff && user1 != 0xffffffff); /* Re-format that MAC address the way that uIP expects to see it */ ethaddr->ether_addr_octet[0] = ((user0 >> 0) & 0xff); ethaddr->ether_addr_octet[1] = ((user0 >> 8) & 0xff); ethaddr->ether_addr_octet[2] = ((user0 >> 16) & 0xff); ethaddr->ether_addr_octet[3] = ((user1 >> 0) & 0xff); ethaddr->ether_addr_octet[4] = ((user1 >> 8) & 0xff); ethaddr->ether_addr_octet[5] = ((user1 >> 16) & 0xff); }
FAR struct uip_callback_s *uip_callbackalloc(FAR struct uip_callback_s **list) { struct uip_callback_s *ret; uip_lock_t save; /* Check the head of the free list */ save = uip_lock(); ret = g_cbfreelist; if (ret) { /* Remove the next instance from the head of the free list */ g_cbfreelist = ret->flink; memset(ret, 0, sizeof(struct uip_callback_s)); /* Add the newly allocated instance to the head of the specified list */ if (list) { ret->flink = *list; *list = ret; } else { ret->flink = NULL; } } #ifdef CONFIG_DEBUG else { nlldbg("Failed to allocate callback\n"); } #endif uip_unlock(save); return ret; }
struct uip_conn *uip_tcpalloc(void) { struct uip_conn *conn; uip_lock_t flags; /* Because this routine is called from both interrupt level and * and from user level, we have not option but to disable interrupts * while accessing g_free_tcp_connections[]; */ flags = uip_lock(); /* Return the entry from the head of the free list */ conn = (struct uip_conn *)dq_remfirst(&g_free_tcp_connections); /* Is the free list empty? */ if (!conn) { /* As a fallback, check for connection structures which are not * established yet. * * Search the active connection list for the oldest connection * that is not in the UIP_ESTABLISHED state. */ struct uip_conn *tmp = g_active_tcp_connections.head; while (tmp) { nllvdbg("conn: %p state: %02x\n", tmp, tmp->tcpstateflags); /* Is this connection in some state other than UIP_ESTABLISHED * state? */ if (tmp->tcpstateflags != UIP_ESTABLISHED) { /* Yes.. Is it the oldest one we have seen so far? */ if (!conn || tmp->timer > conn->timer) { /* Yes.. remember it */ conn = tmp; } } /* Look at the next active connection */ tmp = tmp->node.flink; } /* Did we find a connection that we can re-use? */ if (conn != NULL) { nlldbg("Closing unestablished connection: %p\n", conn); /* Yes... free it. This will remove the connection from the list * of active connections and release all resources held by the * connection. * * REVISIT: Could there be any higher level, socket interface * that needs to be informed that we did this to them? */ uip_tcpfree(conn); /* Now there is guaranteed to be one free connection. Get it! */ conn = (struct uip_conn *)dq_remfirst(&g_free_tcp_connections); } } uip_unlock(flags); /* Mark the connection allocated */ if (conn) { memset(conn, 0, sizeof(struct uip_conn)); conn->tcpstateflags = UIP_ALLOCATED; } return conn; }
static uint16_t sendto_interrupt(struct uip_driver_s *dev, void *conn, void *pvpriv, uint16_t flags) { FAR struct sendto_s *pstate = (FAR struct sendto_s *)pvpriv; nllvdbg("flags: %04x\n", flags); if (pstate) { /* Check if the outgoing packet is available. It may have been claimed * by a sendto interrupt serving a different thread -OR- if the output * buffer currently contains unprocessed incoming data. In these cases * we will just have to wait for the next polling cycle. */ if (dev->d_sndlen > 0 || (flags & UIP_NEWDATA) != 0) { /* Another thread has beat us sending data or the buffer is busy, * Check for a timeout. If not timed out, wait for the next * polling cycle and check again. */ #ifdef CONFIG_NET_SENDTO_TIMEOUT if (send_timeout(pstate)) { /* Yes.. report the timeout */ nlldbg("SEND timeout\n"); pstate->st_sndlen = -ETIMEDOUT; } else #endif /* CONFIG_NET_SENDTO_TIMEOUT */ { /* No timeout. Just wait for the next polling cycle */ return flags; } } /* It looks like we are good to send the data */ else { /* Copy the user data into d_snddata and send it */ uip_send(dev, pstate->st_buffer, pstate->st_buflen); pstate->st_sndlen = pstate->st_buflen; } /* Don't allow any further call backs. */ pstate->st_cb->flags = 0; pstate->st_cb->priv = NULL; pstate->st_cb->event = NULL; /* Wake up the waiting thread */ sem_post(&pstate->st_sem); } return flags; }
int uip_ping(uip_ipaddr_t addr, uint16_t id, uint16_t seqno, uint16_t datalen, int dsecs) { struct icmp_ping_s state; uip_lock_t save; /* Initialize the state structure */ sem_init(&state.png_sem, 0, 0); state.png_ticks = DSEC2TICK(dsecs); /* System ticks to wait */ state.png_result = -ENOMEM; /* Assume allocation failure */ state.png_addr = addr; /* Address of the peer to be ping'ed */ state.png_id = id; /* The ID to use in the ECHO request */ state.png_seqno = seqno; /* The seqno to use int the ECHO request */ state.png_datlen = datalen; /* The length of data to send in the ECHO request */ state.png_sent = false; /* ECHO request not yet sent */ save = uip_lock(); state.png_time = clock_systimer(); /* Set up the callback */ state.png_cb = uip_icmpcallbackalloc(); if (state.png_cb) { state.png_cb->flags = UIP_POLL|UIP_ECHOREPLY; state.png_cb->priv = (void*)&state; state.png_cb->event = ping_interrupt; state.png_result = -EINTR; /* Assume sem-wait interrupted by signal */ /* Notify the device driver of the availaibilty of TX data */ netdev_txnotify(&state.png_addr); /* Wait for either the full round trip transfer to complete or * for timeout to occur. (1) uip_lockedwait will also terminate if a * signal is received, (2) interrupts may be disabled! They will * be re-enabled while the task sleeps and automatically * re-enabled when the task restarts. */ nlldbg("Start time: 0x%08x seqno: %d\n", state.png_time, seqno); uip_lockedwait(&state.png_sem); uip_icmpcallbackfree(state.png_cb); } uip_unlock(save); /* Return the negated error number in the event of a failure, or the * sequence number of the ECHO reply on success. */ if (!state.png_result) { nlldbg("Return seqno=%d\n", state.png_seqno); return (int)state.png_seqno; } else { nlldbg("Return error=%d\n", -state.png_result); return state.png_result; } }
static uint16_t ping_interrupt(struct uip_driver_s *dev, void *conn, void *pvpriv, uint16_t flags) { struct icmp_ping_s *pstate = (struct icmp_ping_s *)pvpriv; uint8_t *ptr; int failcode = -ETIMEDOUT; int i; nllvdbg("flags: %04x\n", flags); if (pstate) { /* Check if this device is on the same network as the destination device. */ if (!uip_ipaddr_maskcmp(pstate->png_addr, dev->d_ipaddr, dev->d_netmask)) { /* Destination address was not on the local network served by this * device. If a timeout occurs, then the most likely reason is * that the destination address is not reachable. */ nllvdbg("Not reachable\n"); failcode = -ENETUNREACH; } else { /* Check if this is a ICMP ECHO reply. If so, return the sequence * number to the caller. NOTE: We may not even have sent the * requested ECHO request; this could have been the delayed ECHO * response from a previous ping. */ if ((flags & UIP_ECHOREPLY) != 0 && conn != NULL) { struct uip_icmpip_hdr *icmp = (struct uip_icmpip_hdr *)conn; nlldbg("ECHO reply: id=%d seqno=%d\n", ntohs(icmp->id), ntohs(icmp->seqno)); if (ntohs(icmp->id) == pstate->png_id) { /* Consume the ECHOREPLY */ flags &= ~UIP_ECHOREPLY; dev->d_len = 0; /* Return the result to the caller */ pstate->png_result = OK; pstate->png_seqno = ntohs(icmp->seqno); goto end_wait; } } /* Check: * If the outgoing packet is available (it may have been claimed * by a sendto interrupt serving a different thread * -OR- * If the output buffer currently contains unprocessed incoming * data. * -OR- * If we have alread sent the ECHO request * * In the first two cases, we will just have to wait for the next * polling cycle. */ if (dev->d_sndlen <= 0 && /* Packet available */ (flags & UIP_NEWDATA) == 0 && /* No incoming data */ !pstate->png_sent) /* Request not sent */ { struct uip_icmpip_hdr *picmp = ICMPBUF; /* We can send the ECHO request now. * * Format the ICMP ECHO request packet */ picmp->type = ICMP_ECHO_REQUEST; picmp->icode = 0; #ifndef CONFIG_NET_IPv6 picmp->id = htons(pstate->png_id); picmp->seqno = htons(pstate->png_seqno); #else # error "IPv6 ECHO Request not implemented" #endif /* Add some easily verifiable data */ for (i = 0, ptr = ICMPDAT; i < pstate->png_datlen; i++) { *ptr++ = i; } /* Send the ICMP echo request. Note that d_sndlen is set to * the size of the ICMP payload and does not include the size * of the ICMP header. */ nlldbg("Send ECHO request: seqno=%d\n", pstate->png_seqno); dev->d_sndlen= pstate->png_datlen + 4; uip_icmpsend(dev, &pstate->png_addr); pstate->png_sent = true; return flags; } } /* Check if the selected timeout has elapsed */ if (ping_timeout(pstate)) { /* Yes.. report the timeout */ nlldbg("Ping timeout\n"); pstate->png_result = failcode; goto end_wait; } /* Continue waiting */ } return flags; end_wait: nllvdbg("Resuming\n"); /* Do not allow any further callbacks */ pstate->png_cb->flags = 0; pstate->png_cb->priv = NULL; pstate->png_cb->event = NULL; /* Wake up the waiting thread */ sem_post(&pstate->png_sem); return flags; }
static uint16_t tcpsend_interrupt(FAR struct net_driver_s *dev, FAR void *pvconn, FAR void *pvpriv, uint16_t flags) { FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pvconn; FAR struct send_s *pstate = (FAR struct send_s *)pvpriv; #ifdef CONFIG_NETDEV_MULTINIC /* The TCP socket is connected and, hence, should be bound to a device. * Make sure that the polling device is the one that we are bound to. */ DEBUGASSERT(conn->dev != NULL); if (dev != conn->dev) { return flags; } #endif nllvdbg("flags: %04x acked: %d sent: %d\n", flags, pstate->snd_acked, pstate->snd_sent); /* If this packet contains an acknowledgement, then update the count of * acknowledged bytes. */ if ((flags & TCP_ACKDATA) != 0) { FAR struct tcp_hdr_s *tcp; /* Update the timeout */ #ifdef CONFIG_NET_SOCKOPTS pstate->snd_time = clock_systimer(); #endif /* Get the offset address of the TCP header */ #ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv6 if (conn->domain == PF_INET) #endif { DEBUGASSERT(IFF_IS_IPv4(dev->d_flags)); tcp = TCPIPv4BUF; } #endif /* CONFIG_NET_IPv4 */ #ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv4 else #endif { DEBUGASSERT(IFF_IS_IPv6(dev->d_flags)); tcp = TCPIPv6BUF; } #endif /* CONFIG_NET_IPv6 */ /* The current acknowledgement number number is the (relative) offset * of the of the next byte needed by the receiver. The snd_isn is the * offset of the first byte to send to the receiver. The difference * is the number of bytes to be acknowledged. */ pstate->snd_acked = tcp_getsequence(tcp->ackno) - pstate->snd_isn; nllvdbg("ACK: acked=%d sent=%d buflen=%d\n", pstate->snd_acked, pstate->snd_sent, pstate->snd_buflen); /* Have all of the bytes in the buffer been sent and acknowledged? */ if (pstate->snd_acked >= pstate->snd_buflen) { /* Yes. Then pstate->snd_buflen should hold the number of bytes * actually sent. */ goto end_wait; } /* No.. fall through to send more data if necessary */ } /* Check if we are being asked to retransmit data */ else if ((flags & TCP_REXMIT) != 0) { /* Yes.. in this case, reset the number of bytes that have been sent * to the number of bytes that have been ACKed. */ pstate->snd_sent = pstate->snd_acked; #if defined(CONFIG_NET_TCP_SPLIT) /* Reset the even/odd indicator to even since we need to * retransmit. */ pstate->snd_odd = false; #endif /* Fall through to re-send data from the last that was ACKed */ } /* Check for a loss of connection */ else if ((flags & TCP_DISCONN_EVENTS) != 0) { /* Report not connected */ nllvdbg("Lost connection\n"); net_lostconnection(pstate->snd_sock, flags); pstate->snd_sent = -ENOTCONN; goto end_wait; } /* Check if the outgoing packet is available (it may have been claimed * by a sendto interrupt serving a different thread). */ #if 0 /* We can't really support multiple senders on the same TCP socket */ else if (dev->d_sndlen > 0) { /* Another thread has beat us sending data, wait for the next poll */ return flags; } #endif /* We get here if (1) not all of the data has been ACKed, (2) we have been * asked to retransmit data, (3) the connection is still healthy, and (4) * the outgoing packet is available for our use. In this case, we are * now free to send more data to receiver -- UNLESS the buffer contains * unprocessed incoming data. In that event, we will have to wait for the * next polling cycle. */ if ((flags & TCP_NEWDATA) == 0 && pstate->snd_sent < pstate->snd_buflen) { uint32_t seqno; /* Get the amount of data that we can send in the next packet */ uint32_t sndlen = pstate->snd_buflen - pstate->snd_sent; #if defined(CONFIG_NET_TCP_SPLIT) /* RFC 1122 states that a host may delay ACKing for up to 500ms but * must respond to every second segment). This logic here will trick * the RFC 1122 recipient into responding sooner. This logic will be * activated if: * * 1. An even number of packets has been send (where zero is an even * number), * 2. There is more data be sent (more than or equal to * CONFIG_NET_TCP_SPLIT_SIZE), but * 3. Not enough data for two packets. * * Then we will split the remaining, single packet into two partial * packets. This will stimulate the RFC 1122 peer to ACK sooner. * * Don't try to split very small packets (less than CONFIG_NET_TCP_SPLIT_SIZE). * Only the first even packet and the last odd packets could have * sndlen less than CONFIG_NET_TCP_SPLIT_SIZE. The value of sndlen on * the last even packet is guaranteed to be at least MSS/2 by the * logic below. */ if (sndlen >= CONFIG_NET_TCP_SPLIT_SIZE) { /* sndlen is the number of bytes remaining to be sent. * conn->mss will provide the number of bytes that can sent * in one packet. The difference, then, is the number of bytes * that would be sent in the next packet after this one. */ int32_t next_sndlen = sndlen - conn->mss; /* Is this the even packet in the packet pair transaction? */ if (!pstate->snd_odd) { /* next_sndlen <= 0 means that the entire remaining data * could fit into this single packet. This is condition * in which we must do the split. */ if (next_sndlen <= 0) { /* Split so that there will be an odd packet. Here * we know that 0 < sndlen <= MSS */ sndlen = (sndlen / 2) + 1; } } /* No... this is the odd packet in the packet pair transaction */ else { /* Will there be another (even) packet afer this one? * (next_sndlen > 0) Will the split condition occur on that * next, even packet? ((next_sndlen - conn->mss) < 0) If * so, then perform the split now to avoid the case where the * byte count is less than CONFIG_NET_TCP_SPLIT_SIZE on the * next pair. */ if (next_sndlen > 0 && (next_sndlen - conn->mss) < 0) { /* Here, we know that sndlen must be MSS < sndlen <= 2*MSS * and so (sndlen / 2) is <= MSS. */ sndlen /= 2; } } } /* Toggle the even/odd indicator */ pstate->snd_odd ^= true; #endif /* CONFIG_NET_TCP_SPLIT */ if (sndlen > conn->mss) { sndlen = conn->mss; } /* Check if we have "space" in the window */ if ((pstate->snd_sent - pstate->snd_acked + sndlen) < conn->winsize) { /* Set the sequence number for this packet. NOTE: The network updates * sndseq on receipt of ACK *before* this function is called. In that * case sndseq will point to the next unacknowledged byte (which might * have already been sent). We will overwrite the value of sndseq * here before the packet is sent. */ seqno = pstate->snd_sent + pstate->snd_isn; nllvdbg("SEND: sndseq %08x->%08x\n", conn->sndseq, seqno); tcp_setsequence(conn->sndseq, seqno); #ifdef NEED_IPDOMAIN_SUPPORT /* If both IPv4 and IPv6 support are enabled, then we will need to * select which one to use when generating the outgoing packet. * If only one domain is selected, then the setup is already in * place and we need do nothing. */ tcpsend_ipselect(dev, pstate); #endif /* Then set-up to send that amount of data. (this won't actually * happen until the polling cycle completes). */ devif_send(dev, &pstate->snd_buffer[pstate->snd_sent], sndlen); /* Check if the destination IP address is in the ARP or Neighbor * table. If not, then the send won't actually make it out... it * will be replaced with an ARP request or Neighbor Solicitation. */ if (pstate->snd_sent != 0 || psock_send_addrchck(conn)) { /* Update the amount of data sent (but not necessarily ACKed) */ pstate->snd_sent += sndlen; nllvdbg("SEND: acked=%d sent=%d buflen=%d\n", pstate->snd_acked, pstate->snd_sent, pstate->snd_buflen); } } } #ifdef CONFIG_NET_SOCKOPTS /* All data has been sent and we are just waiting for ACK or re-transmit * indications to complete the send. Check for a timeout. */ if (send_timeout(pstate)) { /* Yes.. report the timeout */ nlldbg("SEND timeout\n"); pstate->snd_sent = -ETIMEDOUT; goto end_wait; } #endif /* CONFIG_NET_SOCKOPTS */ /* Continue waiting */ return flags; end_wait: /* Do not allow any further callbacks */ pstate->snd_cb->flags = 0; pstate->snd_cb->priv = NULL; pstate->snd_cb->event = NULL; /* There are no outstanding, unacknowledged bytes */ conn->unacked = 0; /* Wake up the waiting thread */ sem_post(&pstate->snd_sem); return flags; }
FAR struct iob_s *iob_trimtail(FAR struct iob_s *iob, unsigned int trimlen) { FAR struct iob_s *entry; FAR struct iob_s *penultimate; FAR struct iob_s *last; unsigned int iosize; int len; nlldbg("iob=%p pktlen=%d trimlen=%d\n", iob, iob->io_pktlen, trimlen); if (iob && trimlen > 0) { len = trimlen; /* Loop until complete the trim */ while (len > 0) { /* Calculate the total length of the data in the I/O buffer * chain and find the last entry in the chain. */ penultimate = NULL; last = NULL; iosize = 0; for (entry = iob; entry; entry = entry->io_flink) { /* Accumulate the total size of all buffers in the list */ iosize += entry->io_len; /* Remember the last and the next to the last in the chain */ penultimate = last; last = entry; } /* Trim from the last entry in the chain. Do we trim this entire * I/O buffer away? */ nllvdbg("iob=%p len=%d vs %d\n", last, last->io_len, len); if (last->io_len <= len) { /* Yes.. Consume the entire buffer */ iob->io_pktlen -= last->io_len; len -= last->io_len; last->io_len = 0; /* Free the last, empty buffer in the list */ iob_free(last); /* There should be a buffer before this one */ if (!penultimate) { /* No.. we just freed the head of the chain */ return NULL; } /* Unlink the penultimate from the freed buffer */ penultimate->io_flink = NULL; } else { /* No, then just take what we need from this I/O buffer and * stop the trim. */ iob->io_pktlen -= len; last->io_len -= len; len = 0; } } } return iob; }
int icmp_ping(in_addr_t addr, uint16_t id, uint16_t seqno, uint16_t datalen, int dsecs) { struct icmp_ping_s state; net_lock_t save; #ifdef CONFIG_NET_ARP_SEND int ret; /* Make sure that the IP address mapping is in the ARP table */ ret = arp_send(addr); if (ret < 0) { ndbg("ERROR: Not reachable\n"); return -ENETUNREACH; } #endif /* Initialize the state structure */ sem_init(&state.png_sem, 0, 0); state.png_ticks = DSEC2TICK(dsecs); /* System ticks to wait */ state.png_result = -ENOMEM; /* Assume allocation failure */ state.png_addr = addr; /* Address of the peer to be ping'ed */ state.png_id = id; /* The ID to use in the ECHO request */ state.png_seqno = seqno; /* The seqno to use in the ECHO request */ state.png_datlen = datalen; /* The length of data to send in the ECHO request */ state.png_sent = false; /* ECHO request not yet sent */ save = net_lock(); state.png_time = clock_systimer(); /* Set up the callback */ state.png_cb = icmp_callback_alloc(); if (state.png_cb) { state.png_cb->flags = (ICMP_POLL | ICMP_ECHOREPLY); state.png_cb->priv = (void*)&state; state.png_cb->event = ping_interrupt; state.png_result = -EINTR; /* Assume sem-wait interrupted by signal */ /* Notify the device driver of the availability of TX data */ #ifdef CONFIG_NETDEV_MULTINIC netdev_ipv4_txnotify(g_ipv4_allzeroaddr, state.png_addr); #else netdev_ipv4_txnotify(state.png_addr); #endif /* Wait for either the full round trip transfer to complete or * for timeout to occur. (1) net_lockedwait will also terminate if a * signal is received, (2) interrupts may be disabled! They will * be re-enabled while the task sleeps and automatically * re-enabled when the task restarts. */ nllvdbg("Start time: 0x%08x seqno: %d\n", state.png_time, seqno); net_lockedwait(&state.png_sem); icmp_callback_free(state.png_cb); } net_unlock(save); /* Return the negated error number in the event of a failure, or the * sequence number of the ECHO reply on success. */ if (!state.png_result) { nllvdbg("Return seqno=%d\n", state.png_seqno); return (int)state.png_seqno; } else { nlldbg("Return error=%d\n", -state.png_result); return state.png_result; } }
FAR char *telnetd_driver(long sd, FAR struct telnetd_s *daemon) { FAR struct telnetd_dev_s *priv; FAR char *devpath = NULL; int ret; /* Allocate instance data for this driver */ priv = (FAR struct telnetd_dev_s*)malloc(sizeof(struct telnetd_dev_s)); if (!priv) { nlldbg("Failed to allocate the driver data structure\n"); return NULL; } /* Initialize the allocated driver instance */ sem_init(&priv->td_exclsem, 0, 1); priv->td_state = STATE_NORMAL; priv->td_crefs = 0; priv->td_pending = 0; priv->td_offset = 0; priv->td_psock = sd; /* Allocation a unique minor device number of the telnet drvier */ do { ret = sem_wait(&g_telnetdcommon.exclsem); if (ret < 0 && errno != -EINTR) { goto errout_with_dev; } } while (ret < 0); priv->td_minor = g_telnetdcommon.minor; g_telnetdcommon.minor++; sem_post(&g_telnetdcommon.exclsem); /* Create a path and name for the driver. */ ret = asprintf(&devpath, TELNETD_DEVFMT, priv->td_minor); if (ret < 0) { nlldbg("Failed to allocate the driver path\n"); goto errout_with_dev; } /* Register the driver */ ret = register_driver(devpath, &g_telnetdfops, 0666, priv); if (ret < 0) { nlldbg("Failed to register the driver %s: %d\n", devpath, ret); goto errout_with_devpath; } /* Return the path to the new telnet driver */ return devpath; errout_with_devpath: free(devpath); errout_with_dev: free(priv); return NULL; }
static ssize_t telnetd_write(FAR struct file *filep, FAR const char *buffer, size_t len) { FAR struct inode *inode = filep->f_inode; FAR struct telnetd_dev_s *priv = inode->i_private; FAR const char *src = buffer; ssize_t nsent; ssize_t ret; int ncopied; char ch; bool eol; nllvdbg("len: %d\n", len); /* Process each character from the user buffer */ for (nsent = 0, ncopied = 0; nsent < len; nsent++) { /* Get the next character from the user buffer */ ch = *src++; /* Add the character to the TX buffer */ eol = telnetd_putchar(priv, ch, &ncopied); /* Was that the end of a line? Or is the buffer too full to hold the * next largest character sequence ("\r\n\0")? */ if (eol || ncopied > TELNET_TXBUFFER_SIZE-3) { /* Yes... send the data now */ ret = send(priv->td_psock, priv->td_txbuffer, ncopied, 0); if (ret < 0) { nlldbg("psock_send failed '%s': %d\n", priv->td_txbuffer, ret); return ret; } /* Reset the index to the beginning of the TX buffer. */ ncopied = 0; } } /* Send anything remaining in the TX buffer */ if (ncopied > 0) { ret = send(priv->td_psock, priv->td_txbuffer, ncopied, 0); if (ret < 0) { nlldbg("psock_send failed '%s': %d\n", priv->td_txbuffer, ret); return ret; } } /* Notice that we don't actually return the number of bytes sent, but * rather, the number of bytes that the caller asked us to send. We may * have sent more bytes (because of CR-LF expansion and because of NULL * termination). But it confuses some logic if you report that you sent * more than you were requested to. */ return len; }
static int telnetd_close(FAR struct file *filep) { FAR struct inode *inode = filep->f_inode; FAR struct telnetd_dev_s *priv = inode->i_private; FAR char *devpath; int ret; nllvdbg("td_crefs: %d\n", priv->td_crefs); /* Get exclusive access to the device structures */ ret = sem_wait(&priv->td_exclsem); if (ret < 0) { ret = -errno; goto errout; } /* Decrement the references to the driver. If the reference count will * decrement to 0, then uninitialize the driver. */ if (priv->td_crefs > 1) { /* Just decrement the reference count and release the semaphore */ priv->td_crefs--; sem_post(&priv->td_exclsem); } else { /* Re-create the path to the driver. */ sched_lock(); ret = asprintf(&devpath, TELNETD_DEVFMT, priv->td_minor); if (ret < 0) { nlldbg("Failed to allocate the driver path\n"); } else { /* Unregister the character driver */ ret = unregister_driver(devpath); if (ret < 0) { nlldbg("Failed to unregister the driver %s: %d\n", devpath, ret); } free(devpath); } /* Close the socket */ closesocket(priv->td_psock); /* Release the driver memory. What if there are threads waiting on * td_exclsem? They will never be awakened! How could this happen? * crefs == 1 so there are no other open references to the driver. * But this could have if someone were trying to re-open the driver * after every other thread has closed it. That really should not * happen in the intended usage model. */ DEBUGASSERT(priv->td_exclsem.semcount == 0); sem_destroy(&priv->td_exclsem); free(priv); sched_unlock(); } ret = OK; errout: return ret; }
static uint16_t psock_send_interrupt(FAR struct net_driver_s *dev, FAR void *pvconn, FAR void *pvpriv, uint16_t flags) { FAR struct tcp_conn_s *conn = (FAR struct tcp_conn_s *)pvconn; FAR struct socket *psock = (FAR struct socket *)pvpriv; nllvdbg("flags: %04x\n", flags); /* If this packet contains an acknowledgement, then update the count of * acknowledged bytes. */ if ((flags & TCP_ACKDATA) != 0) { FAR struct tcp_wrbuffer_s *wrb; FAR sq_entry_t *entry; FAR sq_entry_t *next; uint32_t ackno; ackno = tcp_getsequence(TCPBUF->ackno); nllvdbg("ACK: ackno=%u flags=%04x\n", ackno, flags); /* Look at every write buffer in the unacked_q. The unacked_q * holds write buffers that have been entirely sent, but which * have not yet been ACKed. */ for (entry = sq_peek(&conn->unacked_q); entry; entry = next) { uint32_t lastseq; /* Check of some or all of this write buffer has been ACKed. */ next = sq_next(entry); wrb = (FAR struct tcp_wrbuffer_s*)entry; /* If the ACKed sequence number is greater than the start * sequence number of the write buffer, then some or all of * the write buffer has been ACKed. */ if (ackno > WRB_SEQNO(wrb)) { /* Get the sequence number at the end of the data */ lastseq = WRB_SEQNO(wrb) + WRB_PKTLEN(wrb); nllvdbg("ACK: wrb=%p seqno=%u lastseq=%u pktlen=%u ackno=%u\n", wrb, WRB_SEQNO(wrb), lastseq, WRB_PKTLEN(wrb), ackno); /* Has the entire buffer been ACKed? */ if (ackno >= lastseq) { nllvdbg("ACK: wrb=%p Freeing write buffer\n", wrb); /* Yes... Remove the write buffer from ACK waiting queue */ sq_rem(entry, &conn->unacked_q); /* And return the write buffer to the pool of free buffers */ tcp_wrbuffer_release(wrb); } else { unsigned int trimlen; /* No, then just trim the ACKed bytes from the beginning * of the write buffer. This will free up some I/O buffers * that can be reused while are still sending the last * buffers in the chain. */ trimlen = ackno - WRB_SEQNO(wrb); if (trimlen > WRB_SENT(wrb)) { /* More data has been ACKed then we have sent? */ trimlen = WRB_SENT(wrb); } nllvdbg("ACK: wrb=%p trim %u bytes\n", wrb, trimlen); WRB_TRIM(wrb, trimlen); WRB_SEQNO(wrb) = ackno; WRB_SENT(wrb) -= trimlen; /* Set the new sequence number for what remains */ nllvdbg("ACK: wrb=%p seqno=%u pktlen=%u\n", wrb, WRB_SEQNO(wrb), WRB_PKTLEN(wrb)); } } } /* A special case is the head of the write_q which may be partially * sent and so can still have un-ACKed bytes that could get ACKed * before the entire write buffer has even been sent. */ wrb = (FAR struct tcp_wrbuffer_s*)sq_peek(&conn->write_q); if (wrb && WRB_SENT(wrb) > 0 && ackno > WRB_SEQNO(wrb)) { uint32_t nacked; /* Number of bytes that were ACKed */ nacked = ackno - WRB_SEQNO(wrb); if (nacked > WRB_SENT(wrb)) { /* More data has been ACKed then we have sent? ASSERT? */ nacked = WRB_SENT(wrb); } nllvdbg("ACK: wrb=%p seqno=%u nacked=%u sent=%u ackno=%u\n", wrb, WRB_SEQNO(wrb), nacked, WRB_SENT(wrb), ackno); /* Trim the ACKed bytes from the beginning of the write buffer. */ WRB_TRIM(wrb, nacked); WRB_SEQNO(wrb) = ackno; WRB_SENT(wrb) -= nacked; nllvdbg("ACK: wrb=%p seqno=%u pktlen=%u sent=%u\n", wrb, WRB_SEQNO(wrb), WRB_PKTLEN(wrb), WRB_SENT(wrb)); } } /* Check for a loss of connection */ else if ((flags & (TCP_CLOSE | TCP_ABORT | TCP_TIMEDOUT)) != 0) { nllvdbg("Lost connection: %04x\n", flags); /* Report not connected */ net_lostconnection(psock, flags); /* Free write buffers and terminate polling */ psock_lost_connection(psock, conn); return flags; } /* Check if we are being asked to retransmit data */ else if ((flags & TCP_REXMIT) != 0) { FAR struct tcp_wrbuffer_s *wrb; FAR sq_entry_t *entry; nllvdbg("REXMIT: %04x\n", flags); /* If there is a partially sent write buffer at the head of the * write_q? Has anything been sent from that write buffer? */ wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q); nllvdbg("REXMIT: wrb=%p sent=%u\n", wrb, wrb ? WRB_SENT(wrb) : 0); if (wrb != NULL && WRB_SENT(wrb) > 0) { FAR struct tcp_wrbuffer_s *tmp; uint16_t sent; /* Yes.. Reset the number of bytes sent sent from the write buffer */ sent = WRB_SENT(wrb); if (conn->unacked > sent) { conn->unacked -= sent; } else { conn->unacked = 0; } if (conn->sent > sent) { conn->sent -= sent; } else { conn->sent = 0; } WRB_SENT(wrb) = 0; nllvdbg("REXMIT: wrb=%p sent=%u, conn unacked=%d sent=%d\n", wrb, WRB_SENT(wrb), conn->unacked, conn->sent); /* Increment the retransmit count on this write buffer. */ if (++WRB_NRTX(wrb) >= TCP_MAXRTX) { nlldbg("Expiring wrb=%p nrtx=%u\n", wrb, WRB_NRTX(wrb)); /* The maximum retry count as been exhausted. Remove the write * buffer at the head of the queue. */ tmp = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&conn->write_q); DEBUGASSERT(tmp == wrb); UNUSED(tmp); /* And return the write buffer to the free list */ tcp_wrbuffer_release(wrb); /* NOTE expired is different from un-ACKed, it is designed to * represent the number of segments that have been sent, * retransmitted, and un-ACKed, if expired is not zero, the * connection will be closed. * * field expired can only be updated at TCP_ESTABLISHED state */ conn->expired++; } } /* Move all segments that have been sent but not ACKed to the write * queue again note, the un-ACKed segments are put at the head of the * write_q so they can be resent as soon as possible. */ while ((entry = sq_remlast(&conn->unacked_q)) != NULL) { wrb = (FAR struct tcp_wrbuffer_s*)entry; uint16_t sent; /* Reset the number of bytes sent sent from the write buffer */ sent = WRB_SENT(wrb); if (conn->unacked > sent) { conn->unacked -= sent; } else { conn->unacked = 0; } if (conn->sent > sent) { conn->sent -= sent; } else { conn->sent = 0; } WRB_SENT(wrb) = 0; nllvdbg("REXMIT: wrb=%p sent=%u, conn unacked=%d sent=%d\n", wrb, WRB_SENT(wrb), conn->unacked, conn->sent); /* Free any write buffers that have exceed the retry count */ if (++WRB_NRTX(wrb) >= TCP_MAXRTX) { nlldbg("Expiring wrb=%p nrtx=%u\n", wrb, WRB_NRTX(wrb)); /* Return the write buffer to the free list */ tcp_wrbuffer_release(wrb); /* NOTE expired is different from un-ACKed, it is designed to * represent the number of segments that have been sent, * retransmitted, and un-ACKed, if expired is not zero, the * connection will be closed. * * field expired can only be updated at TCP_ESTABLISHED state */ conn->expired++; continue; } else { /* Insert the write buffer into the write_q (in sequence * number order). The retransmission will occur below * when the write buffer with the lowest sequenc number * is pulled from the write_q again. */ nllvdbg("REXMIT: Moving wrb=%p nrtx=%u\n", wrb, WRB_NRTX(wrb)); psock_insert_segment(wrb, &conn->write_q); } } } /* Check if the outgoing packet is available (it may have been claimed * by a sendto interrupt serving a different thread). */ if (dev->d_sndlen > 0) { /* Another thread has beat us sending data, wait for the next poll */ return flags; } /* We get here if (1) not all of the data has been ACKed, (2) we have been * asked to retransmit data, (3) the connection is still healthy, and (4) * the outgoing packet is available for our use. In this case, we are * now free to send more data to receiver -- UNLESS the buffer contains * unprocessed incoming data. In that event, we will have to wait for the * next polling cycle. */ if ((conn->tcpstateflags & TCP_ESTABLISHED) && (flags & (TCP_POLL | TCP_REXMIT)) && !(sq_empty(&conn->write_q))) { /* Check if the destination IP address is in the ARP table. If not, * then the send won't actually make it out... it will be replaced with * an ARP request. * * NOTE 1: This could be an expensive check if there are a lot of * entries in the ARP table. * * NOTE 2: If we are actually harvesting IP addresses on incoming IP * packets, then this check should not be necessary; the MAC mapping * should already be in the ARP table in many cases. * * NOTE 3: If CONFIG_NET_ARP_SEND then we can be assured that the IP * address mapping is already in the ARP table. */ #if defined(CONFIG_NET_ETHERNET) && !defined(CONFIG_NET_ARP_IPIN) && \ !defined(CONFIG_NET_ARP_SEND) if (arp_find(conn->ripaddr) != NULL) #endif { FAR struct tcp_wrbuffer_s *wrb; size_t sndlen; /* Peek at the head of the write queue (but don't remove anything * from the write queue yet). We know from the above test that * the write_q is not empty. */ wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q); DEBUGASSERT(wrb); /* Get the amount of data that we can send in the next packet. * We will send either the remaining data in the buffer I/O * buffer chain, or as much as will fit given the MSS and current * window size. */ sndlen = WRB_PKTLEN(wrb) - WRB_SENT(wrb); if (sndlen > tcp_mss(conn)) { sndlen = tcp_mss(conn); } if (sndlen > conn->winsize) { sndlen = conn->winsize; } nllvdbg("SEND: wrb=%p pktlen=%u sent=%u sndlen=%u\n", wrb, WRB_PKTLEN(wrb), WRB_SENT(wrb), sndlen); /* Set the sequence number for this segment. If we are * retransmitting, then the sequence number will already * be set for this write buffer. */ if (WRB_SEQNO(wrb) == (unsigned)-1) { WRB_SEQNO(wrb) = conn->isn + conn->sent; } /* The TCP stack updates sndseq on receipt of ACK *before* * this function is called. In that case sndseq will point * to the next unacknowledged byte (which might have already * been sent). We will overwrite the value of sndseq here * before the packet is sent. */ tcp_setsequence(conn->sndseq, WRB_SEQNO(wrb) + WRB_SENT(wrb)); /* Then set-up to send that amount of data with the offset * corresponding to the amount of data already sent. (this * won't actually happen until the polling cycle completes). */ devif_iob_send(dev, WRB_IOB(wrb), sndlen, WRB_SENT(wrb)); /* Remember how much data we send out now so that we know * when everything has been acknowledged. Just increment * the amount of data sent. This will be needed in sequence * number calculations. */ conn->unacked += sndlen; conn->sent += sndlen; nllvdbg("SEND: wrb=%p nrtx=%u unacked=%u sent=%u\n", wrb, WRB_NRTX(wrb), conn->unacked, conn->sent); /* Increment the count of bytes sent from this write buffer */ WRB_SENT(wrb) += sndlen; nllvdbg("SEND: wrb=%p sent=%u pktlen=%u\n", wrb, WRB_SENT(wrb), WRB_PKTLEN(wrb)); /* Remove the write buffer from the write queue if the * last of the data has been sent from the buffer. */ DEBUGASSERT(WRB_SENT(wrb) <= WRB_PKTLEN(wrb)); if (WRB_SENT(wrb) >= WRB_PKTLEN(wrb)) { FAR struct tcp_wrbuffer_s *tmp; nllvdbg("SEND: wrb=%p Move to unacked_q\n", wrb); tmp = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&conn->write_q); DEBUGASSERT(tmp == wrb); UNUSED(tmp); /* Put the I/O buffer chain in the un-acked queue; the * segment is waiting for ACK again */ psock_insert_segment(wrb, &conn->unacked_q); } /* Only one data can be sent by low level driver at once, * tell the caller stop polling the other connection. */ flags &= ~TCP_POLL; } } /* Continue waiting */ return flags; }
static uint16_t send_interrupt(struct uip_driver_s *dev, void *pvconn, void *pvpriv, uint16_t flags) { struct uip_conn *conn = (struct uip_conn*)pvconn; struct send_s *pstate = (struct send_s *)pvpriv; nllvdbg("flags: %04x acked: %d sent: %d\n", flags, pstate->snd_acked, pstate->snd_sent); /* If this packet contains an acknowledgement, then update the count of * acknowldged bytes. */ if ((flags & UIP_ACKDATA) != 0) { /* The current acknowledgement number number is the (relative) offset * of the of the next byte needed by the receiver. The snd_isn is the * offset of the first byte to send to the receiver. The difference * is the number of bytes to be acknowledged. */ pstate->snd_acked = uip_tcpgetsequence(TCPBUF->ackno) - pstate->snd_isn; nllvdbg("ACK: acked=%d sent=%d buflen=%d\n", pstate->snd_acked, pstate->snd_sent, pstate->snd_buflen); /* Have all of the bytes in the buffer been sent and acknowledged? */ if (pstate->snd_acked >= pstate->snd_buflen) { /* Yes. Then pstate->snd_buflen should hold the number of bytes * actually sent. */ goto end_wait; } /* No.. fall through to send more data if necessary */ } /* Check if we are being asked to retransmit data */ else if ((flags & UIP_REXMIT) != 0) { /* Yes.. in this case, reset the number of bytes that have been sent * to the number of bytes that have been ACKed. */ pstate->snd_sent = pstate->snd_acked; /* Fall through to re-send data from the last that was ACKed */ } /* Check for a loss of connection */ else if ((flags & (UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT)) != 0) { /* Report not connected */ nllvdbg("Lost connection\n"); pstate->snd_sent = -ENOTCONN; goto end_wait; } /* Check if the outgoing packet is available (it may have been claimed * by a sendto interrupt serving a different thread). */ #if 0 /* We can't really support multiple senders on the same TCP socket */ else if (dev->d_sndlen > 0) { /* Another thread has beat us sending data, wait for the next poll */ return flags; } #endif /* We get here if (1) not all of the data has been ACKed, (2) we have been * asked to retransmit data, (3) the connection is still healthy, and (4) * the outgoing packet is available for our use. In this case, we are * now free to send more data to receiver -- UNLESS the buffer contains * unprocessing incoming data. In that event, we will have to wait for the * next polling cycle. */ if ((flags & UIP_NEWDATA) == 0 && pstate->snd_sent < pstate->snd_buflen) { uint32_t seqno; /* Get the amount of data that we can send in the next packet */ uint32_t sndlen = pstate->snd_buflen - pstate->snd_sent; if (sndlen > uip_mss(conn)) { sndlen = uip_mss(conn); } /* Set the sequence number for this packet. NOTE: uIP updates * sndseq on recept of ACK *before* this function is called. In that * case sndseq will point to the next unacknowledge byte (which might * have already been sent). We will overwrite the value of sndseq * here before the packet is sent. */ seqno = pstate->snd_sent + pstate->snd_isn; nllvdbg("SEND: sndseq %08x->%08x\n", conn->sndseq, seqno); uip_tcpsetsequence(conn->sndseq, seqno); /* Then set-up to send that amount of data. (this won't actually * happen until the polling cycle completes). */ uip_send(dev, &pstate->snd_buffer[pstate->snd_sent], sndlen); /* Check if the destination IP address is in the ARP table. If not, * then the send won't actually make it out... it will be replaced with * an ARP request. * * NOTE 1: This could an expensive check if there are a lot of entries * in the ARP table. Hence, we only check on the first packet -- when * snd_sent is zero. * * NOTE 2: If we are actually harvesting IP addresses on incomming IP * packets, then this check should not be necessary; the MAC mapping * should already be in the ARP table. */ #if defined(CONFIG_NET_ETHERNET) && defined (CONFIG_NET_ARP_IPIN) if (pstate->snd_sent != 0 || uip_arp_find(conn->ripaddr) != NULL) #endif { /* Update the amount of data sent (but not necessarily ACKed) */ pstate->snd_sent += sndlen; nllvdbg("SEND: acked=%d sent=%d buflen=%d\n", pstate->snd_acked, pstate->snd_sent, pstate->snd_buflen); /* Update the send time */ #if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK) pstate->snd_time = clock_systimer(); #endif } } /* All data has been send and we are just waiting for ACK or re-transmit * indications to complete the send. Check for a timeout. */ #if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK) else if (send_timeout(pstate)) { /* Yes.. report the timeout */ nlldbg("SEND timeout\n"); pstate->snd_sent = -ETIMEDOUT; goto end_wait; } #endif /* CONFIG_NET_SOCKOPTS && !CONFIG_DISABLE_CLOCK */ /* Continue waiting */ return flags; end_wait: /* Do not allow any further callbacks */ pstate->snd_cb->flags = 0; pstate->snd_cb->priv = NULL; pstate->snd_cb->event = NULL; /* There are no outstanding, unacknowledged bytes */ conn->unacked = 0; /* Wake up the waiting thread */ sem_post(&pstate->snd_sem); return flags; }