Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
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;
}
Ejemplo n.º 6
0
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);
}
Ejemplo n.º 7
0
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);
}
Ejemplo n.º 8
0
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;
}
Ejemplo n.º 9
0
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);
}
Ejemplo n.º 10
0
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;
}
Ejemplo n.º 11
0
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;
}
Ejemplo n.º 12
0
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");
    }
}
Ejemplo n.º 13
0
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;
}
Ejemplo n.º 14
0
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));
}
Ejemplo n.º 15
0
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;
}
Ejemplo n.º 16
0
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;
}
Ejemplo n.º 17
0
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);
}
Ejemplo n.º 18
0
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;
}
Ejemplo n.º 19
0
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;
}
Ejemplo n.º 20
0
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;
}
Ejemplo n.º 21
0
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;
    }
}
Ejemplo n.º 22
0
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;
}
Ejemplo n.º 23
0
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;
}
Ejemplo n.º 24
0
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;
}
Ejemplo n.º 25
0
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;
    }
}
Ejemplo n.º 26
0
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;
}
Ejemplo n.º 27
0
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;
}
Ejemplo n.º 28
0
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;
}
Ejemplo n.º 29
0
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;
}
Ejemplo n.º 30
0
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;
}