Exemple #1
0
/**
 * Send data to a specified address using UDP.
 * The netif used for sending can be specified.
 *
 * This function exists mainly for DHCP, to be able to send UDP packets
 * on a netif that is still down.
 *
 * @param pcb UDP PCB used to send the data.
 * @param p chain of pbuf's to be sent.
 * @param dst_ip Destination IP address.
 * @param dst_port Destination UDP port.
 * @param netif the netif used for sending.
 *
 * dst_ip & dst_port are expected to be in the same byte order as in the pcb.
 *
 * @return lwIP error code (@see udp_send for possible error codes)
 *
 * @see udp_disconnect() udp_send()
 */
err_t
udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
  struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif)
{
  struct udp_hdr *udphdr;
  struct ip_addr *src_ip;
  err_t err;
  struct pbuf *q; /* q will be sent down the stack */

  /* if the PCB is not yet bound to a port, bind it here */
  if (pcb->local_port == 0) {
    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: not yet bound to a port, binding now\n"));
    err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
    if (err != ERR_OK) {
      LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: forced port bind failed\n"));
      return err;
    }
  }

  /* not enough space to add an UDP header to first pbuf in given p chain? */
  if (pbuf_header(p, UDP_HLEN)) {
    /* allocate header in a separate new pbuf */
    q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);
    /* new header pbuf could not be allocated? */
    if (q == NULL) {
      LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: could not allocate header\n"));
      return ERR_MEM;
    }
    /* chain header q in front of given pbuf p */
    pbuf_chain(q, p);
    /* first pbuf q points to header pbuf */
    LWIP_DEBUGF(UDP_DEBUG,
                ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
  } else {
    /* adding space for header within p succeeded */
    /* first pbuf q equals given pbuf */
    q = p;
    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p));
  }
  LWIP_ASSERT("check that first pbuf can hold struct udp_hdr",
              (q->len >= sizeof(struct udp_hdr)));
  /* q now represents the packet to be sent */
  udphdr = (struct udp_hdr *)(q->payload);
  udphdr->src = htons(pcb->local_port);
  udphdr->dest = htons(dst_port);
  /* in UDP, 0 checksum means 'no checksum' */
  udphdr->chksum = 0x0000; 

  /* PCB local address is IP_ANY_ADDR? */
  if (ip_addr_isany(&pcb->local_ip)) {
    /* use outgoing network interface IP address as source address */
    src_ip = &(netif->ip_addr);
  } else {
    /* check if UDP PCB local IP address is correct
     * this could be an old address if netif->ip_addr has changed */
    if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {
      /* local_ip doesn't match, drop the packet */
      if (q != p) {
        /* free the header pbuf */
        pbuf_free(q);
        q = NULL;
        /* p is still referenced by the caller, and will live on */
      }
      return ERR_VAL;
    }
    /* use UDP PCB local IP address as source address */
    src_ip = &(pcb->local_ip);
  }

  LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len));

#if LWIP_UDPLITE
  /* UDP Lite protocol? */
  if (pcb->flags & UDP_FLAGS_UDPLITE) {
    u16_t chklen, chklen_hdr;
    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len));
    /* set UDP message length in UDP header */
    chklen_hdr = chklen = pcb->chksum_len_tx;
    if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) {
      if (chklen != 0) {
        LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen));
      }
      /* For UDP-Lite, checksum length of 0 means checksum
         over the complete packet. (See RFC 3828 chap. 3.1)
         At least the UDP-Lite header must be covered by the
         checksum, therefore, if chksum_len has an illegal
         value, we generate the checksum over the complete
         packet to be safe. */
      chklen_hdr = 0;
      chklen = q->tot_len;
    }
    udphdr->len = htons(chklen_hdr);
    /* calculate checksum */
#if CHECKSUM_GEN_UDP
    udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip,
                                        IP_PROTO_UDPLITE, q->tot_len, chklen);
    /* chksum zero must become 0xffff, as zero means 'no checksum' */
    if (udphdr->chksum == 0x0000)
      udphdr->chksum = 0xffff;
#endif /* CHECKSUM_CHECK_UDP */
    /* output to IP */
    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));
#if LWIP_NETIF_HWADDRHINT
    netif->addr_hint = &(pcb->addr_hint);
#endif /* LWIP_NETIF_HWADDRHINT*/
    err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);
#if LWIP_NETIF_HWADDRHINT
    netif->addr_hint = NULL;
#endif /* LWIP_NETIF_HWADDRHINT*/
  } else
#endif /* LWIP_UDPLITE */
  {      /* UDP */
    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len));
    udphdr->len = htons(q->tot_len);
    /* calculate checksum */
#if CHECKSUM_GEN_UDP
    if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
      udphdr->chksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len);
      /* chksum zero must become 0xffff, as zero means 'no checksum' */
      if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff;
    }
#endif /* CHECKSUM_CHECK_UDP */
    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));
    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));
    /* output to IP */
#if LWIP_NETIF_HWADDRHINT
    netif->addr_hint = &(pcb->addr_hint);
#endif /* LWIP_NETIF_HWADDRHINT*/
    err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);
#if LWIP_NETIF_HWADDRHINT
    netif->addr_hint = NULL;
#endif /* LWIP_NETIF_HWADDRHINT*/
  }
  /* TODO: must this be increased even if error occured? */
  snmp_inc_udpoutdatagrams();

  /* did we chain a separate header pbuf earlier? */
  if (q != p) {
    /* free the header pbuf */
    pbuf_free(q);
    q = NULL;
    /* p is still referenced by the caller, and will live on */
  }

  UDP_STATS_INC(udp.xmit);
  return err;
}
Exemple #2
0
/**
 * Handle the incoming SLIP stream character by character
 *
 * @param netif the lwip network interface structure for this slipif
 * @param c received character (multiple calls to this function will
 *        return a complete packet, NULL is returned before - used for polling)
 * @return The IP packet when SLIP_END is received
 */
static struct pbuf*
slipif_rxbyte(struct netif *netif, u8_t c)
{
    struct slipif_priv *priv;
    struct pbuf *t;

    LWIP_ASSERT("netif != NULL", (netif != NULL));
    LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));

    priv = netif->state;

    switch (priv->state) {
    case SLIP_RECV_NORMAL:
        switch (c) {
        case SLIP_END:
            if (priv->recved > 0) {
                /* Received whole packet. */
                /* Trim the pbuf to the size of the received packet. */
                pbuf_realloc(priv->q, priv->recved);

                LINK_STATS_INC(link.recv);

                LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet (%"U16_F" bytes)\n", priv->recved));
                t = priv->q;
                priv->p = priv->q = NULL;
                priv->i = priv->recved = 0;
                return t;
            }
            return NULL;
        case SLIP_ESC:
            priv->state = SLIP_RECV_ESCAPE;
            return NULL;
        } /* end switch (c) */
        break;
    case SLIP_RECV_ESCAPE:
        /* un-escape END or ESC bytes, leave other bytes
           (although that would be a protocol error) */
        switch (c) {
        case SLIP_ESC_END:
            c = SLIP_END;
            break;
        case SLIP_ESC_ESC:
            c = SLIP_ESC;
            break;
        }
        priv->state = SLIP_RECV_NORMAL;
        break;
    } /* end switch (priv->state) */

    /* byte received, packet not yet completely received */
    if (priv->p == NULL) {
        /* allocate a new pbuf */
        LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n"));
        priv->p = pbuf_alloc(PBUF_LINK, (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN), PBUF_POOL);

        if (priv->p == NULL) {
            LINK_STATS_INC(link.drop);
            LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n"));
            /* don't process any further since we got no pbuf to receive to */
            return NULL;
        }

        if (priv->q != NULL) {
            /* 'chain' the pbuf to the existing chain */
            pbuf_cat(priv->q, priv->p);
        } else {
            /* p is the first pbuf in the chain */
            priv->q = priv->p;
        }
    }

    /* this automatically drops bytes if > SLIP_MAX_SIZE */
    if ((priv->p != NULL) && (priv->recved <= SLIP_MAX_SIZE)) {
        ((u8_t *)priv->p->payload)[priv->i] = c;
        priv->recved++;
        priv->i++;
        if (priv->i >= priv->p->len) {
            /* on to the next pbuf */
            priv->i = 0;
            if (priv->p->next != NULL && priv->p->next->len > 0) {
                /* p is a chain, on to the next in the chain */
                priv->p = priv->p->next;
            } else {
                /* p is a single pbuf, set it to NULL so next time a new
                 * pbuf is allocated */
                priv->p = NULL;
            }
        }
    }
    return NULL;
}
/**
 * Sends a 'getresponse' message to the request originator.
 *
 * @param m_stat points to the current message request state source
 * @return ERR_OK when success, ERR_MEM if we're out of memory
 *
 * @note the caller is responsible for filling in outvb in the m_stat
 * and provide error-status and index (except for tooBig errors) ...
 */
err_t
snmp_send_response(struct snmp_msg_pstat *m_stat)
{
  struct snmp_varbind_root emptyvb = {NULL, NULL, 0, 0, 0};
  struct pbuf *p;
  u16_t tot_len;
  err_t err;

  /* pass 0, calculate length fields */
  tot_len = snmp_varbind_list_sum(&m_stat->outvb);
  tot_len = snmp_resp_header_sum(m_stat, tot_len);

  /* try allocating pbuf(s) for complete response */
  p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
  if (p == NULL)
  {
    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() tooBig\n"));

    /* can't construct reply, return error-status tooBig */
    m_stat->error_status = SNMP_ES_TOOBIG;
    m_stat->error_index = 0;
    /* pass 0, recalculate lengths, for empty varbind-list */
    tot_len = snmp_varbind_list_sum(&emptyvb);
    tot_len = snmp_resp_header_sum(m_stat, tot_len);
    /* retry allocation once for header and empty varbind-list */
    p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
  }
  if (p != NULL)
  {
    /* first pbuf alloc try or retry alloc success */
    u16_t ofs;

    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() p != NULL\n"));

    /* pass 1, size error, encode packet ino the pbuf(s) */
    ofs = snmp_resp_header_enc(m_stat, p);
    if (m_stat->error_status == SNMP_ES_TOOBIG)
    {
      snmp_varbind_list_enc(&emptyvb, p, ofs);
    }
    else
    {
      snmp_varbind_list_enc(&m_stat->outvb, p, ofs);
    }

    switch (m_stat->error_status)
    {
      case SNMP_ES_TOOBIG:
        snmp_inc_snmpouttoobigs();
        break;
      case SNMP_ES_NOSUCHNAME:
        snmp_inc_snmpoutnosuchnames();
        break;
      case SNMP_ES_BADVALUE:
        snmp_inc_snmpoutbadvalues();
        break;
      case SNMP_ES_GENERROR:
        snmp_inc_snmpoutgenerrs();
        break;
    }
    snmp_inc_snmpoutgetresponses();
    snmp_inc_snmpoutpkts();

    /** @todo do we need separate rx and tx pcbs for threaded case? */
    /** connect to the originating source */
    udp_connect(m_stat->pcb, &m_stat->sip, m_stat->sp);
    err = udp_send(m_stat->pcb, p);
    if (err == ERR_MEM)
    {
      /** @todo release some memory, retry and return tooBig? tooMuchHassle? */
      err = ERR_MEM;
    }
    else
    {
      err = ERR_OK;
    }
    /** disassociate remote address and port with this pcb */
    udp_disconnect(m_stat->pcb);

    pbuf_free(p);
    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() done\n"));
    return err;
  }
  else
  {
    /* first pbuf alloc try or retry alloc failed
       very low on memory, couldn't return tooBig */
    return ERR_MEM;
  }
}
Exemple #4
0
/**
 * Fragment an IP datagram if too large for the netif.
 *
 * Chop the datagram in MTU sized chunks and send them in order
 * by using a fixed size static memory buffer (PBUF_REF) or
 * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF).
 *
 * @param p ip packet to send
 * @param netif the netif on which to send
 * @param dest destination ip address to which to send
 *
 * @return ERR_OK if sent successfully, err_t otherwise
 */
err_t 
ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest)
{
  struct pbuf *rambuf;
#if IP_FRAG_USES_STATIC_BUF
  struct pbuf *header;
#else
#if !LWIP_NETIF_TX_SINGLE_PBUF
  struct pbuf *newpbuf;
#endif
  struct ip_hdr *original_iphdr;
#endif
  struct ip_hdr *iphdr;
  u16_t nfb;
  u16_t left, cop;
  u16_t mtu = netif->mtu;
  u16_t ofo, omf;
  u16_t last;
  u16_t poff = IP_HLEN;
  u16_t tmp;
#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
  u16_t newpbuflen = 0;
  u16_t left_to_copy;
#endif

  /* Get a RAM based MTU sized pbuf */
#if IP_FRAG_USES_STATIC_BUF
  /* When using a static buffer, we use a PBUF_REF, which we will
   * use to reference the packet (without link header).
   * Layer and length is irrelevant.
   */
  rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
  if (rambuf == NULL) {
    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n"));
    return ERR_MEM;
  }
  rambuf->tot_len = rambuf->len = mtu;
  rambuf->payload = LWIP_MEM_ALIGN((void *)buf);

  /* Copy the IP header in it */
  iphdr = (struct ip_hdr *)rambuf->payload;
  SMEMCPY(iphdr, p->payload, IP_HLEN);
#else /* IP_FRAG_USES_STATIC_BUF */
  original_iphdr = (struct ip_hdr *)p->payload;
  iphdr = original_iphdr;
#endif /* IP_FRAG_USES_STATIC_BUF */

  /* Save original offset */
  tmp = ntohs(IPH_OFFSET(iphdr));
  ofo = tmp & IP_OFFMASK;
  omf = tmp & IP_MF;

  left = p->tot_len - IP_HLEN;

  nfb = (mtu - IP_HLEN) / 8;

  while (left) {
    last = (left <= mtu - IP_HLEN);

    /* Set new offset and MF flag */
    tmp = omf | (IP_OFFMASK & (ofo));
    if (!last) {
      tmp = tmp | IP_MF;
    }

    /* Fill this fragment */
    cop = last ? left : nfb * 8;

#if IP_FRAG_USES_STATIC_BUF
    poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff);
#else /* IP_FRAG_USES_STATIC_BUF */
#if LWIP_NETIF_TX_SINGLE_PBUF
    rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM);
    if (rambuf == NULL) {
      return ERR_MEM;
    }
    LWIP_ASSERT("this needs a pbuf in one piece!",
      (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));
    poff += pbuf_copy_partial(p, rambuf->payload, cop, poff);
    /* make room for the IP header */
    if(pbuf_header(rambuf, IP_HLEN)) {
      pbuf_free(rambuf);
      return ERR_MEM;
    }
    /* fill in the IP header */
    SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
    iphdr = rambuf->payload;
#else /* LWIP_NETIF_TX_SINGLE_PBUF */
    /* When not using a static buffer, create a chain of pbufs.
     * The first will be a PBUF_RAM holding the link and IP header.
     * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
     * but limited to the size of an mtu.
     */
    rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM);
    if (rambuf == NULL) {
      return ERR_MEM;
    }
    LWIP_ASSERT("this needs a pbuf in one piece!",
                (p->len >= (IP_HLEN)));
    SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
    iphdr = (struct ip_hdr *)rambuf->payload;

    /* Can just adjust p directly for needed offset. */
    p->payload = (u8_t *)p->payload + poff;
    p->len -= poff;

    left_to_copy = cop;
    while (left_to_copy) {
      struct pbuf_custom_ref *pcr;
      newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
      /* Is this pbuf already empty? */
      if (!newpbuflen) {
        p = p->next;
        continue;
      }
      pcr = ip_frag_alloc_pbuf_custom_ref();
      if (pcr == NULL) {
        pbuf_free(rambuf);
        return ERR_MEM;
      }
      /* Mirror this pbuf, although we might not need all of it. */
      newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
      if (newpbuf == NULL) {
        ip_frag_free_pbuf_custom_ref(pcr);
        pbuf_free(rambuf);
        return ERR_MEM;
      }
      pbuf_ref(p);
      pcr->original = p;
      pcr->pc.custom_free_function = ipfrag_free_pbuf_custom;

      /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain
       * so that it is removed when pbuf_dechain is later called on rambuf.
       */
      pbuf_cat(rambuf, newpbuf);
      left_to_copy -= newpbuflen;
      if (left_to_copy) {
        p = p->next;
      }
    }
    poff = newpbuflen;
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
#endif /* IP_FRAG_USES_STATIC_BUF */

    /* Correct header */
    IPH_OFFSET_SET(iphdr, htons(tmp));
    IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
    IPH_CHKSUM_SET(iphdr, 0);
    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));

#if IP_FRAG_USES_STATIC_BUF
    if (last) {
      pbuf_realloc(rambuf, left + IP_HLEN);
    }

    /* This part is ugly: we alloc a RAM based pbuf for 
     * the link level header for each chunk and then 
     * free it.A PBUF_ROM style pbuf for which pbuf_header
     * worked would make things simpler.
     */
    header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);
    if (header != NULL) {
      pbuf_chain(header, rambuf);
      netif->output(netif, header, dest);
      IPFRAG_STATS_INC(ip_frag.xmit);
      snmp_inc_ipfragcreates();
      pbuf_free(header);
    } else {
      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n"));
      pbuf_free(rambuf);
      return ERR_MEM;
    }
#else /* IP_FRAG_USES_STATIC_BUF */
    /* No need for separate header pbuf - we allowed room for it in rambuf
     * when allocated.
     */
    netif->output(netif, rambuf, dest);
    IPFRAG_STATS_INC(ip_frag.xmit);

    /* Unfortunately we can't reuse rambuf - the hardware may still be
     * using the buffer. Instead we free it (and the ensuing chain) and
     * recreate it next time round the loop. If we're lucky the hardware
     * will have already sent the packet, the free will really free, and
     * there will be zero memory penalty.
     */
    
    pbuf_free(rambuf);
#endif /* IP_FRAG_USES_STATIC_BUF */
    left -= cop;
    ofo += nfb;
  }
#if IP_FRAG_USES_STATIC_BUF
  pbuf_free(rambuf);
#endif /* IP_FRAG_USES_STATIC_BUF */
  snmp_inc_ipfragoks();
  return ERR_OK;
}
Exemple #5
0
/*-----------------------------------------------------------------------------------*/
static void
unixif_input_handler(void *data)
{
  struct netif *netif;
  struct unixif *unixif;
  char buf[1532], *bufptr;
  int len, plen, rlen;
  struct pbuf *p, *q;

  netif = (struct netif *)data;
  unixif = (struct unixif *)netif->state;

  len = read(unixif->fd, &plen, sizeof(int));
  if (len == -1) {
    perror("unixif_irq_handler: read");
    abort();
  }

//
  printf("unixif_input_handler: len == %d plen == %d bytes | %x \n", len, plen, plen);  
//
  LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_irq_handler: len == %d plen == %d bytes\n", len, plen));  
  if (len == sizeof(int)) {

    if (plen < 20 || plen > 1500) {
      LWIP_DEBUGF(UNIXIF_DEBUG, ("plen %d!\n", plen));
      return;
    }
    
    printf("[+] Reading IP-packet from lower socket\n");

    len = read(unixif->fd, buf, plen);
    if (len == -1) {
      perror("unixif_irq_handler: read");
      abort();
    }
//
    printf("unixif_irq_handler: read %d bytes\n", len);
//
    LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_irq_handler: read %d bytes\n", len));
    p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL);

    if (p != NULL) {
      rlen = len;
      bufptr = buf;
      q = p;
      while (rlen > 0) {
        memcpy(q->payload, bufptr, rlen > q->len? q->len: rlen);
        rlen -= q->len;
        bufptr += q->len;
        q = q->next;
      }
      pbuf_realloc(p, len);
      LINK_STATS_INC(link.recv);
      tcpdump(p);
      
      // formated printout of packet payload
      int i=0;
      for(i=0; i < p->len; i++) {
        printf("%02x ", (*((char *)p->payload + i) & 0xff));
        if (((i + 1) % 8) == 0) {
          printf("\n");
        }
      }
      printf("\n");
      
      // call input-handler of lwip
      netif->input(p, netif);

    } else {
      LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_irq_handler: could not allocate pbuf\n"));
    }


  }
}
Exemple #6
0
/**
 * Receive callback function for RAW netconns.
 * Doesn't 'eat' the packet, only references it and sends it to
 * conn->recvmbox
 *
 * @see raw.h (struct raw_pcb.recv) for parameters and return value
 */
static u8_t
recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
    struct ip_addr *addr)
{
  struct pbuf *q;
  struct netbuf *buf;
  struct netconn *conn;
#if LWIP_SO_RCVBUF
  int recv_avail;
#endif /* LWIP_SO_RCVBUF */

  LWIP_UNUSED_ARG(addr);
  conn = arg;

#if LWIP_SO_RCVBUF
  SYS_ARCH_GET(conn->recv_avail, recv_avail);
  if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL) &&
      ((recv_avail + (int)(p->tot_len)) <= conn->recv_bufsize)) {
#else  /* LWIP_SO_RCVBUF */
  if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL)) {
#endif /* LWIP_SO_RCVBUF */
    /* copy the whole packet into new pbufs */
    q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
    if(q != NULL) {
      if (pbuf_copy(q, p) != ERR_OK) {
        pbuf_free(q);
        q = NULL;
      }
    }

    if(q != NULL) {
      buf = memp_malloc(MEMP_NETBUF);
      if (buf == NULL) {
        pbuf_free(q);
        return 0;
      }

      buf->p = q;
      buf->ptr = q;
      buf->addr = &(((struct ip_hdr*)(q->payload))->src);
      buf->port = pcb->protocol;

      if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
        netbuf_delete(buf);
        return 0;
      } else {
        SYS_ARCH_INC(conn->recv_avail, q->tot_len);
        /* Register event with callback */
        API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len);
      }
    }
  }

  return 0; /* do not eat the packet */
}
#endif /* LWIP_RAW*/

#if LWIP_UDP
/**
 * Receive callback function for UDP netconns.
 * Posts the packet to conn->recvmbox or deletes it on memory error.
 *
 * @see udp.h (struct udp_pcb.recv) for parameters
 */
static void
recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
   struct ip_addr *addr, u16_t port)
{
  struct netbuf *buf;
  struct netconn *conn;
#if LWIP_SO_RCVBUF
  int recv_avail;
#endif /* LWIP_SO_RCVBUF */

  LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
  LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
  LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
  conn = arg;
  LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);

#if LWIP_SO_RCVBUF
  SYS_ARCH_GET(conn->recv_avail, recv_avail);
  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL) ||
      ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
#else  /* LWIP_SO_RCVBUF */
  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {
#endif /* LWIP_SO_RCVBUF */
    pbuf_free(p);
    return;
  }

  buf = memp_malloc(MEMP_NETBUF);
  if (buf == NULL) {
    pbuf_free(p);
    return;
  } else {
    buf->p = p;
    buf->ptr = p;
    buf->addr = addr;
    buf->port = port;
#if LWIP_NETBUF_RECVINFO
    {
      const struct ip_hdr* iphdr = ip_current_header();
      /* get the UDP header - always in the first pbuf, ensured by udp_input */
      const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr));
      buf->toaddr = (struct ip_addr*)&iphdr->dest;
      buf->toport = udphdr->dest;
    }
#endif /* LWIP_NETBUF_RECVINFO */
  }

  if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
    netbuf_delete(buf);
    return;
  } else {
    SYS_ARCH_INC(conn->recv_avail, p->tot_len);
    /* Register event with callback */
    API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len);
  }
}
#endif /* LWIP_UDP */

#if LWIP_TCP
/**
 * Receive callback function for TCP netconns.
 * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
 *
 * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
 */
static err_t
recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
  struct netconn *conn;
  u16_t len;

  LWIP_UNUSED_ARG(pcb);
  LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
  LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
  conn = arg;
  LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);

  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {
    return ERR_VAL;
  }

  conn->err = err;
  if (p != NULL) {
    len = p->tot_len;
    SYS_ARCH_INC(conn->recv_avail, len);
  } else {
    len = 0;
  }

  if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) {
    return ERR_MEM;
  } else {
    /* Register event with callback */
    API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
  }

  return ERR_OK;
}

/**
 * Poll callback function for TCP netconns.
 * Wakes up an application thread that waits for a connection to close
 * or data to be sent. The application thread then takes the
 * appropriate action to go on.
 *
 * Signals the conn->sem.
 * netconn_close waits for conn->sem if closing failed.
 *
 * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
 */
static err_t
poll_tcp(void *arg, struct tcp_pcb *pcb)
{
  struct netconn *conn = arg;

  LWIP_UNUSED_ARG(pcb);
  LWIP_ASSERT("conn != NULL", (conn != NULL));

  if (conn->state == NETCONN_WRITE) {
    do_writemore(conn);
  } else if (conn->state == NETCONN_CLOSE) {
    do_close_internal(conn);
  }

  return ERR_OK;
}

/**
 * Sent callback function for TCP netconns.
 * Signals the conn->sem and calls API_EVENT.
 * netconn_write waits for conn->sem if send buffer is low.
 *
 * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
 */
static err_t
sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
{
  struct netconn *conn = arg;

  LWIP_UNUSED_ARG(pcb);
  LWIP_ASSERT("conn != NULL", (conn != NULL));

  if (conn->state == NETCONN_WRITE) {
    LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
    do_writemore(conn);
  } else if (conn->state == NETCONN_CLOSE) {
    do_close_internal(conn);
  }

  if (conn) {
    if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)) {
      API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
    }
  }
  
  return ERR_OK;
}

/**
 * Error callback function for TCP netconns.
 * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
 * The application thread has then to decide what to do.
 *
 * @see tcp.h (struct tcp_pcb.err) for parameters
 */
static void
err_tcp(void *arg, err_t err)
{
  struct netconn *conn;

  conn = arg;
  LWIP_ASSERT("conn != NULL", (conn != NULL));

  conn->pcb.tcp = NULL;

  conn->err = err;
  if (conn->recvmbox != SYS_MBOX_NULL) {
    /* Register event with callback */
    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
    sys_mbox_post(conn->recvmbox, NULL);
  }
  if (conn->op_completed != SYS_SEM_NULL && conn->state == NETCONN_CONNECT) {
    conn->state = NETCONN_NONE;
    sys_sem_signal(conn->op_completed);
  }
  if (conn->acceptmbox != SYS_MBOX_NULL) {
    /* Register event with callback */
    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
    sys_mbox_post(conn->acceptmbox, NULL);
  }
  if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) {
    /* calling do_writemore/do_close_internal is not necessary
       since the pcb has already been deleted! */
    conn->state = NETCONN_NONE;
    /* wake up the waiting task */
    sys_sem_signal(conn->op_completed);
  }
}

/**
 * Setup a tcp_pcb with the correct callback function pointers
 * and their arguments.
 *
 * @param conn the TCP netconn to setup
 */
static void
setup_tcp(struct netconn *conn)
{
  struct tcp_pcb *pcb;

  pcb = conn->pcb.tcp;
  tcp_arg(pcb, conn);
  tcp_recv(pcb, recv_tcp);
  tcp_sent(pcb, sent_tcp);
  tcp_poll(pcb, poll_tcp, 4);
  tcp_err(pcb, err_tcp);
}

/**
 * Accept callback function for TCP netconns.
 * Allocates a new netconn and posts that to conn->acceptmbox.
 *
 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
 */
static err_t
accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
{
  struct netconn *newconn;
  struct netconn *conn;

#if API_MSG_DEBUG
#if TCP_DEBUG
  tcp_debug_print_state(newpcb->state);
#endif /* TCP_DEBUG */
#endif /* API_MSG_DEBUG */
  conn = (struct netconn *)arg;

  LWIP_ERROR("accept_function: invalid conn->acceptmbox",
             conn->acceptmbox != SYS_MBOX_NULL, return ERR_VAL;);

  /* We have to set the callback here even though
   * the new socket is unknown. conn->socket is marked as -1. */
  newconn = netconn_alloc(conn->type, conn->callback);
  if (newconn == NULL) {
    return ERR_MEM;
  }
  newconn->pcb.tcp = newpcb;
  setup_tcp(newconn);
  newconn->err = err;

  if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) {
    /* When returning != ERR_OK, the connection is aborted in tcp_process(),
       so do nothing here! */
    newconn->pcb.tcp = NULL;
    netconn_free(newconn);
    return ERR_MEM;
  } else {
    /* Register event with callback */
    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
  }

  return ERR_OK;
}
#endif /* LWIP_TCP */

/**
 * Create a new pcb of a specific type.
 * Called from do_newconn().
 *
 * @param msg the api_msg_msg describing the connection type
 * @return msg->conn->err, but the return value is currently ignored
 */
static err_t
pcb_new(struct api_msg_msg *msg)
{
   msg->conn->err = ERR_OK;

   LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);

   /* Allocate a PCB for this connection */
   switch(NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
   case NETCONN_RAW:
     msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
     if(msg->conn->pcb.raw == NULL) {
       msg->conn->err = ERR_MEM;
       break;
     }
     raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
     break;
#endif /* LWIP_RAW */
#if LWIP_UDP
   case NETCONN_UDP:
     msg->conn->pcb.udp = udp_new();
     if(msg->conn->pcb.udp == NULL) {
       msg->conn->err = ERR_MEM;
       break;
     }
#if LWIP_UDPLITE
     if (msg->conn->type==NETCONN_UDPLITE) {
       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
     }
#endif /* LWIP_UDPLITE */
     if (msg->conn->type==NETCONN_UDPNOCHKSUM) {
       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
     }
     udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
     break;
#endif /* LWIP_UDP */
#if LWIP_TCP
   case NETCONN_TCP:
     msg->conn->pcb.tcp = tcp_new();
     if(msg->conn->pcb.tcp == NULL) {
       msg->conn->err = ERR_MEM;
       break;
     }
     setup_tcp(msg->conn);
     break;
#endif /* LWIP_TCP */
   default:
     /* Unsupported netconn type, e.g. protocol disabled */
     msg->conn->err = ERR_VAL;
     break;
   }

  return msg->conn->err;
}
Exemple #7
0
/**
 * Send an IP packet to be received on the same netif (loopif-like).
 * The pbuf is simply copied and handed back to netif->input.
 * In multithreaded mode, this is done directly since netif->input must put
 * the packet on a queue.
 * In callback mode, the packet is put on an internal queue and is fed to
 * netif->input by netif_poll().
 *
 * @param netif the lwip network interface structure
 * @param p the (IP) packet to 'send'
 * @param ipaddr the ip address to send the packet to (not used)
 * @return ERR_OK if the packet has been sent
 *         ERR_MEM if the pbuf used to copy the packet couldn't be allocated
 */
err_t
netif_loop_output(struct netif *netif, struct pbuf *p,
       struct ip_addr *ipaddr)
{
  struct pbuf *r;
  err_t err;
  struct pbuf *last;
#if LWIP_LOOPBACK_MAX_PBUFS
  u8_t clen = 0;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
  SYS_ARCH_DECL_PROTECT(lev);
  LWIP_UNUSED_ARG(ipaddr);

  /* Allocate a new pbuf */
  r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
  if (r == NULL) {
    return ERR_MEM;
  }
#if LWIP_LOOPBACK_MAX_PBUFS
  clen = pbuf_clen(r);
  /* check for overflow or too many pbuf on queue */
  if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) ||
    ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) {
      pbuf_free(r);
      r = NULL;
      return ERR_MEM;
  }
  netif->loop_cnt_current += clen;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */

  /* Copy the whole pbuf queue p into the single pbuf r */
  if ((err = pbuf_copy(r, p)) != ERR_OK) {
    pbuf_free(r);
    r = NULL;
    return err;
  }

  /* Put the packet on a linked list which gets emptied through calling
     netif_poll(). */

  /* let last point to the last pbuf in chain r */
  for (last = r; last->next != NULL; last = last->next);

  SYS_ARCH_PROTECT(lev);
  if(netif->loop_first != NULL) {
    LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL);
    netif->loop_last->next = r;
    netif->loop_last = last;
  } else {
    netif->loop_first = r;
    netif->loop_last = last;
  }
  SYS_ARCH_UNPROTECT(lev);

#if LWIP_NETIF_LOOPBACK_MULTITHREADING
  /* For multithreading environment, schedule a call to netif_poll */
  tcpip_callback((void (*)(void *))(netif_poll), netif);
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */

  return ERR_OK;
}
/**
 * This function will read a single packet from the Stellaris ethernet
 * interface, if available, and return a pointer to a pbuf.  The timestamp
 * of the packet will be placed into the pbuf structure.
 *
 * @param netif the lwip network interface structure for this ethernetif
 * @return pointer to pbuf packet if available, NULL otherswise.
 */
static struct pbuf *
stellarisif_receive(struct netif *netif)
{
    struct pbuf *p, *q;
    u16_t len;
    u32_t temp;
    int i;
    unsigned long *ptr;
#if LWIP_PTPD
    u32_t time_s, time_ns;

    /* Get the current timestamp if PTPD is enabled */
    lwIPHostGetTime(&time_s, &time_ns);
#endif


    /* Check if a packet is available, if not, return NULL packet. */
    if((HWREG(ETH_BASE + MAC_O_NP) & MAC_NP_NPR_M) == 0) {
        return(NULL);
    }

    /**
     * Obtain the size of the packet and put it into the "len" variable.
     * Note:  The length returned in the FIFO length position includes the
     * two bytes for the length + the 4 bytes for the FCS.
     *
     */
    temp = HWREG(ETH_BASE + MAC_O_DATA);
    len = temp & 0xFFFF;

    /* We allocate a pbuf chain of pbufs from the pool. */
    p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);

    /* If a pbuf was allocated, read the packet into the pbuf. */
    if(p != NULL) {
        /* Place the first word into the first pbuf location. */
        *(unsigned long *)p->payload = temp;
        p->payload = (char *)(p->payload) + 4;
        p->len -= 4;

        /* Process all but the last buffer in the pbuf chain. */
        q = p;
        while(q != NULL) {
            /* Setup a byte pointer into the payload section of the pbuf. */
            ptr = q->payload;

            /**
             * Read data from FIFO into the current pbuf
             * (assume pbuf length is modulo 4)
             *
             */
            for(i = 0; i < q->len; i += 4) {
                *ptr++ = HWREG(ETH_BASE + MAC_O_DATA);
            }

            /* Link in the next pbuf in the chain. */
            q = q->next;
        }

        /* Restore the first pbuf parameters to their original values. */
        p->payload = (char *)(p->payload) - 4;
        p->len += 4;

        /* Adjust the link statistics */
        LINK_STATS_INC(link.recv);

#if LWIP_PTPD
        /* Place the timestamp in the PBUF */
        p->time_s = time_s;
        p->time_ns = time_ns;
#endif
    }

    /* If no pbuf available, just drain the RX fifo. */
    else {
        for(i = 4; i < len; i+=4) {
            temp = HWREG(ETH_BASE + MAC_O_DATA);
        }

        /* Adjust the link statistics */
        LINK_STATS_INC(link.memerr);
        LINK_STATS_INC(link.drop);
    }

    return(p);
}
Exemple #9
0
/** Initialize the connection struct */
static err_t
httpc_init_connection_common(httpc_state_t **connection, const httpc_connection_t *settings, const char* server_name,
                      u16_t server_port, const char* uri, altcp_recv_fn recv_fn, void* callback_arg, int use_host)
{
  size_t alloc_len;
  mem_size_t mem_alloc_len;
  int req_len, req_len2;
  httpc_state_t *req;
#if HTTPC_DEBUG_REQUEST
  size_t server_name_len, uri_len;
#endif

  LWIP_ASSERT("uri != NULL", uri != NULL);

  /* get request len */
  req_len = httpc_create_request_string(settings, server_name, server_port, uri, use_host, NULL, 0);
  if ((req_len < 0) || (req_len > 0xFFFF)) {
    return ERR_VAL;
  }
  /* alloc state and request in one block */
  alloc_len = sizeof(httpc_state_t);
#if HTTPC_DEBUG_REQUEST
  server_name_len = server_name ? strlen(server_name) : 0;
  uri_len = strlen(uri);
  alloc_len += server_name_len + 1 + uri_len + 1;
#endif
  mem_alloc_len = (mem_size_t)alloc_len;
  if ((mem_alloc_len < alloc_len) || (req_len + 1 > 0xFFFF)) {
    return ERR_VAL;
  }

  req = (httpc_state_t*)mem_malloc((mem_size_t)alloc_len);
  if(req == NULL) {
    return ERR_MEM;
  }
  memset(req, 0, sizeof(httpc_state_t));
  req->timeout_ticks = HTTPC_POLL_TIMEOUT;
  req->request = pbuf_alloc(PBUF_RAW, (u16_t)(req_len + 1), PBUF_RAM);
  if (req->request == NULL) {
    httpc_free_state(req);
    return ERR_MEM;
  }
  if (req->request->next != NULL) {
    /* need a pbuf in one piece */
    httpc_free_state(req);
    return ERR_MEM;
  }
  req->hdr_content_len = HTTPC_CONTENT_LEN_INVALID;
#if HTTPC_DEBUG_REQUEST
  req->server_name = (char*)(req + 1);
  if (server_name) {
    memcpy(req->server_name, server_name, server_name_len + 1);
  }
  req->uri = req->server_name + server_name_len + 1;
  memcpy(req->uri, uri, uri_len + 1);
#endif
  req->pcb = altcp_new(settings->altcp_allocator);
  if(req->pcb == NULL) {
    httpc_free_state(req);
    return ERR_MEM;
  }
  req->remote_port = settings->use_proxy ? settings->proxy_port : server_port;
  altcp_arg(req->pcb, req);
  altcp_recv(req->pcb, httpc_tcp_recv);
  altcp_err(req->pcb, httpc_tcp_err);
  altcp_poll(req->pcb, httpc_tcp_poll, HTTPC_POLL_INTERVAL);
  altcp_sent(req->pcb, httpc_tcp_sent);

  /* set up request buffer */
  req_len2 = httpc_create_request_string(settings, server_name, server_port, uri, use_host,
    (char *)req->request->payload, req_len + 1);
  if (req_len2 != req_len) {
    httpc_free_state(req);
    return ERR_VAL;
  }

  req->recv_fn = recv_fn;
  req->conn_settings = settings;
  req->callback_arg = callback_arg;

  *connection = req;
  return ERR_OK;
}
Exemple #10
0
/**
 * Handle the incoming SLIP stream character by character
 *
 * Poll the serial layer by calling sio_recv()
 *
 * @param netif the lwip network interface structure for this slipif
 * @return The IP packet when SLIP_END is received
 */
static struct pbuf *
slipif_input(struct netif *netif)
{
  u8_t c;
  /* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */
  struct pbuf *p, *q;
  u16_t recved;
  u16_t i;

  LWIP_ASSERT("netif != NULL", (netif != NULL));
  LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));

  q = p = NULL;
  recved = i = 0;
  c = 0;

  while (1) {
    c = sio_recv(netif->state);
    switch (c) {
    case SLIP_END:
      if (recved > 0) {
        /* Received whole packet. */
        /* Trim the pbuf to the size of the received packet. */
        pbuf_realloc(q, recved);

        LINK_STATS_INC(link.recv);

        LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet\n"));
        return q;
      }
      break;

    case SLIP_ESC:
      c = sio_recv(netif->state);
      switch (c) {
      case SLIP_ESC_END:
        c = SLIP_END;
        break;
      case SLIP_ESC_ESC:
        c = SLIP_ESC;
        break;
      }
      /* FALLTHROUGH */

    default:
      /* byte received, packet not yet completely received */
      if (p == NULL) {
        /* allocate a new pbuf */
        LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n"));
        p = pbuf_alloc(PBUF_LINK, PBUF_POOL_BUFSIZE, PBUF_POOL);

        if (p == NULL) {
          LINK_STATS_INC(link.drop);
          LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n"));
          /* don't process any further since we got no pbuf to receive to */
          break;
        }

        if (q != NULL) {
          /* 'chain' the pbuf to the existing chain */
          pbuf_cat(q, p);
        } else {
          /* p is the first pbuf in the chain */
          q = p;
        }
      }

      /* this automatically drops bytes if > MAX_SIZE */
      if ((p != NULL) && (recved <= MAX_SIZE)) {
        ((u8_t *)p->payload)[i] = c;
        recved++;
        i++;
        if (i >= p->len) {
          /* on to the next pbuf */
          i = 0;
          if (p->next != NULL && p->next->len > 0) {
            /* p is a chain, on to the next in the chain */
            p = p->next;
          } else {
            /* p is a single pbuf, set it to NULL so next time a new
             * pbuf is allocated */
            p = NULL;
          }
        }
      }
      break;
    }
  }
#if ((COMPILER_TYPE!=IAR) && (COMPILER_TYPE != Keil4))
   return NULL;
#endif
}
Exemple #11
0
Fichier : rpc.c Projet : gapry/AOS
static inline struct pbuf*
pbuf_new(u16_t length)
{
    return pbuf_alloc(PBUF_TRANSPORT, length, PBUF_RAM);
}
Exemple #12
0
/**
 * Send an IP packet to be received on the same netif (loopif-like).
 * The pbuf is simply copied and handed back to netif->input.
 * In multithreaded mode, this is done directly since netif->input must put
 * the packet on a queue.
 * In callback mode, the packet is put on an internal queue and is fed to
 * netif->input by netif_poll().
 *
 * @param netif the lwip network interface structure
 * @param p the (IP) packet to 'send'
 * @param ipaddr the ip address to send the packet to (not used)
 * @return ERR_OK if the packet has been sent
 *         ERR_MEM if the pbuf used to copy the packet couldn't be allocated
 */
err_t
netif_loop_output(struct netif *netif, struct pbuf *p,
       ip_addr_t *ipaddr)
{
  struct pbuf *r;
  err_t err;
  struct pbuf *last;
#if LWIP_LOOPBACK_MAX_PBUFS
  u8_t clen = 0;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
  /* If we have a loopif, SNMP counters are adjusted for it,
   * if not they are adjusted for 'netif'. */
#if LWIP_SNMP
#if LWIP_HAVE_LOOPIF
  struct netif *stats_if = &loop_netif;
#else /* LWIP_HAVE_LOOPIF */
  struct netif *stats_if = netif;
#endif /* LWIP_HAVE_LOOPIF */
#endif /* LWIP_SNMP */
  SYS_ARCH_DECL_PROTECT(lev);
  LWIP_UNUSED_ARG(ipaddr);

  /* Allocate a new pbuf */
  r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM, netif->prot_thread);
  if (r == NULL) {
    LINK_STATS_INC(link.memerr);
    LINK_STATS_INC(link.drop);
    snmp_inc_ifoutdiscards(stats_if);
    return ERR_MEM;
  }
#if LWIP_LOOPBACK_MAX_PBUFS
  clen = pbuf_clen(r);
  /* check for overflow or too many pbuf on queue */
  if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) ||
     ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) {
    pbuf_free(r, netif->prot_thread);
    LINK_STATS_INC(link.memerr);
    LINK_STATS_INC(link.drop);
    snmp_inc_ifoutdiscards(stats_if);
    return ERR_MEM;
  }
  netif->loop_cnt_current += clen;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */

  /* Copy the whole pbuf queue p into the single pbuf r */
  if ((err = pbuf_copy(r, p)) != ERR_OK) {
    pbuf_free(r, netif->prot_thread);
    LINK_STATS_INC(link.memerr);
    LINK_STATS_INC(link.drop);
    snmp_inc_ifoutdiscards(stats_if);
    return err;
  }

  /* Put the packet on a linked list which gets emptied through calling
     netif_poll(). */

  /* let last point to the last pbuf in chain r */
  for (last = r; last->next != NULL; last = last->next);

  SYS_ARCH_PROTECT(lev);
  if(netif->loop_first != NULL) {
    LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL);
    netif->loop_last->next = r;
    netif->loop_last = last;
  } else {
    netif->loop_first = r;
    netif->loop_last = last;
  }
  SYS_ARCH_UNPROTECT(lev);

  LINK_STATS_INC(link.xmit);
  snmp_add_ifoutoctets(stats_if, p->tot_len);
  snmp_inc_ifoutucastpkts(stats_if);

#if LWIP_NETIF_LOOPBACK_MULTITHREADING
  /* For multithreading environment, schedule a call to netif_poll */
  tcpip_callback((tcpip_callback_fn)netif_poll, netif);
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */

  return ERR_OK;
}
Exemple #13
0
static int rtl8139_rx(struct dev *dev) {
  struct nic *tp = (struct nic *) dev->privdata;
  long ioaddr = tp->iobase;
  unsigned char *rx_ring = tp->rx_ring;
  unsigned short cur_rx = tp->cur_rx;

  //kprintf("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x, free to %4.4x, Cmd %2.2x\n",
  //  dev->name, cur_rx, inpw(ioaddr + RxBufAddr),
  //  inpw(ioaddr + RxBufPtr), inp(ioaddr + ChipCmd));

  while ((inp(ioaddr + ChipCmd) & RxBufEmpty) == 0) {
    unsigned int ring_offset = cur_rx % tp->rx_buf_len;
    unsigned long rx_status = *(unsigned long *)(rx_ring + ring_offset);
    unsigned int rx_size = rx_status >> 16;        // Includes the CRC

    //{
    //  int i;
    //  kprintf("%s:  rtl8139_rx() status %4.4x, size %4.4x, cur %4.4x\n", dev->name, rx_status, rx_size, cur_rx);
    //  kprintf("%s: Frame contents ", dev->name);
    //  for (i = 0; i < 70; i++) kprintf(" %2.2x", rx_ring[ring_offset + i]);
    //  kprintf("\n");
    //}

    if (rx_status & (RxBadSymbol | RxRunt | RxTooLong | RxCRCErr | RxBadAlign)) {
      kprintf("%s: Ethernet frame had errors, status %8.8x\n", dev->name, rx_status);

      if (rx_status == 0xffffffff) {
        kprintf("%s: Invalid receive status at ring offset %4.4x\n", dev->name, ring_offset);
        rx_status = 0;
      }

      if (rx_status & RxTooLong) {
        kprintf("%s: Oversized Ethernet frame, status %4.4x!\n", dev->name, rx_status);

        // The chip hangs here.
        // This should never occur, which means that we are screwed when it does
      }

      tp->stats.rx_errors++;
      if (rx_status & (RxBadSymbol | RxBadAlign)) tp->stats.rx_frame_errors++;
      if (rx_status & (RxRunt | RxTooLong)) tp->stats.rx_length_errors++;
      if (rx_status & RxCRCErr) tp->stats.rx_crc_errors++;
      
      // Reset the receiver, based on RealTek recommendation. (Bug?)
      tp->cur_rx = 0;
      outp(ioaddr + ChipCmd, CmdTxEnb);
      
      // Reset the multicast list
      rtl8139_set_rx_mode(dev);
      outp(ioaddr + ChipCmd, CmdRxEnb | CmdTxEnb);
    } else {
      // Allocate new pbuf
      // Omit the four octet CRC from the length
      struct pbuf *p;
      int pkt_size = rx_size - 4;

      p = pbuf_alloc(PBUF_RAW, pkt_size, PBUF_RW);
      if (p == NULL) {
        kprintf("%s: Memory squeeze, deferring packet.\n", dev->name);
        
        // We should check that some rx space is free.
        // If not, free one and mark stats->rx_dropped
        tp->stats.rx_dropped++;
        break;
      }
      
      if (ring_offset + rx_size > tp->rx_buf_len) {
        int semi_count = tp->rx_buf_len - ring_offset - 4;
        
        memcpy(p->payload, &rx_ring[ring_offset + 4], semi_count);
        memcpy((char *) p->payload + semi_count, rx_ring, pkt_size - semi_count);
      } else {
        memcpy(p->payload, &rx_ring[ring_offset + 4], pkt_size);
      }

      // Send packet to upper layer
      if (dev_receive(tp->devno, p) < 0) pbuf_free(p);

      tp->stats.rx_bytes += pkt_size;
      tp->stats.rx_packets++;
    }

    cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
    outpw(ioaddr + RxBufPtr, cur_rx - 16);
  }

  //kprintf("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x, free to %4.4x, Cmd %2.2x\n",
  //  dev->name, cur_rx, inpw(ioaddr + RxBufAddr),
  //  inpw(ioaddr + RxBufPtr), inp(ioaddr + ChipCmd));

  tp->cur_rx = cur_rx;
  return 0;
}
Exemple #14
0
/**
 *  @brief This function processes received packet and forwards it
 *  to kernel/upper layer
 *  
 *  @param priv    A pointer to wlan_private
 *  @param skb     A pointer to skb which includes the received packet
 *  @return 	   WLAN_STATUS_SUCCESS or WLAN_STATUS_FAILURE
 */
void ProcessRxedPacket(WlanCard *cardinfo,u8 *data,u32 len)
{
	struct pbuf* p = RT_NULL;
	RxPacketHdr_t *pRxPkt;
	RxPD *pRxPD;
	u32 pbuflen;
	int hdrChop;
	int minlen;
	EthII_Hdr_t *pEthHdr;
	Rx_Pbuf_List *RxNode = NULL;
	rt_base_t level;
	WlanCard *card = cardinfo;
	Rx_Pbuf_List *HeadNode = &card->RxList;
	const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };

	RxNode = rt_malloc(sizeof(RxNode));
	if (RxNode == NULL)
	{
		WlanDebug(WlanErr,"RX packet Error: memory alloc failed\r\n");
		goto done;
	}

	pRxPD = (RxPD *) data;
	pRxPkt = (RxPacketHdr_t *) ((u8 *) pRxPD + pRxPD->PktOffset);
	/*mac source address :6byte  .mac destination address :6byte. length 2 bytes =14*/
	minlen = (8 + 4 + (pRxPD->PktOffset));
	if (len < minlen)
	{
		WlanDebug( WlanErr,"RX Error: packet length is too long\n");
		rt_free(RxNode);
		goto done;
	}

	WlanDebug(WlanData, "RX Data:%d\n",len - pRxPD->PktOffset);
	WlanDebug(WlanData, "SNR: %d, NF: %d\n", pRxPD->SNR, pRxPD->NF);
	WlanDebug(WlanData,"RX Data Dest \r\n %x,%x,%x,%x,%x,%x\r\n", pRxPkt->eth803_hdr.dest_addr[0],
			pRxPkt->eth803_hdr.dest_addr[1],
			pRxPkt->eth803_hdr.dest_addr[2],
			pRxPkt->eth803_hdr.dest_addr[3],
			pRxPkt->eth803_hdr.dest_addr[4],
			pRxPkt->eth803_hdr.dest_addr[5]);
	WlanDebug(WlanData,"RX Data Src\r\n %x,%x,%x,%x,%x,%x\r\n", pRxPkt->eth803_hdr.src_addr[0],
			pRxPkt->eth803_hdr.src_addr[1],
			pRxPkt->eth803_hdr.src_addr[2],
			pRxPkt->eth803_hdr.src_addr[3],
			pRxPkt->eth803_hdr.src_addr[4],
			pRxPkt->eth803_hdr.src_addr[5]);

	if (rt_memcmp(&pRxPkt->rfc1042_hdr, rfc1042_eth_hdr,
			sizeof(rfc1042_eth_hdr)) == 0)
	{
		/*
		 *  Replace the 803 header and rfc1042 header (llc/snap) with an
		 *    EthernetII header, keep the src/dst and snap_type (ethertype)
		 *
		 *  The firmware only passes up SNAP frames converting
		 *    all RX Data from 802.11 to 802.2/LLC/SNAP frames.
		 *
		 *  To create the Ethernet II, just move the src, dst address right
		 *    before the snap_type.
		 */
		pEthHdr = (EthII_Hdr_t *) ((u8 *) &pRxPkt->eth803_hdr
				+ sizeof(pRxPkt->eth803_hdr) + sizeof(pRxPkt->rfc1042_hdr)
				- sizeof(pRxPkt->eth803_hdr.dest_addr)
				- sizeof(pRxPkt->eth803_hdr.src_addr)
				- sizeof(pRxPkt->rfc1042_hdr.snap_type));

		rt_memcpy(pEthHdr->src_addr, pRxPkt->eth803_hdr.src_addr,
				sizeof(pEthHdr->src_addr));
		rt_memcpy(pEthHdr->dest_addr, pRxPkt->eth803_hdr.dest_addr,
				sizeof(pEthHdr->dest_addr));

		/* Chop off the RxPD + the excess memory from the 802.2/llc/snap header
		 *   that was removed
		 */
		hdrChop = (u8 *) pEthHdr - (u8 *) pRxPD;
	}
	else
	{
		hexdump("RX Data: LLC/SNAP", (u8 *) &pRxPkt->rfc1042_hdr,
				sizeof(pRxPkt->rfc1042_hdr));

		/* Chop off the RxPD */
		hdrChop = (u8 *) &pRxPkt->eth803_hdr - (u8 *) pRxPD;
		rt_free(RxNode);
	}

	/* Chop off the leading header bytes so the skb points to the start of
	 *   either the reconstructed EthII frame or the 802.2/llc/snap frame
	 */

	pbuflen = (len - hdrChop);
	if (pbuflen < 100)
		pbuflen = 100;
	p = pbuf_alloc(PBUF_LINK, pbuflen, PBUF_RAM);
	if (p == RT_NULL)
	{
		WlanDebug(WlanErr,"alloc pbuf failed length %d",pbuflen);
		rt_free(RxNode);
		return;
	}
	rt_memcpy(p->payload, (u8*) ((u32) pRxPD + hdrChop), pbuflen);
	RxNode->p = p;

	level = rt_hw_interrupt_disable();
	if (HeadNode->next == HeadNode)
	{
		HeadNode->next = RxNode;
		HeadNode->pre = RxNode;
		RxNode->next = HeadNode;
		RxNode->pre = HeadNode;
	}
	else
	{
		HeadNode->pre->next = RxNode;
		RxNode->pre = HeadNode->pre;
		HeadNode->pre = RxNode;
		RxNode->next = HeadNode;
	}
	card->RxQueueCount++;
	rt_hw_interrupt_enable(level);

done:
	return;
}
Exemple #15
0
static void
dhcp6ds_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p,
             ip6_addr_t *addr, u16_t port)
{
    u8_t msg_header[4];
    unsigned int msg_type, msg_tid;
    int copied;
    size_t roff;
    struct pbuf *q;
    err_t error;

    LWIP_UNUSED_ARG(arg);
    LWIP_ASSERT1(p != NULL);

    copied = pbuf_copy_partial(p, msg_header, sizeof(msg_header), 0);
    if (copied != sizeof(msg_header)) {
        DPRINTF(("%s: message header truncated\n", __func__));
        pbuf_free(p);
        return;
    }
    pbuf_header(p, -(s16_t)sizeof(msg_header));

    msg_type = msg_header[0];
    msg_tid = (msg_header[1] << 16) | (msg_header[2] << 8) | msg_header[3];
    DPRINTF(("%s: type %u, tid 0x%6x\n", __func__, msg_type, msg_tid));
    if (msg_type != DHCP6_INFORMATION_REQUEST) { /* TODO:? RELAY_FORW */
        pbuf_free(p);
        return;
    }

    roff = 0;

    msg_header[0] = DHCP6_REPLY;
    memcpy(dhcp6ds_reply_buf + roff, msg_header, sizeof(msg_header));
    roff += sizeof(msg_header);


    /* loop over options */
    while (p->tot_len > 0) {
        u16_t opt, optlen;

        /* fetch option code */
        copied = pbuf_copy_partial(p, &opt, sizeof(opt), 0);
        if (copied != sizeof(opt)) {
            DPRINTF(("%s: option header truncated\n", __func__));
            pbuf_free(p);
            return;
        }
        pbuf_header(p, -(s16_t)sizeof(opt));
        opt = ntohs(opt);

        /* fetch option length */
        copied = pbuf_copy_partial(p, &optlen, sizeof(optlen), 0);
        if (copied != sizeof(optlen)) {
            DPRINTF(("%s: option %u length truncated\n", __func__, opt));
            pbuf_free(p);
            return;
        }
        pbuf_header(p, -(s16_t)sizeof(optlen));
        optlen = ntohs(optlen);

        /* enough data? */
        if (optlen > p->tot_len) {
            DPRINTF(("%s: option %u truncated: expect %u, got %u\n",
                     __func__, opt, optlen, p->tot_len));
            pbuf_free(p);
            return;
        }

        DPRINTF2(("%s: option %u length %u\n", __func__, opt, optlen));

        if (opt == DHCP6_OPTION_CLIENTID) {
            u16_t s;

            /* "A DUID can be no more than 128 octets long (not
               including the type code)." */
            if (optlen > 130) {
                DPRINTF(("%s: client DUID too long: %u\n", __func__, optlen));
                pbuf_free(p);
                return;
            }

            s = PP_HTONS(DHCP6_OPTION_CLIENTID);
            memcpy(dhcp6ds_reply_buf + roff, &s, sizeof(s));
            roff += sizeof(s);

            s = ntohs(optlen);
            memcpy(dhcp6ds_reply_buf + roff, &s, sizeof(s));
            roff += sizeof(s);

            pbuf_copy_partial(p, dhcp6ds_reply_buf + roff, optlen, 0);
            roff += optlen;
        }
        else if (opt == DHCP6_OPTION_ORO) {
            u16_t *opts;
            int i, nopts;

            if (optlen % 2 != 0) {
                DPRINTF2(("%s: Option Request of odd length\n", __func__));
                goto bad_oro;
            }
            nopts = optlen / 2;

            opts = (u16_t *)malloc(optlen);
            if (opts == NULL) {
                DPRINTF2(("%s: failed to allocate space for Option Request\n",
                          __func__));
                goto bad_oro;
            }

            pbuf_copy_partial(p, opts, optlen, 0);
            for (i = 0; i < nopts; ++i) {
                opt = ntohs(opts[i]);
                DPRINTF2(("> request option %u\n", opt));
            };
            free(opts);

          bad_oro: /* empty */;
        }

        pbuf_header(p, -optlen); /* go to next option */
    }
    pbuf_free(p);               /* done */


    memcpy(dhcp6ds_reply_buf + roff, dhcp6ds_serverid, sizeof(dhcp6ds_serverid));
    roff += sizeof(dhcp6ds_serverid);

    memcpy(dhcp6ds_reply_buf + roff, dhcp6ds_dns, sizeof(dhcp6ds_dns));
    roff += sizeof(dhcp6ds_dns);

    q = pbuf_alloc(PBUF_RAW, roff, PBUF_RAM);
    if (q == NULL) {
        DPRINTF(("%s: pbuf_alloc(%d) failed\n", __func__, (int)roff));
        return;
    }

    error = pbuf_take(q, dhcp6ds_reply_buf, roff);
    if (error != ERR_OK) {
        DPRINTF(("%s: pbuf_take(%d) failed: %s\n",
                 __func__, (int)roff, proxy_lwip_strerr(error)));
        pbuf_free(q);
        return;
    }

    error = udp_sendto_ip6(pcb, q, addr, port);
    if (error != ERR_OK) {
        DPRINTF(("%s: udp_sendto failed: %s\n",
                 __func__, proxy_lwip_strerr(error)));
    }

    pbuf_free(q);
}
Exemple #16
0
/**
 * Should allocate a pbuf and transfer the bytes of the incoming
 * packet from the interface into the pbuf.
 *
 * @param netif the lwip network interface structure for this ethernetif
 * @return a pbuf filled with the received packet (including MAC header)
 *         NULL on memory error
 */
static struct pbuf *low_level_input(struct netif *netif)
{
  struct pbuf             *p = NULL;
  struct pbuf             *q;
  u16_t                   len;
  static xSemaphoreHandle xRxSemaphore = NULL;


  /* Parameter not used. */
  ( void ) netif;

  if( xRxSemaphore == NULL )
  {
    vSemaphoreCreateBinary( xRxSemaphore );
  }

  /* Access to the MACB is guarded using a semaphore. */
  if( xSemaphoreTake( xRxSemaphore, netifGUARD_BLOCK_NBTICKS ) )
  {
    /* Obtain the size of the packet. */
    len = ulMACBInputLength();

    if( len )
    {
#if ETH_PAD_SIZE
      len += ETH_PAD_SIZE;    /* allow room for Ethernet padding */
#endif

      /* We allocate a pbuf chain of pbufs from the pool. */
      p = pbuf_alloc( PBUF_RAW, len, PBUF_POOL );

      if( p != NULL )
      {
#if ETH_PAD_SIZE
        pbuf_header( p, -ETH_PAD_SIZE );    /* drop the padding word */
#endif

        /* Let the driver know we are going to read a new packet. */
        vMACBRead( NULL, 0, len );

        /* We iterate over the pbuf chain until we have read the entire
        packet into the pbuf. */
        for( q = p; q != NULL; q = q->next )
        {
          /* Read enough bytes to fill this pbuf in the chain. The
          available data in the pbuf is given by the q->len variable. */
          vMACBRead( q->payload, q->len, len );
        }

#if ETH_PAD_SIZE
        pbuf_header( p, ETH_PAD_SIZE );     /* reclaim the padding word */
#endif
        LINK_STATS_INC(link.recv);
      }
      else
      {
        LINK_STATS_INC(link.memerr);
        LINK_STATS_INC(link.drop);
      }
    }
    xSemaphoreGive( xRxSemaphore );
  }

  return p;
}
/**
 *
 * Create PBUF_POOL (or PBUF_RAM) copies of PBUF_REF pbufs.
 *
 * Used to queue packets on behalf of the lwIP stack, such as
 * ARP based queueing.
 *
 * Go through a pbuf chain and replace any PBUF_REF buffers
 * with PBUF_POOL (or PBUF_RAM) pbufs, each taking a copy of
 * the referenced data.
 *
 * @note You MUST explicitly use p = pbuf_take(p);
 * The pbuf you give as argument, may have been replaced
 * by a (differently located) copy through pbuf_take()!
 *
 * @note Any replaced pbufs will be freed through pbuf_free().
 * This may deallocate them if they become no longer referenced.
 *
 * @param p Head of pbuf chain to process
 *
 * @return Pointer to head of pbuf chain
 */
struct pbuf *
pbuf_take(struct pbuf *p)
{
  struct pbuf *q , *prev, *head;
  LWIP_ASSERT("pbuf_take: p != NULL\n", p != NULL);
  LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 3, ("pbuf_take(%p)\n", (void*)p));

  prev = NULL;
  head = p;
  /* iterate through pbuf chain */
  do
  {
    /* pbuf is of type PBUF_REF? */
    if (p->flags == PBUF_FLAG_REF) {
      LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE, ("pbuf_take: encountered PBUF_REF %p\n", (void *)p));
      /* allocate a pbuf (w/ payload) fully in RAM */
      /* PBUF_POOL buffers are faster if we can use them */
      if (p->len <= PBUF_POOL_BUFSIZE) {
        q = pbuf_alloc(PBUF_RAW, p->len, PBUF_POOL);
        if (q == NULL) {
          LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_POOL\n"));
        }
      } else {
        /* no replacement pbuf yet */
        q = NULL;
        LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: PBUF_POOL too small to replace PBUF_REF\n"));
      }
      /* no (large enough) PBUF_POOL was available? retry with PBUF_RAM */
      if (q == NULL) {
        q = pbuf_alloc(PBUF_RAW, p->len, PBUF_RAM);
        if (q == NULL) {
          LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 2, ("pbuf_take: Could not allocate PBUF_RAM\n"));
        }
      }
      /* replacement pbuf could be allocated? */
      if (q != NULL)
      {
        /* copy p to q */
        /* copy successor */
        q->next = p->next;
        /* remove linkage from original pbuf */
        p->next = NULL;
        /* remove linkage to original pbuf */
        if (prev != NULL) {
          /* prev->next == p at this point */
          LWIP_ASSERT("prev->next == p", prev->next == p);
          /* break chain and insert new pbuf instead */
          prev->next = q;
        /* prev == NULL, so we replaced the head pbuf of the chain */
        } else {
          head = q;
        }
        /* copy pbuf payload */
        memcpy(q->payload, p->payload, p->len);
        q->tot_len = p->tot_len;
        q->len = p->len;
        /* in case p was the first pbuf, it is no longer refered to by
         * our caller, as the caller MUST do p = pbuf_take(p);
         * in case p was not the first pbuf, it is no longer refered to
         * by prev. we can safely free the pbuf here.
         * (note that we have set p->next to NULL already so that
         * we will not free the rest of the chain by accident.)
         */
        pbuf_free(p);
        /* do not copy ref, since someone else might be using the old buffer */
        LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_take: replaced PBUF_REF %p with %p\n", (void *)p, (void *)q));
        p = q;
      } else {
        /* deallocate chain */
        pbuf_free(head);
        LWIP_DEBUGF(PBUF_DEBUG | 2, ("pbuf_take: failed to allocate replacement pbuf for %p\n", (void *)p));
        return NULL;
      }
    /* p->flags != PBUF_FLAG_REF */
    } else {
      LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: skipping pbuf not of type PBUF_REF\n"));
    }
    /* remember this pbuf */
    prev = p;
    /* proceed to next pbuf in original chain */
    p = p->next;
  } while (p);
  LWIP_DEBUGF(PBUF_DEBUG | DBG_TRACE | 1, ("pbuf_take: end of chain reached.\n"));

  return head;
}
Exemple #18
0
static int
pxudp_pmgr_pump(struct pollmgr_handler *handler, SOCKET fd, int revents)
{
    struct pxudp *pxudp;
    struct pbuf *p;
    ssize_t nread;
    err_t error;

    pxudp = (struct pxudp *)handler->data;
    LWIP_ASSERT1(handler == &pxudp->pmhdl);
    LWIP_ASSERT1(fd == pxudp->sock);
    LWIP_UNUSED_ARG(fd);


    if (revents & ~(POLLIN|POLLERR)) {
        DPRINTF(("%s: unexpected revents 0x%x\n", __func__, revents));
        return pxudp_schedule_delete(pxudp);
    }

    /*
     * XXX: AFAICS, there's no way to match the error with the
     * outgoing datagram that triggered it, since we do non-blocking
     * sends from lwip thread.
     */
    if (revents & POLLERR) {
        int sockerr = -1;
        socklen_t optlen = (socklen_t)sizeof(sockerr);
        int status;

        status = getsockopt(pxudp->sock, SOL_SOCKET,
                            SO_ERROR, (char *)&sockerr, &optlen);
        if (status < 0) {
            DPRINTF(("%s: sock %d: SO_ERROR failed with errno %d\n",
                     __func__, pxudp->sock, errno));
        }
        else {
            DPRINTF(("%s: sock %d: errno %d\n",
                     __func__, pxudp->sock, sockerr));
        }
    }

    if ((revents & POLLIN) == 0) {
        return POLLIN;
    }

    nread = recv(pxudp->sock, pollmgr_udpbuf, sizeof(pollmgr_udpbuf), 0);
    if (nread == SOCKET_ERROR) {
        perror(__func__);
        return POLLIN;
    }

    p = pbuf_alloc(PBUF_RAW, (u16_t)nread, PBUF_RAM);
    if (p == NULL) {
        DPRINTF(("%s: pbuf_alloc(%d) failed\n", __func__, (int)nread));
        return POLLIN;
    }

    error = pbuf_take(p, pollmgr_udpbuf, (u16_t)nread);
    if (error != ERR_OK) {
        DPRINTF(("%s: pbuf_take(%d) failed\n", __func__, (int)nread));
        pbuf_free(p);
        return POLLIN;
    }

    error = sys_mbox_trypost(&pxudp->inmbox, p);
    if (error != ERR_OK) {
        pbuf_free(p);
        return POLLIN;
    }

    proxy_lwip_post(&pxudp->msg_inbound);

    return POLLIN;
}
Exemple #19
0
/** \brief  Low level output of a packet. Never call this from an
 *          interrupt context, as it may block until TX descriptors
 *          become available.
 *
 *  \param[in] netif the lwip network interface structure for this lpc_enetif
 *  \param[in] p the MAC packet to send (e.g. IP packet including MAC addresses and type)
 *  \return ERR_OK if the packet could be sent or an err_t value if the packet couldn't be sent
 */
static err_t lpc_low_level_output(struct netif *netif, struct pbuf *p)
{
	struct lpc_enetdata *lpc_enetif = netif->state;
	struct pbuf *q;
	u8_t *dst;
    u32_t idx, notdmasafe = 0;
	struct pbuf *np;
	s32_t dn;

	/* Zero-copy TX buffers may be fragmented across mutliple payload
	   chains. Determine the number of descriptors needed for the
	   transfer. The pbuf chaining can be a mess! */
	dn = (s32_t) pbuf_clen(p);

	/* Test to make sure packet addresses are DMA safe. A DMA safe
	   address is once that uses external memory or periphheral RAM.
	   IRAM and FLASH are not safe! */
	for (q = p; q != NULL; q = q->next)
		notdmasafe += lpc_packet_addr_notsafe(q->payload);

#if LPC_TX_PBUF_BOUNCE_EN==1
	/* If the pbuf is not DMA safe, a new bounce buffer (pbuf) will be
	   created that will be used instead. This requires an copy from the
	   non-safe DMA region to the new pbuf */
	if (notdmasafe) {
		/* Allocate a pbuf in DMA memory */
		np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
		if (np == NULL)
			return ERR_MEM;

		/* This buffer better be contiguous! */
		LWIP_ASSERT("lpc_low_level_output: New transmit pbuf is chained",
			(pbuf_clen(np) == 1));

		/* Copy to DMA safe pbuf */
		dst = (u8_t *) np->payload;
	 	for(q = p; q != NULL; q = q->next) {
			/* Copy the buffer to the descriptor's buffer */
	  		MEMCPY(dst, (u8_t *) q->payload, q->len);
		  dst += q->len;
		}
		np->len = p->tot_len;

		LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
			("lpc_low_level_output: Switched to DMA safe buffer, old=%p, new=%p\n",
			q, np));

		/* use the new buffer for descrptor queueing. The original pbuf will
		   be de-allocated outsuide this driver. */
		p = np;
		dn = 1;
	}
#else
	if (notdmasafe)
		LWIP_ASSERT("lpc_low_level_output: Not a DMA safe pbuf",
			(notdmasafe == 0));
#endif

	/* Wait until enough descriptors are available for the transfer. */
	/* THIS WILL BLOCK UNTIL THERE ARE ENOUGH DESCRIPTORS AVAILABLE */
	while (dn > lpc_tx_ready(netif))
#if NO_SYS == 0
	    osSemaphoreWait(lpc_enetif->xTXDCountSem.id, osWaitForever);
#else
		osDelay(1);
#endif

	/* Get free TX buffer index */
	idx = LPC_EMAC->TxProduceIndex;

#if NO_SYS == 0
	/* Get exclusive access */
	sys_mutex_lock(&lpc_enetif->TXLockMutex);
#endif

	/* Prevent LWIP from de-allocating this pbuf. The driver will
	   free it once it's been transmitted. */
	if (!notdmasafe)
		pbuf_ref(p);

	/* Setup transfers */
	q = p;
	while (dn > 0) {
		dn--;

		/* Only save pointer to free on last descriptor */
		if (dn == 0) {
			/* Save size of packet and signal it's ready */
			lpc_enetif->ptxd[idx].control = (q->len - 1) | EMAC_TCTRL_INT |
				EMAC_TCTRL_LAST;
            lpc_enetif->txb[idx] = p;
		}
		else {
			/* Save size of packet, descriptor is not last */
			lpc_enetif->ptxd[idx].control = (q->len - 1) | EMAC_TCTRL_INT;
			lpc_enetif->txb[idx] = NULL;
		}

		LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
			("lpc_low_level_output: pbuf packet(%p) sent, chain#=%d,"
			" size = %d (index=%d)\n", q->payload, dn, q->len, idx));

		lpc_enetif->ptxd[idx].packet = (u32_t) q->payload;

		q = q->next;

		idx++;
		if (idx >= LPC_NUM_BUFF_TXDESCS)
			idx = 0;
	}

	LPC_EMAC->TxProduceIndex = idx;

	LINK_STATS_INC(link.xmit);

#if NO_SYS == 0
	/* Restore access */
	sys_mutex_unlock(&lpc_enetif->TXLockMutex);
#endif

	return ERR_OK;
}
/*
 * Compress (encrypt) a packet.
 * It's strange to call this a compressor, since the output is always
 * MPPE_OVHD + 2 bytes larger than the input.
 */
err_t
mppe_compress(ppp_pcb *pcb, ppp_mppe_state *state, struct pbuf **pb, u16_t protocol)
{
	struct pbuf *n, *np;
	u8_t *pl;
	err_t err;

	LWIP_UNUSED_ARG(pcb);

	/* TCP stack requires that we don't change the packet payload, therefore we copy
	 * the whole packet before encryption.
	 */
	np = pbuf_alloc(PBUF_RAW, MPPE_OVHD + sizeof(protocol) + (*pb)->tot_len, PBUF_POOL);
	if (!np) {
		return ERR_MEM;
	}

	/* Hide MPPE header + protocol */
	pbuf_header(np, -(s16_t)(MPPE_OVHD + sizeof(protocol)));

	if ((err = pbuf_copy(np, *pb)) != ERR_OK) {
		pbuf_free(np);
		return err;
	}

	/* Reveal MPPE header + protocol */
	pbuf_header(np, (s16_t)(MPPE_OVHD + sizeof(protocol)));

	*pb = np;
	pl = (u8_t*)np->payload;

	state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
	PPPDEBUG(LOG_DEBUG, ("mppe_compress[%d]: ccount %d\n", pcb->netif->num, state->ccount));
	/* FIXME: use PUT* macros */
	pl[0] = state->ccount>>8;
	pl[1] = state->ccount;

	if (!state->stateful ||	/* stateless mode     */
	    ((state->ccount & 0xff) == 0xff) ||	/* "flag" packet      */
	    (state->bits & MPPE_BIT_FLUSHED)) {	/* CCP Reset-Request  */
		/* We must rekey */
		if (state->stateful) {
			PPPDEBUG(LOG_DEBUG, ("mppe_compress[%d]: rekeying\n", pcb->netif->num));
		}
		mppe_rekey(state, 0);
		state->bits |= MPPE_BIT_FLUSHED;
	}
	pl[0] |= state->bits;
	state->bits &= ~MPPE_BIT_FLUSHED;	/* reset for next xmit */
	pl += MPPE_OVHD;

	/* Add protocol */
	/* FIXME: add PFC support */
	pl[0] = protocol >> 8;
	pl[1] = protocol;

	/* Hide MPPE header */
	pbuf_header(np, -(s16_t)MPPE_OVHD);

	/* Encrypt packet */
	for (n = np; n != NULL; n = n->next) {
		arc4_crypt(&state->arc4, (u8_t*)n->payload, n->len);
		if (n->tot_len == n->len) {
			break;
		}
	}

	/* Reveal MPPE header */
	pbuf_header(np, (s16_t)MPPE_OVHD);

	return ERR_OK;
}
Exemple #21
0
/*-----------------------------------------------------------------------------------*/
static void
low_level_init(struct netif *netif)
{
    mcf5272if_t *mcf5272;
    MCF5272_IMM *imm;
    VOID        (*old_lisr)(INT);   /* old LISR */
    u32_t value;
    u32_t old_level;
    struct pbuf *p;
    int i;

    mcf5272 = netif->state;
    imm = mcf5272->imm;

    /* Initialize our ethernet address */
    sys_get_eth_addr(mcf5272->ethaddr);
    
    /* First disable fec */
    disable_fec(mcf5272);

    /* Plug appropriate low level interrupt vectors */
    sys_setvect(MCF5272_VECTOR_ERx, mcf5272fec_rx, mcf5272_dis_rx_int);
    sys_setvect(MCF5272_VECTOR_ETx, mcf5272fec_tx_hisr, mcf5272_dis_tx_int);
    //sys_setvect(MCF5272_VECTOR_ENTC, mcf5272fec_ntc);

    /* Set the I_MASK register to enable only rx & tx frame interrupts */
    MCF5272_WR_FEC_IMR(imm, MCF5272_FEC_IMR_TXFEN | MCF5272_FEC_IMR_RXFEN);

    /* Clear I_EVENT register */
    MCF5272_WR_FEC_EIR(imm,0xFFFFFFFF);

    /* Set up the appropriate interrupt levels */
    /* Disable interrupts, since this is a read/modify/write operation */
    old_level = sys_arch_protect();
    value = MCF5272_RD_SIM_ICR3(imm);
    MCF5272_WR_SIM_ICR3(imm, value | MCF5272_SIM_ICR_ERX_IL(FEC_LEVEL) |
                        MCF5272_SIM_ICR_ETX_IL(FEC_LEVEL));
    sys_arch_unprotect(old_level);
    
    /* Set the source address for the controller */
    MCF5272_WR_FEC_MALR(imm,0 
                        | (mcf5272->ethaddr->addr[0] <<24) 
                        | (mcf5272->ethaddr->addr[1] <<16)	
                        | (mcf5272->ethaddr->addr[2] <<8) 
                        | (mcf5272->ethaddr->addr[3] <<0)); 
    MCF5272_WR_FEC_MAUR(imm,0
                        | (mcf5272->ethaddr->addr[4] <<24)
                        | (mcf5272->ethaddr->addr[5] <<16));
    
    /* Initialize the hash table registers */
    /* We are not supporting multicast addresses */
    MCF5272_WR_FEC_HTUR(imm,0);
    MCF5272_WR_FEC_HTLR(imm,0);

    /* Set Receive Buffer Size. We subtract 16 because the start of the receive
    *  buffer MUST be divisible by 16, so depending on where the payload really
    *  starts in the pbuf, we might be increasing the start point by up to 15 bytes.
    *  See the alignment code in fill_rx_ring() */
    /* There might be an offset to the payload address and we should subtract
     * that offset */
    p = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, PBUF_POOL);
    i = 0;
    if (p)
    {
        struct pbuf *q = p;
        
        while ((q = q->next) != 0)
            i += q->len;
        mcf5272->rx_buf_len = PBUF_POOL_BUFSIZE-16-i;
        pbuf_free(p);
    }
    
    
    MCF5272_WR_FEC_EMRBR(imm, (u16_t) mcf5272->rx_buf_len);

    /* Point to the start of the circular Rx buffer descriptor queue */
    MCF5272_WR_FEC_ERDSR(imm, ((u32_t) &mcf5272->rxbd_a[0]));

    /* Point to the start of the circular Tx buffer descriptor queue */
    MCF5272_WR_FEC_ETDSR(imm, ((u32_t) &mcf5272->txbd_a[0]));
    
    /* Set the tranceiver interface to MII mode */
    MCF5272_WR_FEC_RCR(imm, 0
                       | MCF5272_FEC_RCR_MII_MODE
                       | MCF5272_FEC_RCR_DRT); 	/* half duplex */

    /* Only operate in half-duplex, no heart beat control */
    MCF5272_WR_FEC_TCR(imm, 0);

    /* Set the maximum frame length (MTU) */
    MCF5272_WR_FEC_MFLR(imm, MTU_FEC);

    /* Set MII bus speed */
    MCF5272_WR_FEC_MSCR(imm, 0x0a);

    /* Enable fec i/o pins */
    value = MCF5272_RD_GPIO_PBCNT(imm);
    MCF5272_WR_GPIO_PBCNT(imm, ((value & 0x0000ffff) | 0x55550000));

    /* Clear MII interrupt status */
    MCF5272_WR_FEC_EIR(imm, MCF5272_FEC_IMR_MIIEN);
        
/*     /\* Read phy ID *\/ */
/*     MCF5272_WR_FEC_MMFR(imm, 0x600a0000); */
/*     while (1) */
/*     { */
/*         value = MCF5272_RD_FEC_EIR(imm); */
/*         if ((value & MCF5272_FEC_IMR_MIIEN) != 0) */
/*         { */
/*             MCF5272_WR_FEC_EIR(imm, MCF5272_FEC_IMR_MIIEN); */
/*             break; */
/*         } */
/*     } */
/*     phy = MCF5272_RD_FEC_MMFR(imm); */
    
    /* Enable FEC */
    enable_fec(mcf5272);

    /* THIS IS FOR LEVEL ONE/INTEL PHY ONLY!!! */
    /* Program Phy LED 3 to tell us transmit status */
    MCF5272_WR_FEC_MMFR(imm, 0x50520412);

}
Exemple #22
0
/**
 * Send an ARP request for the given IP address.
 *
 * Sends an ARP request for the given IP address, unless
 * a request for this address is already pending. Optionally
 * queues an outgoing packet on the resulting ARP entry.
 *
 * @param netif The lwIP network interface where ipaddr
 * must be queried for.
 * @param ipaddr The IP address to be resolved.
 * @param q If non-NULL, a pbuf that must be queued on the
 * ARP entry for the ipaddr IP address.
 *
 * @return NULL.
 *
 * @note Might be used in the future by manual IP configuration
 * as well.
 *
 * TODO: use the ctime field to see how long ago an ARP request was sent,
 * possibly retry.
 */
err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
{
  struct eth_addr *srcaddr;
  struct etharp_hdr *hdr;
  err_t result = ERR_OK;
  s8_t i;
  u8_t perform_arp_request = 1;
  /* prevent 'unused argument' warning if ARP_QUEUEING == 0 */
  (void)q;
  srcaddr = (struct eth_addr *)netif->hwaddr;
  /* bail out if this IP address is pending */
  for (i = 0; i < ARP_TABLE_SIZE; ++i) {
    if (ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
      if (arp_table[i].state == ETHARP_STATE_PENDING) {
        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already pending as entry %u\n", i));
        /* break out of for-loop, user may wish to queue a packet on a pending entry */
        /* TODO: we will issue a new ARP request, which should not occur too often */
        /* we might want to run a faster timer on ARP to limit this */
        break;
      }
      else if (arp_table[i].state == ETHARP_STATE_STABLE) {
        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already stable as entry %u\n", i));
        /* User wishes to queue a packet on a stable entry (or does she want to send
         * out the packet immediately, we will not know), so we force an ARP request.
         * Upon response we will send out the queued packet in etharp_update().
         * 
         * Alternatively, we could accept the stable entry, and just send out the packet
         * immediately. I chose to implement the former approach.
         */
        perform_arp_request = (q?1:0);
        break;
      }
    }
  }
  /* queried address not yet in ARP table? */
  if (i == ARP_TABLE_SIZE) {
    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: IP address not found in ARP table\n"));
    /* find an available (unused or old) entry */
    i = find_arp_entry();
    /* bail out if no ARP entries are available */
    if (i == ERR_MEM) {
      LWIP_DEBUGF(ETHARP_DEBUG | 2, ("etharp_query: no more ARP entries available. Should seldom occur.\n"));
      return ERR_MEM;
    }
    /* i is available, create ARP entry */
    arp_table[i].state = ETHARP_STATE_PENDING;
    ip_addr_set(&arp_table[i].ipaddr, ipaddr);
  }
  /* { i is now valid } */
#if ARP_QUEUEING /* queue packet (even on a stable entry, see above) */
  etharp_enqueue(i, q);
#endif
  /* ARP request? */
  if (perform_arp_request)
  {
    struct pbuf *p;
    /* allocate a pbuf for the outgoing ARP request packet */
    p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM);
    /* could allocate pbuf? */
    if (p != NULL) {
      u8_t j;
      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: sending ARP request.\n"));
      hdr = p->payload;
      hdr->opcode = htons(ARP_REQUEST);
      for (j = 0; j < netif->hwaddr_len; ++j)
      {
        hdr->shwaddr.addr[j] = srcaddr->addr[j];
        /* the hardware address is what we ask for, in
         * a request it is a don't-care, we use 0's */
        hdr->dhwaddr.addr[j] = 0x00;
      }
      ip_addr_set(&(hdr->dipaddr), ipaddr);
      ip_addr_set(&(hdr->sipaddr), &(netif->ip_addr));

      hdr->hwtype = htons(HWTYPE_ETHERNET);
      ARPH_HWLEN_SET(hdr, netif->hwaddr_len);

      hdr->proto = htons(ETHTYPE_IP);
      ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));
      for (j = 0; j < netif->hwaddr_len; ++j)
      {
        hdr->ethhdr.dest.addr[j] = 0xff;
        hdr->ethhdr.src.addr[j] = srcaddr->addr[j];
      }
      hdr->ethhdr.type = htons(ETHTYPE_ARP);
      /* send ARP query */
      result = netif->linkoutput(netif, p);
      /* free ARP query packet */
      pbuf_free(p);
      p = NULL;
    } else {
      result = ERR_MEM;
      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_query: could not allocate pbuf for ARP request.\n"));
    }
  }
  return result;
}
Exemple #23
0
/**
 * Send the raw IP packet to the given address. Note that actually you cannot
 * modify the IP headers (this is inconsistent with the receive callback where
 * you actually get the IP headers), you can only specify the IP payload here.
 * It requires some more changes in lwIP. (there will be a raw_send() function
 * then.)
 *
 * @param pcb the raw pcb which to send
 * @param p the IP payload to send
 * @param ipaddr the destination address of the IP packet
 *
 */
err_t
raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
{
  err_t err;
  struct netif *netif;
  ip_addr_t *src_ip;
  struct pbuf *q; /* q will be sent down the stack */
  
  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
  
  /* not enough space to add an IP header to first pbuf in given p chain? */
  if (pbuf_header(p, IP_HLEN)) {
    /* allocate header in new pbuf */
    q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
    /* new header pbuf could not be allocated? */
    if (q == NULL) {
      LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
      return ERR_MEM;
    }
    if (p->tot_len != 0) {
      /* chain header q in front of given pbuf p */
      pbuf_chain(q, p);
    }
    /* { first pbuf q points to header pbuf } */
    LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
  }  else {
    /* first pbuf q equals given pbuf */
    q = p;
    if(pbuf_header(q, -IP_HLEN)) {
      LWIP_ASSERT("Can't restore header we just removed!", 0);
      return ERR_MEM;
    }
  }

  if ((netif = ip_route(ipaddr)) == NULL) {
    LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
      ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
    /* free any temporary header pbuf allocated by pbuf_header() */
    if (q != p) {
      pbuf_free(q);
    }
    return ERR_RTE;
  }

#if IP_SOF_BROADCAST
  /* broadcast filter? */
  if (!ip_get_option(pcb, SOF_BROADCAST) && ip_addr_isbroadcast(ipaddr, netif)) {
    LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
    /* free any temporary header pbuf allocated by pbuf_header() */
    if (q != p) {
      pbuf_free(q);
    }
    return ERR_VAL;
  }
#endif /* IP_SOF_BROADCAST */

  if (ip_addr_isany(&pcb->local_ip)) {
    /* use outgoing network interface IP address as source address */
    src_ip = &(netif->ip_addr);
  } else {
    /* use RAW PCB local IP address as source address */
    src_ip = &(pcb->local_ip);
  }

  NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
  err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
  NETIF_SET_HWADDRHINT(netif, NULL);

  /* did we chain a header earlier? */
  if (q != p) {
    /* free the header */
    pbuf_free(q);
  }
  return err;
}
Exemple #24
0
/**
 * Processes ICMP input packets, called from ip_input().
 *
 * Currently only processes icmp echo requests and sends
 * out the echo response.
 *
 * @param p the icmp echo request packet, p->payload pointing to the ip header
 * @param inp the netif on which this packet was received
 */
void icmp_input(struct pbuf *p, struct netif *inp)
{
    u8_t type;

#ifdef LWIP_DEBUG
    u8_t code;
#endif                          /* LWIP_DEBUG */
    struct icmp_echo_hdr *iecho;
    struct ip_hdr *iphdr;
    struct ip_addr tmpaddr;
    s16_t hlen;

    ICMP_STATS_INC(icmp.recv);
    snmp_inc_icmpinmsgs();

    iphdr = p->payload;
    hlen = IPH_HL(iphdr) * 4;
    if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t) * 2)) {
        LWIP_DEBUGF(ICMP_DEBUG,
                    ("icmp_input: short ICMP (%" U16_F " bytes) received\n",
                     p->tot_len));
        goto lenerr;
    }

    type = *((u8_t *) p->payload);
#ifdef LWIP_DEBUG
    code = *(((u8_t *) p->payload) + 1);
#endif                          /* LWIP_DEBUG */
    switch (type) {
        case ICMP_ECHO:
#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
            {
                int accepted = 1;

#if !LWIP_MULTICAST_PING
                /* multicast destination address? */
                if (ip_addr_ismulticast(&iphdr->dest)) {
                    accepted = 0;
                }
#endif                          /* LWIP_MULTICAST_PING */
#if !LWIP_BROADCAST_PING
                /* broadcast destination address? */
                if (ip_addr_isbroadcast(&iphdr->dest, inp)) {
                    accepted = 0;
                }
#endif                          /* LWIP_BROADCAST_PING */
                /* broadcast or multicast destination address not acceptd? */
                if (!accepted) {
                    LWIP_DEBUGF(ICMP_DEBUG,
                                ("icmp_input: Not echoing to multicast or broadcast pings\n"));
                    ICMP_STATS_INC(icmp.err);
                    pbuf_free(p);
                    return;
                }
            }
#endif                          /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */
            LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
            if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
                LWIP_DEBUGF(ICMP_DEBUG,
                            ("icmp_input: bad ICMP echo received\n"));
                goto lenerr;
            }
            if (inet_chksum_pbuf(p) != 0) {
                LWIP_DEBUGF(ICMP_DEBUG,
                            ("icmp_input: checksum failed for received ICMP echo\n"));
                pbuf_free(p);
                ICMP_STATS_INC(icmp.chkerr);
                snmp_inc_icmpinerrors();
                return;
            }
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
            if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
                /* p is not big enough to contain link headers
                 * allocate a new one and copy p into it
                 */
                struct pbuf *r;

                /* switch p->payload to ip header */
                if (pbuf_header(p, hlen)) {
                    LWIP_ASSERT
                      ("icmp_input: moving p->payload to ip header failed\n",
                       0);
                    goto memerr;
                }
                /* allocate new packet buffer with space for link headers */
                r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
                if (r == NULL) {
                    LWIP_DEBUGF(ICMP_DEBUG,
                                ("icmp_input: allocating new pbuf failed\n"));
                    goto memerr;
                }
                LWIP_ASSERT
                  ("check that first pbuf can hold struct the ICMP header",
                   (r->len >= hlen + sizeof(struct icmp_echo_hdr)));
                /* copy the whole packet including ip header */
                if (pbuf_copy(r, p) != ERR_OK) {
                    LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0);
                    goto memerr;
                }
                iphdr = r->payload;
                /* switch r->payload back to icmp header */
                if (pbuf_header(r, -hlen)) {
                    LWIP_ASSERT
                      ("icmp_input: restoring original p->payload failed\n", 0);
                    goto memerr;
                }
                /* free the original p */
                pbuf_free(p);
                /* we now have an identical copy of p that has room for link headers */
                p = r;
            } else {
                /* restore p->payload to point to icmp header */
                if (pbuf_header(p, -(s16_t) (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
                    LWIP_ASSERT
                      ("icmp_input: restoring original p->payload failed\n", 0);
                    goto memerr;
                }
            }
#endif                          /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
            /* At this point, all checks are OK. */
            /* We generate an answer by switching the dest and src ip addresses,
             * setting the icmp type to ECHO_RESPONSE and updating the checksum. */
            iecho = p->payload;
            tmpaddr.addr = iphdr->src.addr;
            iphdr->src.addr = iphdr->dest.addr;
            iphdr->dest.addr = tmpaddr.addr;
            ICMPH_TYPE_SET(iecho, ICMP_ER);
            /* adjust the checksum */
            if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) {
                iecho->chksum += htons(ICMP_ECHO << 8) + 1;
            } else {
                iecho->chksum += htons(ICMP_ECHO << 8);
            }

            /* Set the correct TTL and recalculate the header checksum. */
            IPH_TTL_SET(iphdr, ICMP_TTL);
            IPH_CHKSUM_SET(iphdr, 0);
#if CHECKSUM_GEN_IP
            if (is_hw_feature_enabled(IPv4_CHECKSUM_HW)) {
                p->nicflags |= NETIF_TXFLAG_IPCHECKSUM;
            } else {
                IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
            }
#endif                          /* CHECKSUM_GEN_IP */

            ICMP_STATS_INC(icmp.xmit);
            /* increase number of messages attempted to send */
            snmp_inc_icmpoutmsgs();
            /* increase number of echo replies attempted to send */
            snmp_inc_icmpoutechoreps();

            if (pbuf_header(p, hlen)) {
                LWIP_ASSERT("ICMP: Can't move over header in packet", 0);
            } else {
                err_t ret;

                /* Calling callback to inform arrival of ICMP packet */
//      printf("Sending back the ping reply\n");
                if (icmp_notifier != NULL) {
                    icmp_notifier(p);
                }
                ret = ip_output_if(p, &(iphdr->src), IP_HDRINCL,
                                   ICMP_TTL, 0, IP_PROTO_ICMP, inp);
                if (ret != ERR_OK) {
                    LWIP_DEBUGF(ICMP_DEBUG,
                                ("icmp_input: ip_output_if returned an error: %c.\n",
                                 ret));
                }
            }
            break;
        default:
            LWIP_DEBUGF(ICMP_DEBUG,
                        ("icmp_input: ICMP type %" S16_F " code %" S16_F
                         " not supported.\n", (s16_t) type, (s16_t) code));
            ICMP_STATS_INC(icmp.proterr);
            ICMP_STATS_INC(icmp.drop);
    }
    pbuf_free(p);
    return;
  lenerr:
    pbuf_free(p);
    ICMP_STATS_INC(icmp.lenerr);
    snmp_inc_icmpinerrors();
    return;
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
  memerr:
    pbuf_free(p);
    ICMP_STATS_INC(icmp.err);
    snmp_inc_icmpinerrors();
    return;
#endif                          /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
}
Exemple #25
0
static void ICACHE_FLASH_ATTR send_ack(struct dhcps_msg *m)
{

		u8_t *end;
	    struct pbuf *p, *q;
	    u8_t *data;
	    u16_t cnt=0;
	    u16_t i;
        create_msg(m);

        end = add_msg_type(&m->options[4], DHCPACK);
        end = add_offer_options(end);
        end = add_end(end);

	    p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcps_msg), PBUF_RAM);
#if DHCPS_DEBUG
		os_printf("udhcp: send_ack>>p->ref = %d\n", p->ref);
#endif
	    if(p != NULL){

#if DHCPS_DEBUG
	        os_printf("dhcps: send_ack>>pbuf_alloc succeed\n");
	        os_printf("dhcps: send_ack>>p->tot_len = %d\n", p->tot_len);
	        os_printf("dhcps: send_ack>>p->len = %d\n", p->len);
#endif
	        q = p;
	        while(q != NULL){
	            data = (u8_t *)q->payload;
	            for(i=0; i<q->len; i++)
	            {
	                data[i] = ((u8_t *) m)[cnt++];
#if DHCPS_DEBUG
					os_printf("%02x ",data[i]);
					if((i+1)%16 == 0){
						os_printf("\n");
					}
#endif
	            }

	            q = q->next;
	        }
	    }else{

#if DHCPS_DEBUG
	        os_printf("dhcps: send_ack>>pbuf_alloc failed\n");
#endif
	        return;
	    }
#if DHCPS_DEBUG
	    err_t SendAck_err_t = udp_sendto( pcb_dhcps, p, &broadcast_dhcps, DHCPS_CLIENT_PORT );
        os_printf("dhcps: send_ack>>udp_sendto result %x\n",SendAck_err_t);
#else
        udp_sendto( pcb_dhcps, p, &broadcast_dhcps, DHCPS_CLIENT_PORT );
#endif

	    if(p->ref != 0){
#if DHCPS_DEBUG
	        os_printf("udhcp: send_ack>>free pbuf\n");
#endif
	        pbuf_free(p);
	    }
}
/* Low level output of a packet. Never call this from an interrupt context,
   as it may block until TX descriptors become available */
static err_t lpc_low_level_output(struct netif *netif, struct pbuf *sendp)
{
	struct lpc_enetdata *lpc_netifdata = netif->state;
	u32_t idx, fidx, dn;
	struct pbuf *p = sendp;

#if LPC_CHECK_SLOWMEM == 1
	struct pbuf *q, *wp;

	u8_t *dst;
	int pcopy = 0;

	/* Check packet address to determine if it's in slow memory and
	   relocate if necessary */
	for (q = p; ((q != NULL) && (pcopy == 0)); q = q->next) {
		fidx = 0;
		for (idx = 0; idx < sizeof(slmem);
			 idx += sizeof(struct lpc_slowmem_array_t)) {
			if ((q->payload >= (void *) slmem[fidx].start) &&
				(q->payload <= (void *) slmem[fidx].end)) {
				/* Needs copy */
				pcopy = 1;
			}
		}
	}

	if (pcopy) {
		/* Create a new pbuf with the total pbuf size */
		wp = pbuf_alloc(PBUF_RAW, (u16_t) EMAC_ETH_MAX_FLEN, PBUF_RAM);
		if (!wp) {
			/* Exit with error */
			return ERR_MEM;
		}

		/* Copy pbuf */
		dst = (u8_t *) wp->payload;
		wp->tot_len = 0;
		for (q = p; q != NULL; q = q->next) {
			MEMCPY(dst, (u8_t *) q->payload, q->len);
			dst += q->len;
			wp->tot_len += q->len;
		}
		wp->len = wp->tot_len;

		/* LWIP will free original pbuf on exit of function */

		p = sendp = wp;
	}
#endif

	/* Zero-copy TX buffers may be fragmented across mutliple payload
	   chains. Determine the number of descriptors needed for the
	   transfer. The pbuf chaining can be a mess! */
	dn = (u32_t) pbuf_clen(p);

	/* Wait until enough descriptors are available for the transfer. */
	/* THIS WILL BLOCK UNTIL THERE ARE ENOUGH DESCRIPTORS AVAILABLE */
	while (dn > lpc_tx_ready(netif))
#if NO_SYS == 0
	{xSemaphoreTake(lpc_netifdata->xTXDCountSem, 0); }
#else
	{msDelay(1); }
#endif

	/* Get the next free descriptor index */
	fidx = idx = lpc_netifdata->tx_fill_idx;

#if NO_SYS == 0
	/* Get exclusive access */
	sys_mutex_lock(&lpc_netifdata->TXLockMutex);
#endif

	/* Fill in the next free descriptor(s) */
	while (dn > 0) {
		dn--;

		/* Setup packet address and length */
		lpc_netifdata->ptdesc[idx].B1ADD = (u32_t) p->payload;
		lpc_netifdata->ptdesc[idx].BSIZE = (u32_t) TDES_ENH_BS1(p->len);

		/* Save pointer to pbuf so we can reclain the memory for
		   the pbuf after the buffer has been sent. Only the first
		   pbuf in a chain is saved since the full chain doesn't
		   need to be freed. */
		/* For first packet only, first flag */
		lpc_netifdata->tx_free_descs--;
		if (idx == fidx) {
			lpc_netifdata->ptdesc[idx].CTRLSTAT |= TDES_ENH_FS;
#if LPC_CHECK_SLOWMEM == 1
			/* If this is a copied pbuf, then avoid getting the extra reference
			   or the TX reclaim will be off by 1 */
			if (!pcopy) {
				pbuf_ref(p);
			}
#else
			/* Increment reference count on this packet so LWIP doesn't
			   attempt to free it on return from this call */
			pbuf_ref(p);
#endif
		}
		else {
			lpc_netifdata->ptdesc[idx].CTRLSTAT |= TDES_OWN;
		}

		/* Save address of pbuf, but make sure it's associated with the
		   first chained pbuf so it gets freed once all pbuf chains are
		   transferred. */
		if (!dn) {
			lpc_netifdata->txpbufs[idx] = sendp;
		}
		else {
			lpc_netifdata->txpbufs[idx] = NULL;
		}

		/* For last packet only, interrupt and last flag */
		if (dn == 0) {
			lpc_netifdata->ptdesc[idx].CTRLSTAT |= TDES_ENH_LS |
												   TDES_ENH_IC;
		}

		/* IP checksumming requires full buffering in IP */
		lpc_netifdata->ptdesc[idx].CTRLSTAT |= TDES_ENH_CIC(3);

		LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE,
					("lpc_low_level_output: pbuf packet %p sent, chain %d,"
					 " size %d, index %d, free %d\n", p, dn, p->len, idx,
					 lpc_netifdata->tx_free_descs));

		/* Update next available descriptor */
		idx++;
		if (idx >= LPC_NUM_BUFF_TXDESCS) {
			idx = 0;
		}

		/* Next packet fragment */
		p = p->next;
	}

	lpc_netifdata->tx_fill_idx = idx;

	LINK_STATS_INC(link.xmit);

	/* Give first descriptor to DMA to start transfer */
	lpc_netifdata->ptdesc[fidx].CTRLSTAT |= TDES_OWN;

	/* Tell DMA to poll descriptors to start transfer */
	LPC_ETHERNET->DMA_TRANS_POLL_DEMAND = 1;

#if NO_SYS == 0
	/* Restore access */
	sys_mutex_unlock(&lpc_netifdata->TXLockMutex);
#endif

	return ERR_OK;
}
Exemple #27
0
/**
 * Process an incoming UDP datagram.
 *
 * Given an incoming UDP datagram (as a chain of pbufs) this function
 * finds a corresponding UDP PCB and hands over the pbuf to the pcbs
 * recv function. If no pcb is found or the datagram is incorrect, the
 * pbuf is freed.
 *
 * @param p pbuf to be demultiplexed to a UDP PCB.
 * @param inp network interface on which the datagram was received.
 *
 */
void
udp_input(struct pbuf *p, struct netif *inp)
{
  struct udp_hdr *udphdr;
  struct udp_pcb *pcb, *prev;
  struct udp_pcb *uncon_pcb;
  struct ip_hdr *iphdr;
  u16_t src, dest;
  u8_t local_match;
  u8_t broadcast;

  PERF_START;

  UDP_STATS_INC(udp.recv);

  iphdr = (struct ip_hdr *)p->payload;

  /* Check minimum length (IP header + UDP header)
   * and move payload pointer to UDP header */
  if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) {
    /* drop short packets */
    LWIP_DEBUGF(UDP_DEBUG,
                ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len));
    UDP_STATS_INC(udp.lenerr);
    UDP_STATS_INC(udp.drop);
    snmp_inc_udpinerrors();
    pbuf_free(p);
    goto end;
  }

  udphdr = (struct udp_hdr *)p->payload;

  /* is broadcast packet ? */
  broadcast = ip_addr_isbroadcast(&current_iphdr_dest, inp);

  LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));

  /* convert src and dest ports to host byte order */
  src = ntohs(udphdr->src);
  dest = ntohs(udphdr->dest);

  udp_debug_print(udphdr);

  /* print the UDP source and destination */
  LWIP_DEBUGF(UDP_DEBUG,
              ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- "
               "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
               ip4_addr1_16(&iphdr->dest), ip4_addr2_16(&iphdr->dest),
               ip4_addr3_16(&iphdr->dest), ip4_addr4_16(&iphdr->dest), ntohs(udphdr->dest),
               ip4_addr1_16(&iphdr->src), ip4_addr2_16(&iphdr->src),
               ip4_addr3_16(&iphdr->src), ip4_addr4_16(&iphdr->src), ntohs(udphdr->src)));

#if LWIP_DHCP
  pcb = NULL;
  /* when LWIP_DHCP is active, packets to DHCP_CLIENT_PORT may only be processed by
     the dhcp module, no other UDP pcb may use the local UDP port DHCP_CLIENT_PORT */
  if (dest == DHCP_CLIENT_PORT) {
    /* all packets for DHCP_CLIENT_PORT not coming from DHCP_SERVER_PORT are dropped! */
    if (src == DHCP_SERVER_PORT) {
      if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) {
        /* accept the packe if 
           (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY!
           - inp->dhcp->pcb->remote == ANY or iphdr->src */
        if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) ||
           ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), &current_iphdr_src))) {
          pcb = inp->dhcp->pcb;
        }
      }
    }
  } else
#endif /* LWIP_DHCP */
  {
    prev = NULL;
//    local_match = 0;
    uncon_pcb = NULL;
    /* Iterate through the UDP pcb list for a matching pcb.
     * 'Perfect match' pcbs (connected to the remote port & ip address) are
     * preferred. If no perfect match is found, the first unconnected pcb that
     * matches the local port and ip address gets the datagram. */
    for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
      local_match = 0;
      /* print the PCB local and remote address */
      LWIP_DEBUGF(UDP_DEBUG,
                  ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- "
                   "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
                   ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
                   ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), pcb->local_port,
                   ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
                   ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip), pcb->remote_port));

      /* compare PCB local addr+port to UDP destination addr+port */
      if ((pcb->local_port == dest) &&
          ((!broadcast && ip_addr_isany(&pcb->local_ip)) ||
           ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest) ||
#if LWIP_IGMP
           ip_addr_ismulticast(&current_iphdr_dest) ||
#endif /* LWIP_IGMP */
#if IP_SOF_BROADCAST_RECV
           (broadcast && (pcb->so_options & SOF_BROADCAST)))) {
#else  /* IP_SOF_BROADCAST_RECV */
           (broadcast))) {
#endif /* IP_SOF_BROADCAST_RECV */
        local_match = 1;
        if ((uncon_pcb == NULL) && 
            ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {
          /* the first unconnected matching PCB */
          uncon_pcb = pcb;
        }
      }
      /* compare PCB remote addr+port to UDP source addr+port */
      if ((local_match != 0) &&
          (pcb->remote_port == src) &&
          (ip_addr_isany(&pcb->remote_ip) ||
           ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src))) {
        /* the first fully matching PCB */
        if (prev != NULL) {
          /* move the pcb to the front of udp_pcbs so that is
             found faster next time */
          prev->next = pcb->next;
          pcb->next = udp_pcbs;
          udp_pcbs = pcb;
        } else {
          UDP_STATS_INC(udp.cachehit);
        }
        break;
      }
      prev = pcb;
    }
    /* no fully matching pcb found? then look for an unconnected pcb */
    if (pcb == NULL) {
      pcb = uncon_pcb;
    }
  }

  /* Check checksum if this is a match or if it was directed at us. */
  if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &current_iphdr_dest)) {
    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n"));
#if LWIP_UDPLITE
    if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {
      /* Do the UDP Lite checksum */
#if CHECKSUM_CHECK_UDP
      u16_t chklen = ntohs(udphdr->len);
      if (chklen < sizeof(struct udp_hdr)) {
        if (chklen == 0) {
          /* For UDP-Lite, checksum length of 0 means checksum
             over the complete packet (See RFC 3828 chap. 3.1) */
          chklen = p->tot_len;
        } else {
          /* At least the UDP-Lite header must be covered by the
             checksum! (Again, see RFC 3828 chap. 3.1) */
          UDP_STATS_INC(udp.chkerr);
          UDP_STATS_INC(udp.drop);
          snmp_inc_udpinerrors();
          pbuf_free(p);
          goto end;
        }
      }
      if (inet_chksum_pseudo_partial(p, &current_iphdr_src, &current_iphdr_dest,
                             IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) {
       LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
                   ("udp_input: UDP Lite datagram discarded due to failing checksum\n"));
        UDP_STATS_INC(udp.chkerr);
        UDP_STATS_INC(udp.drop);
        snmp_inc_udpinerrors();
        pbuf_free(p);
        goto end;
      }
#endif /* CHECKSUM_CHECK_UDP */
    } else
#endif /* LWIP_UDPLITE */
    {
#if CHECKSUM_CHECK_UDP
      if (udphdr->chksum != 0) {
        if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
                               IP_PROTO_UDP, p->tot_len) != 0) {
          LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
                      ("udp_input: UDP datagram discarded due to failing checksum\n"));
          UDP_STATS_INC(udp.chkerr);
          UDP_STATS_INC(udp.drop);
          snmp_inc_udpinerrors();
          pbuf_free(p);
          goto end;
        }
      }
#endif /* CHECKSUM_CHECK_UDP */
    }
    if(pbuf_header(p, -UDP_HLEN)) {
      /* Can we cope with this failing? Just assert for now */
      LWIP_ASSERT("pbuf_header failed\n", 0);
      UDP_STATS_INC(udp.drop);
      snmp_inc_udpinerrors();
      pbuf_free(p);
      goto end;
    }
    if (pcb != NULL) {
      snmp_inc_udpindatagrams();
#if SO_REUSE && SO_REUSE_RXTOALL
      if ((broadcast || ip_addr_ismulticast(&current_iphdr_dest)) &&
          ((pcb->so_options & SOF_REUSEADDR) != 0)) {
        /* pass broadcast- or multicast packets to all multicast pcbs
           if SOF_REUSEADDR is set on the first match */
        struct udp_pcb *mpcb;
        u8_t p_header_changed = 0;
        for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) {
          if (mpcb != pcb) {
            /* compare PCB local addr+port to UDP destination addr+port */
            if ((mpcb->local_port == dest) &&
                ((!broadcast && ip_addr_isany(&mpcb->local_ip)) ||
                 ip_addr_cmp(&(mpcb->local_ip), &current_iphdr_dest) ||
#if LWIP_IGMP
                 ip_addr_ismulticast(&current_iphdr_dest) ||
#endif /* LWIP_IGMP */
#if IP_SOF_BROADCAST_RECV
                 (broadcast && (mpcb->so_options & SOF_BROADCAST)))) {
#else  /* IP_SOF_BROADCAST_RECV */
                 (broadcast))) {
#endif /* IP_SOF_BROADCAST_RECV */
              /* pass a copy of the packet to all local matches */
              if (mpcb->recv != NULL) {
                struct pbuf *q;
                /* for that, move payload to IP header again */
                if (p_header_changed == 0) {
                  pbuf_header(p, (s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
                  p_header_changed = 1;
                }
                q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
                if (q != NULL) {
                  err_t err = pbuf_copy(q, p);
                  if (err == ERR_OK) {
                    /* move payload to UDP data */
                    pbuf_header(q, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
                    mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src);
                  }
                }
              }
            }
          }
        }
        if (p_header_changed) {
          /* and move payload to UDP data again */
          pbuf_header(p, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
        }
      }
#endif /* SO_REUSE && SO_REUSE_RXTOALL */
      /* callback */
      if (pcb->recv != NULL) {
        /* now the recv function is responsible for freeing p */
        pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src);
      } else {
        /* no recv function registered? then we have to free the pbuf! */
        pbuf_free(p);
        goto end;
      }
    } else {
Exemple #28
0
static struct pbuf *
ip_reass(struct pbuf *p)
{
  struct pbuf *q;
  struct ip_hdr *fraghdr, *iphdr;
  u16_t offset, len;
  u16_t i;
  
  iphdr = (struct ip_hdr *)ip_reassbuf;
  fraghdr = (struct ip_hdr *)p->payload;

  /* If ip_reasstmr is zero, no packet is present in the buffer, so we
     write the IP header of the fragment into the reassembly
     buffer. The timer is updated with the maximum age. */
  if(ip_reasstmr == 0) {
    DEBUGF(IP_REASS_DEBUG, ("ip_reass: new packet\n"));
    memcpy(iphdr, fraghdr, IP_HLEN);
    ip_reasstmr = IP_REASS_MAXAGE;
    ip_reassflags = 0;
    /* Clear the bitmap. */
    bzero(ip_reassbitmap, sizeof(ip_reassbitmap));
  }

  /* Check if the incoming fragment matches the one currently present
     in the reasembly buffer. If so, we proceed with copying the
     fragment into the buffer. */
  if(ip_addr_cmp(&iphdr->src, &fraghdr->src) &&
     ip_addr_cmp(&iphdr->dest, &fraghdr->dest) &&
     IPH_ID(iphdr) == IPH_ID(fraghdr)) {
    DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching old packet\n"));
    /* Find out the offset in the reassembly buffer where we should
       copy the fragment. */
    len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
    offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;

    /* If the offset or the offset + fragment length overflows the
       reassembly buffer, we discard the entire packet. */
    if(offset > IP_REASS_BUFSIZE ||
       offset + len > IP_REASS_BUFSIZE) {
      DEBUGF(IP_REASS_DEBUG, ("ip_reass: fragment outside of buffer (%d:%d/%d).\n",
			      offset, offset + len, IP_REASS_BUFSIZE));
      ip_reasstmr = 0;
      goto nullreturn;
    }

    /* Copy the fragment into the reassembly buffer, at the right
       offset. */
    DEBUGF(IP_REASS_DEBUG, ("ip_reass: copying with offset %d into %d:%d\n",
			    offset, IP_HLEN + offset, IP_HLEN + offset + len));
    memcpy(&ip_reassbuf[IP_HLEN + offset], 
	  (u8_t *)fraghdr + IPH_HL(fraghdr) * 4, len);

    /* Update the bitmap. */
    if(offset / (8 * 8) == (offset + len) / (8 * 8)) {
      DEBUGF(IP_REASS_DEBUG, ("ip_reass: updating single byte in bitmap.\n"));
      /* If the two endpoints are in the same byte, we only update
	 that byte. */
      ip_reassbitmap[offset / (8 * 8)] |=
	bitmap_bits[(offset / 8 ) & 7] &
	~bitmap_bits[((offset + len) / 8 ) & 7];
    } else {
      /* If the two endpoints are in different bytes, we update the
	 bytes in the endpoints and fill the stuff inbetween with
	 0xff. */
      ip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8 ) & 7];
      DEBUGF(IP_REASS_DEBUG, ("ip_reass: updating many bytes in bitmap (%d:%d).\n",
			      1 + offset / (8 * 8), (offset + len) / (8 * 8)));
      for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
	ip_reassbitmap[i] = 0xff;
      }      
      ip_reassbitmap[(offset + len) / (8 * 8)] |= ~bitmap_bits[((offset + len) / 8 ) & 7];
    }
    
    /* If this fragment has the More Fragments flag set to zero, we
       know that this is the last fragment, so we can calculate the
       size of the entire packet. We also set the
       IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
       the final fragment. */

    if((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) {
      ip_reassflags |= IP_REASS_FLAG_LASTFRAG;
      ip_reasslen = offset + len;
      DEBUGF(IP_REASS_DEBUG, ("ip_reass: last fragment seen, total len %d\n", ip_reasslen));
    }
    
    /* Finally, we check if we have a full packet in the buffer. We do
       this by checking if we have the last fragment and if all bits
       in the bitmap are set. */
    if(ip_reassflags & IP_REASS_FLAG_LASTFRAG) {
      /* Check all bytes up to and including all but the last byte in
	 the bitmap. */
      for(i = 0; i < ip_reasslen / (8 * 8) - 1; ++i) {
	if(ip_reassbitmap[i] != 0xff) {
	  DEBUGF(IP_REASS_DEBUG, ("ip_reass: last fragment seen, bitmap %d/%d failed (%x)\n", i, ip_reasslen / (8 * 8) - 1, ip_reassbitmap[i]));
	  goto nullreturn;
	}
      }
      /* Check the last byte in the bitmap. It should contain just the
	 right amount of bits. */
      if(ip_reassbitmap[ip_reasslen / (8 * 8)] !=
	 (u8_t)~bitmap_bits[ip_reasslen / 8 & 7]) {
	DEBUGF(IP_REASS_DEBUG, ("ip_reass: last fragment seen, bitmap %d didn't contain %x (%x)\n",
				ip_reasslen / (8 * 8), ~bitmap_bits[ip_reasslen / 8 & 7],
				ip_reassbitmap[ip_reasslen / (8 * 8)]));
	goto nullreturn;
      }

      /* Pretend to be a "normal" (i.e., not fragmented) IP packet
	 from now on. */
      IPH_OFFSET_SET(iphdr, 0);
      IPH_CHKSUM_SET(iphdr, 0);
#if CHECKSUM_GEN_IP || CHECKSUM_CHECK_IP /* FIXME: correct? */
      IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
#endif
      
      /* If we have come this far, we have a full packet in the
	 buffer, so we allocate a pbuf and copy the packet into it. We
	 also reset the timer. */
      ip_reasstmr = 0;
      pbuf_free(p);
      p = pbuf_alloc(PBUF_LINK, ip_reasslen, PBUF_POOL);
      if(p != NULL) {
	i = 0;
	for(q = p; q != NULL; q = q->next) {
	  /* Copy enough bytes to fill this pbuf in the chain. The
	     avaliable data in the pbuf is given by the q->len
	     variable. */
	  DEBUGF(IP_REASS_DEBUG, ("ip_reass: memcpy from %p (%d) to %p, %d bytes\n",
				  &ip_reassbuf[i], i, q->payload, q->len > ip_reasslen - i? ip_reasslen - i: q->len));
	  memcpy(q->payload, &ip_reassbuf[i],
		q->len > ip_reasslen - i? ip_reasslen - i: q->len);
	  i += q->len;
	}
      }
      DEBUGF(IP_REASS_DEBUG, ("ip_reass: p %p\n", p));
      return p;
    }
  }

 nullreturn:
  pbuf_free(p);
  return NULL;
}
/**
 * Sends an generic or enterprise specific trap message.
 *
 * @param generic_trap is the trap code
 * @param eoid points to enterprise object identifier
 * @param specific_trap used for enterprise traps when generic_trap == 6
 * @return ERR_OK when success, ERR_MEM if we're out of memory
 *
 * @note the caller is responsible for filling in outvb in the trap_msg
 * @note the use of the enterpise identifier field
 * is per RFC1215.
 * Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps
 * and .iso.org.dod.internet.private.enterprises.yourenterprise
 * (sysObjectID) for specific traps.
 */
err_t
snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap)
{
  struct snmp_trap_dst *td;
  struct netif *dst_if;
  struct ip_addr dst_ip;
  struct pbuf *p;
  u16_t i,tot_len;

  for (i=0, td = &trap_dst[0]; i<SNMP_TRAP_DESTINATIONS; i++, td++)
  {
    if ((td->enable != 0) && (td->dip.addr != 0))
    {
      /* network order trap destination */
      trap_msg.dip.addr = td->dip.addr;
      /* lookup current source address for this dst */
      dst_if = ip_route(&td->dip);
      dst_ip.addr = ntohl(dst_if->ip_addr.addr);
      trap_msg.sip_raw[0] = dst_ip.addr >> 24;
      trap_msg.sip_raw[1] = dst_ip.addr >> 16;
      trap_msg.sip_raw[2] = dst_ip.addr >> 8;
      trap_msg.sip_raw[3] = dst_ip.addr;
      trap_msg.gen_trap = generic_trap;
      trap_msg.spc_trap = specific_trap;
      if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC)
      {
        /* enterprise-Specific trap */
        trap_msg.enterprise = eoid;
      }
      else
      {
        /* generic (MIB-II) trap */
        snmp_get_snmpgrpid_ptr(&trap_msg.enterprise);
      }
      snmp_get_sysuptime(&trap_msg.ts);

      /* pass 0, calculate length fields */
      tot_len = snmp_varbind_list_sum(&trap_msg.outvb);
      tot_len = snmp_trap_header_sum(&trap_msg, tot_len);

      /* allocate pbuf(s) */
      p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);
      if (p != NULL)
      {
        u16_t ofs;

        /* pass 1, encode packet ino the pbuf(s) */
        ofs = snmp_trap_header_enc(&trap_msg, p);
        snmp_varbind_list_enc(&trap_msg.outvb, p, ofs);

        snmp_inc_snmpouttraps();
        snmp_inc_snmpoutpkts();

        /** connect to the TRAP destination */
        udp_connect(trap_msg.pcb, &trap_msg.dip, SNMP_TRAP_PORT);
        udp_send(trap_msg.pcb, p);
        /** disassociate remote address and port with this pcb */
        udp_disconnect(trap_msg.pcb);

        pbuf_free(p);
      }
      else
      {
        return ERR_MEM;
      }
    }
  }
Exemple #30
0
/******************************************************************************
 * FunctionName : espconn_udp_sent
 * Description  : sent data for client or server
 * Parameters   : void *arg -- client or server to send
 * 				  uint8* psent -- Data to send
 *                uint16 length -- Length of data to send
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
espconn_udp_sent(void *arg, uint8 *psent, uint16 length)
{
    espconn_msg *pudp_sent = arg;
    struct udp_pcb *upcb = pudp_sent->pcommon.pcb;
    struct pbuf *p, *q;
    u8_t *data = NULL;
    u16_t cnt = 0;
    u16_t datalen = 0;
    u16_t i = 0;
    err_t err;
    LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %d %p\n", __LINE__, length, upcb));

    if (pudp_sent == NULL || upcb == NULL || psent == NULL || length == 0) {
        return;
    }

    if (1024 < length) {
        datalen = 1024;
    } else {
        datalen = length;
    }

    p = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_RAM);
    LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, p));

    if (p != NULL) {
        q = p;

        while (q != NULL) {
            data = (u8_t *)q->payload;
            LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, data));

            for (i = 0; i < q->len; i++) {
                data[i] = ((u8_t *) psent)[cnt++];
            }

            q = q->next;
        }
    } else {
        return;
    }

    upcb->remote_port = pudp_sent->pespconn->proto.udp->remote_port;
    IP4_ADDR(&upcb->remote_ip, pudp_sent->pespconn->proto.udp->remote_ip[0],
    		pudp_sent->pespconn->proto.udp->remote_ip[1],
    		pudp_sent->pespconn->proto.udp->remote_ip[2],
    		pudp_sent->pespconn->proto.udp->remote_ip[3]);

    LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %x %d\n", __LINE__, upcb->remote_ip, upcb->remote_port));
    err = udp_send(upcb, p);
    LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %d\n", __LINE__, err));
    (void)err;

    if (p->ref != 0) {
        LWIP_DEBUGF(ESPCONN_UDP_DEBUG, ("espconn_udp_sent %d %p\n", __LINE__, p));
        pbuf_free(p);
        pudp_sent->pcommon.ptrbuf = psent + datalen;
        pudp_sent->pcommon.cntr = length - datalen;
        espconn_data_sent(pudp_sent);
    }
}