Example #1
0
void ip_addr_set(struct ip_addr *dest, struct ip_addr *src)
{
    SMEMCPY(dest, src, sizeof(struct ip_addr));
    /*  dest->addr[0] = src->addr[0];
       dest->addr[1] = src->addr[1];
       dest->addr[2] = src->addr[2];
       dest->addr[3] = src->addr[3]; */
}
Example #2
0
/** Prepare HELO/EHLO message */
static enum smtp_session_state
smtp_prepare_helo(struct smtp_session *s, u16_t *tx_buf_len, struct tcp_pcb *pcb)
{
  size_t ipa_len;
  char *ipa = ipaddr_ntoa(&pcb->local_ip);
  LWIP_ASSERT("ipaddr_ntoa returned NULL", ipa != NULL);
  ipa_len = strlen(ipa);
  LWIP_ASSERT("string too long", ipa_len <= 0xffff);

  *tx_buf_len = SMTP_CMD_EHLO_1_LEN + (u16_t)ipa_len + SMTP_CMD_EHLO_2_LEN;
  LWIP_ASSERT("tx_buf overflow detected", *tx_buf_len <= SMTP_TX_BUF_LEN);

  SMEMCPY(s->tx_buf, SMTP_CMD_EHLO_1, SMTP_CMD_EHLO_1_LEN);
  MEMCPY(&s->tx_buf[SMTP_CMD_EHLO_1_LEN], ipa, ipa_len);
  SMEMCPY(&s->tx_buf[SMTP_CMD_EHLO_1_LEN + ipa_len], SMTP_CMD_EHLO_2, SMTP_CMD_EHLO_2_LEN);
  return SMTP_HELO;
}
Example #3
0
/** Prepare QUIT message */
static enum smtp_session_state
smtp_prepare_quit(struct smtp_session *s, u16_t *tx_buf_len)
{
  *tx_buf_len = SMTP_CMD_QUIT_LEN;
  s->tx_buf[*tx_buf_len] = 0;
  SMEMCPY(s->tx_buf, SMTP_CMD_QUIT, SMTP_CMD_QUIT_LEN);
  LWIP_ASSERT("tx_buf overflow detected", *tx_buf_len <= SMTP_TX_BUF_LEN);
  return SMTP_CLOSED;
}
Example #4
0
/**
 * Resolve and fill-in Ethernet address header for outgoing IPv6 packet.
 *
 * For IPv6 multicast, corresponding Ethernet addresses
 * are selected and the packet is transmitted on the link.
 *
 * For unicast addresses, ...
 *
 * @TODO anycast addresses
 *
 * @param netif The lwIP network interface which the IP packet will be sent on.
 * @param q The pbuf(s) containing the IP packet to be sent.
 * @param ip6addr The IP address of the packet destination.
 *
 * @return
 * - ERR_RTE No route to destination (no gateway to external networks),
 * or the return type of either etharp_query() or etharp_send_ip().
 */
err_t
ethip6_output(struct netif *netif, struct pbuf *q, ip6_addr_t *ip6addr)
{
  struct eth_addr dest;
  s8_t i;

  /* make room for Ethernet header - should not fail */
  if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
    /* bail out */
    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
      ("etharp_output: could not allocate room for header.\n"));
    return ERR_BUF;
  }

  /* multicast destination IP address? */
  if (ip6_addr_ismulticast(ip6addr)) {
    /* Hash IP multicast address to MAC address.*/
    dest.addr[0] = 0x33;
    dest.addr[1] = 0x33;
    dest.addr[2] = ((u8_t *)(&(ip6addr->addr[3])))[0];
    dest.addr[3] = ((u8_t *)(&(ip6addr->addr[3])))[1];
    dest.addr[4] = ((u8_t *)(&(ip6addr->addr[3])))[2];
    dest.addr[5] = ((u8_t *)(&(ip6addr->addr[3])))[3];

    /* Send out. */
    return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest);
  }

  /* We have a unicast destination IP address */
  /* TODO anycast? */
  /* Get next hop record. */
  i = nd6_get_next_hop_entry(ip6addr, netif);
  if (i < 0) {
    /* failed to get a next hop neighbor record. */
    return ERR_MEM;
  }

  /* Now that we have a destination record, send or queue the packet. */
  if (neighbor_cache[i].state == ND6_STALE) {
    /* Switch to delay state. */
    neighbor_cache[i].state = ND6_DELAY;
    neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME;
  }
  /* TODO should we send or queue if PROBE? send for now, to let unicast NS pass. */
  if ((neighbor_cache[i].state == ND6_REACHABLE) ||
      (neighbor_cache[i].state == ND6_DELAY) ||
      (neighbor_cache[i].state == ND6_PROBE)) {

    /* Send out. */
    SMEMCPY(dest.addr, neighbor_cache[i].lladdr, 6);
    return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest);
  }

  /* We should queue packet on this interface. */
  pbuf_header(q, -(s16_t)SIZEOF_ETH_HDR);
  return nd6_queue_packet(i, q);
}
Example #5
0
static bool convert_lwip_addr_to_mbed(nsapi_addr_t *out, const ip_addr_t *in)
{
#if LWIP_IPV6
    if (IP_IS_V6(in)) {
        out->version = NSAPI_IPv6;
        SMEMCPY(out->bytes, ip_2_ip6(in), sizeof(ip6_addr_t));
        return true;
    }
#endif
#if LWIP_IPV4
    if (IP_IS_V4(in)) {
        out->version = NSAPI_IPv4;
        SMEMCPY(out->bytes, ip_2_ip4(in), sizeof(ip4_addr_t));
        return true;
    }
#endif
#if LWIP_IPV6 && LWIP_IPV4
    return false;
#endif
}
Example #6
0
/**
 * Free a datagram (struct ip_reassdata) and all its pbufs.
 * Updates the total count of enqueued pbufs (ip_reass_pbufcount),
 * SNMP counters and sends an ICMP time exceeded packet.
 *
 * @param ipr datagram to free
 * @param prev the previous datagram in the linked list
 * @return the number of pbufs freed
 */
static int
ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
{
  u16_t pbufs_freed = 0;
  u8_t clen;
  struct pbuf *p;
  struct ip_reass_helper *iprh;

  LWIP_ASSERT("prev != ipr", prev != ipr);
  if (prev != NULL) {
    LWIP_ASSERT("prev->next == ipr", prev->next == ipr);
  }

  snmp_inc_ipreasmfails();
#if LWIP_ICMP
  iprh = (struct ip_reass_helper *)ipr->p->payload;
  if (iprh->start == 0) {
    /* The first fragment was received, send ICMP time exceeded. */
    /* First, de-queue the first pbuf from r->p. */
    p = ipr->p;
    ipr->p = iprh->next_pbuf;
    /* Then, copy the original header into it. */
    SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN);
    icmp_time_exceeded(p, ICMP_TE_FRAG);
    clen = pbuf_clen(p);
    LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
    pbufs_freed += clen;
    pbuf_free(p);
  }
#endif /* LWIP_ICMP */

  /* First, free all received pbufs.  The individual pbufs need to be released 
     separately as they have not yet been chained */
  p = ipr->p;
  while (p != NULL) {
    struct pbuf *pcur;
    iprh = (struct ip_reass_helper *)p->payload;
    pcur = p;
    /* get the next pointer before freeing */
    p = iprh->next_pbuf;
    clen = pbuf_clen(pcur);
    LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
    pbufs_freed += clen;
    pbuf_free(pcur);
  }
  /* Then, unchain the struct ip_reassdata from the list and free it. */
  ip_reass_dequeue_datagram(ipr, prev);
  LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed);
  ip_reass_pbufcount -= pbufs_freed;

  return pbufs_freed;
}
static void
create_arp_response(ip_addr_t *adr)
{
  int k;
  struct eth_hdr *ethhdr;
  struct etharp_hdr *etharphdr;
  struct pbuf *p = pbuf_alloc(PBUF_RAW, sizeof(struct eth_hdr) + sizeof(struct etharp_hdr), PBUF_RAM);
  if(p == NULL) {
    FAIL_RET();
  }
  ethhdr = (struct eth_hdr*)p->payload;
  etharphdr = (struct etharp_hdr*)(ethhdr + 1);

  ethhdr->dest = test_ethaddr;
  ethhdr->src = test_ethaddr2;
  ethhdr->type = htons(ETHTYPE_ARP);

  etharphdr->hwtype = htons(/*HWTYPE_ETHERNET*/ 1);
  etharphdr->proto = htons(ETHTYPE_IP);
  etharphdr->hwlen = ETHARP_HWADDR_LEN;
  etharphdr->protolen = sizeof(ip_addr_t);
  etharphdr->opcode = htons(ARP_REPLY);

  SMEMCPY(&etharphdr->sipaddr, adr, sizeof(ip_addr_t));
  SMEMCPY(&etharphdr->dipaddr, &test_ipaddr, sizeof(ip_addr_t));

  k = 6;
  while(k > 0) {
    k--;
    /* Write the ARP MAC-Addresses */
    etharphdr->shwaddr.addr[k] = test_ethaddr2.addr[k];
    etharphdr->dhwaddr.addr[k] = test_ethaddr.addr[k];
    /* Write the Ethernet MAC-Addresses */
    ethhdr->dest.addr[k] = test_ethaddr.addr[k];
    ethhdr->src.addr[k]  = test_ethaddr2.addr[k];
  }

  ethernet_input(p, &test_netif);
}
Example #8
0
/**
 * Send an icmp packet in response to an incoming packet.
 *
 * @param p the input packet for which the 'unreachable' should be sent,
 *          p->payload pointing to the IP header
 * @param type Type of the ICMP header
 * @param code Code of the ICMP header
 */
static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
{
    struct pbuf *q;
    struct ip_hdr *iphdr;

    /* we can use the echo header here */
    struct icmp_echo_hdr *icmphdr;

    /* ICMP header + IP header + 8 bytes of data */
    q =
      pbuf_alloc(PBUF_IP,
                 sizeof(struct icmp_echo_hdr) + IP_HLEN +
                 ICMP_DEST_UNREACH_DATASIZE, PBUF_RAM);
    if (q == NULL) {
        LWIP_DEBUGF(ICMP_DEBUG,
                    ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
        return;
    }
    LWIP_ASSERT("check that first pbuf can hold icmp message",
                (q->len >=
                 (sizeof(struct icmp_echo_hdr) + IP_HLEN +
                  ICMP_DEST_UNREACH_DATASIZE)));

    iphdr = p->payload;
    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
    ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
    LWIP_DEBUGF(ICMP_DEBUG, (" to "));
    ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
    LWIP_DEBUGF(ICMP_DEBUG, ("\n"));

    icmphdr = q->payload;
    icmphdr->type = type;
    icmphdr->code = code;
    icmphdr->id = 0;
    icmphdr->seqno = 0;

    /* copy fields from original packet */
    SMEMCPY((u8_t *) q->payload + sizeof(struct icmp_echo_hdr),
            (u8_t *) p->payload, IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);

    /* calculate checksum */
    icmphdr->chksum = 0;
    icmphdr->chksum = inet_chksum(icmphdr, q->len);
    ICMP_STATS_INC(icmp.xmit);
    /* increase number of messages attempted to send */
    snmp_inc_icmpoutmsgs();
    /* increase number of destination unreachable messages attempted to send */
    snmp_inc_icmpouttimeexcds();
    ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP);
    pbuf_free(q);
}
Example #9
0
/**
 * Send an icmp packet in response to an incoming packet.
 *
 * @param p the input packet for which the 'unreachable' should be sent,
 *          p->payload pointing to the IP header
 * @param type Type of the ICMP header
 * @param code Code of the ICMP header
 */
static void ICACHE_FLASH_ATTR
icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
{
  struct pbuf *q;
  struct ip_hdr *iphdr;
  /* we can use the echo header here */
  struct icmp_echo_hdr *icmphdr;
  ip_addr_t iphdr_src;

  /* ICMP header + IP header + 8 bytes of data */
  //为差错报文申请pbuf空间,pbuf中预留IP首部和以太网首部空间,pbuf数据区
  //长度=差错报文首部+差错报文数据长度(IP首部长度+8)
  q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
                 PBUF_RAM);
  if (q == NULL) {//失败,返回
    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
    return;
  }
  LWIP_ASSERT("check that first pbuf can hold icmp message",
             (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));

  iphdr = (struct ip_hdr *)p->payload;//指向引起差错的IP数据包首部
  LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
  LWIP_DEBUGF(ICMP_DEBUG, (" to "));
  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
  LWIP_DEBUGF(ICMP_DEBUG, ("\n"));

  icmphdr = (struct icmp_echo_hdr *)q->payload;//指向差错报文首部
  icmphdr->type = type;//填写类型字段
  icmphdr->code = code;//填写代码字段
  icmphdr->id = 0;//对于目的不可达和数据报超时
  icmphdr->seqno = 0;//报文,首部剩余的4个字节都为0

  /* copy fields from original packet 将引起差错的IP数据报的IP首部+8字节数据拷贝到差错报文数据区*/
  SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,
          IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);

  /* calculate checksum */
  icmphdr->chksum = 0;//报文校验和字段清0
  icmphdr->chksum = inet_chksum(icmphdr, q->len);//计算填写校验和
  ICMP_STATS_INC(icmp.xmit);
  /* increase number of messages attempted to send */
  snmp_inc_icmpoutmsgs();
  /* increase number of destination unreachable messages attempted to send */
  snmp_inc_icmpouttimeexcds();
  ip_addr_copy(iphdr_src, iphdr->src);
  ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP);//调用IP层函数输出ICMP报文
  pbuf_free(q);
}
/**
 * Free a datagram (struct ip6_reassdata) and all its pbufs.
 * Updates the total count of enqueued pbufs (ip6_reass_pbufcount),
 * sends an ICMP time exceeded packet.
 *
 * @param ipr datagram to free
 */
static void
ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr)
{
  struct ip6_reassdata **pipr;
  u16_t pbufs_freed = 0;
  u8_t clen;
  struct pbuf *p;
  struct ip6_reass_helper *iprh;

  /* First, free all received pbufs.  The individual pbufs need to be released
     separately as they have not yet been chained */
  iprh = ipr->iprh;
  while (iprh != NULL) {
    struct ip6_reass_helper *next = iprh->next;
    p = iprh->p;

#if LWIP_ICMP6
    /* If the first fragment was received, send ICMP time exceeded. */
    if (iprh->start == 0) {
      SMEMCPY(ipr->iphdr0, &ipr->iphdr, IP6_HLEN);
      if (pbuf_header(p, (u8_t *)p->payload - (u8_t *)ipr->iphdr0) == 0) {
        icmp6_time_exceeded(p, ICMP6_TE_FRAG);
      }
      else {
        LWIP_ASSERT("ip6_reass_free: moving p->payload to ip6 header failed\n", 0);
      }
    }
#endif /* LWIP_ICMP6 */

    clen = pbuf_clen(p);
    LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
    pbufs_freed += clen;
    pbuf_free(p);

    iprh = next;
  }

  /* Then, unchain the struct ip6_reassdata from the list and free it. */
  for (pipr = &reassdatagrams; *pipr != NULL; pipr = &(*pipr)->next) {
    if (*pipr == ipr) {
      (*pipr) = ipr->next;
      break;
    }
  }
  memp_free(MEMP_IP6_REASSDATA, ipr);

  /* Finally, update number of pbufs in reassembly queue */
  LWIP_ASSERT("ip_reass_pbufcount >= clen", ip6_reass_pbufcount >= pbufs_freed);
  ip6_reass_pbufcount -= pbufs_freed;
}
Example #11
0
/** Send base64-encoded username */
static enum smtp_session_state
smtp_prepare_auth_login_uname(struct smtp_session *s, u16_t *tx_buf_len)
{
  size_t base64_len = smtp_base64_encode(s->tx_buf, SMTP_TX_BUF_LEN,
    SMTP_USERNAME(s), strlen(SMTP_USERNAME(s)));
  /* @todo: support base64-encoded longer than 64k */
  LWIP_ASSERT("string too long", base64_len <= 0xffff);
  LWIP_ASSERT("tx_buf overflow detected", base64_len + SMTP_CRLF_LEN <= SMTP_TX_BUF_LEN);
  *tx_buf_len = (u16_t)base64_len + SMTP_CRLF_LEN;

  SMEMCPY(&s->tx_buf[base64_len], SMTP_CRLF, SMTP_CRLF_LEN);
  s->tx_buf[*tx_buf_len] = 0;
  return SMTP_AUTH_LOGIN_PASS;
}
Example #12
0
static err_t 
netif_init(struct netif *netif)
{
  netif->linkoutput = netif_output;
  netif->output     = etharp_output;
  netif->output_ip6 = ethip6_output;
  netif->mtu        = ETHERNET_MTU;
  netif->flags      = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP | NETIF_FLAG_MLD6;
  MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 100000000);

  SMEMCPY(netif->hwaddr, your_mac_address_goes_here, sizeof(netif->hwaddr));
  netif->hwaddr_len = sizeof(netif->hwaddr);

  return ERR_OK;
}
Example #13
0
/**
 * Resolve and fill-in Ethernet address header for outgoing IPv6 packet.
 *
 * For IPv6 multicast, corresponding Ethernet addresses
 * are selected and the packet is transmitted on the link.
 *
 * For unicast addresses, ...
 *
 * @todo anycast addresses
 *
 * @param netif The lwIP network interface which the IP packet will be sent on.
 * @param q The pbuf(s) containing the IP packet to be sent.
 * @param ip6addr The IP address of the packet destination.
 *
 * @return
 * - ERR_RTE No route to destination (no gateway to external networks),
 * or the return type of either nd6_queue_packet() or ethernet_output().
 */
err_t
ethip6_output(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr)
{
  struct eth_addr dest;
  s8_t i;

  /* multicast destination IP address? */
  if (ip6_addr_ismulticast(ip6addr)) {
    /* Hash IP multicast address to MAC address.*/
    dest.addr[0] = 0x33;
    dest.addr[1] = 0x33;
    dest.addr[2] = ((const u8_t *)(&(ip6addr->addr[3])))[0];
    dest.addr[3] = ((const u8_t *)(&(ip6addr->addr[3])))[1];
    dest.addr[4] = ((const u8_t *)(&(ip6addr->addr[3])))[2];
    dest.addr[5] = ((const u8_t *)(&(ip6addr->addr[3])))[3];

    /* Send out. */
    return ethernet_output(netif, q, (struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6);
  }

  /* We have a unicast destination IP address */
  /* @todo anycast? */
  /* Get next hop record. */
  i = nd6_get_next_hop_entry(ip6addr, netif);
  if (i < 0) {
    /* failed to get a next hop neighbor record. */
    return ERR_MEM;
  }

  /* Now that we have a destination record, send or queue the packet. */
  if (neighbor_cache[i].state == ND6_STALE) {
    /* Switch to delay state. */
    neighbor_cache[i].state = ND6_DELAY;
    neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL;
  }
  /* @todo should we send or queue if PROBE? send for now, to let unicast NS pass. */
  if ((neighbor_cache[i].state == ND6_REACHABLE) ||
      (neighbor_cache[i].state == ND6_DELAY) ||
      (neighbor_cache[i].state == ND6_PROBE)) {

    /* Send out. */
    SMEMCPY(dest.addr, neighbor_cache[i].lladdr, 6);
    return ethernet_output(netif, q, (struct eth_addr*)(netif->hwaddr), &dest, ETHTYPE_IPV6);
  }

  /* We should queue packet on this interface. */
  return nd6_queue_packet(i, q);
}
Example #14
0
/**
 * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0.
 *
 * @param p the input packet for which the 'time exceeded' should be sent,
 *          p->payload pointing to the IP header
 * @param t type of the 'time exceeded' packet
 */
void
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
{
  struct pbuf *q;
  struct ip_hdr *iphdr;
  struct icmp_te_hdr *tehdr;

  /* ICMP header + IP header + 8 bytes of data */
  q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
                 PBUF_RAM);
  if (q == NULL) {
    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
    return;
  }
  LWIP_ASSERT("check that first pbuf can hold icmp message",
             (q->len >= (sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));

  iphdr = (struct ip_hdr *) p->payload;
  LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
  LWIP_DEBUGF(ICMP_DEBUG, (" to "));
  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
  LWIP_DEBUGF(ICMP_DEBUG, ("\n"));

  tehdr = (struct icmp_te_hdr *) q->payload;
  ICMPH_TYPE_SET(tehdr, ICMP_TE);
  ICMPH_CODE_SET(tehdr, t);

  /* copy fields from original packet */
  SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_dur_hdr), (u8_t *)p->payload,
          IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);

  /* calculate checksum */
  tehdr->chksum = 0;
  tehdr->chksum = inet_chksum(tehdr, q->len);
  ICMP_STATS_INC(icmp.xmit);
  /* increase number of messages attempted to send */
  snmp_inc_icmpoutmsgs();
  /* increase number of destination unreachable messages attempted to send */
  snmp_inc_icmpouttimeexcds();
  ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP);
  pbuf_free(q);
}
Example #15
0
/**
 * Send an icmp 'destination unreachable' packet, called from ip_input() if
 * the transport layer protocol is unknown and from udp_input() if the local
 * port is not bound.
 *
 * @param p the input packet for which the 'unreachable' should be sent,
 *          p->payload pointing to the IP header
 * @param t type of the 'unreachable' packet
 */
void
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
{
  struct pbuf *q;
  struct ip_hdr *iphdr;
  struct icmp_dur_hdr *idur;

  /* ICMP header + IP header + 8 bytes of data */
  q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
                 PBUF_RAM);
  if (q == NULL) {
    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
    return;
  }
  LWIP_ASSERT("check that first pbuf can hold icmp message",
             (q->len >= (sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));

  iphdr = p->payload;

  idur = q->payload;
  ICMPH_TYPE_SET(idur, ICMP_DUR);
  ICMPH_CODE_SET(idur, t);

  SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_dur_hdr), p->payload,
          IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);

  /* calculate checksum */
  idur->chksum = 0;
  idur->chksum = inet_chksum(idur, q->len);
  ICMP_STATS_INC(icmp.xmit);
  /* increase number of messages attempted to send */
  snmp_inc_icmpoutmsgs();
  /* increase number of destination unreachable messages attempted to send */
  snmp_inc_icmpoutdestunreachs();

  ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP);
  pbuf_free(q);
}
Example #16
0
void
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
{
    struct pbuf *q;
    struct ip_hdr *iphdr;
    struct icmp_te_hdr *tehdr;

    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n"));

    /* @todo: can this be PBUF_LINK instead of PBUF_IP? */
    q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
    /* ICMP header + IP header + 8 bytes of data */
    if (q == NULL) {
        LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
        pbuf_free(p);
        return;
    }
    LWIP_ASSERT("check that first pbuf can hold icmp message",
                (q->len >= (8 + IP_HLEN + 8)));

    iphdr = p->payload;

    tehdr = q->payload;
    tehdr->type = (u8_t)ICMP6_TE;
    tehdr->icode = (u8_t)t;

    /* copy fields from original packet */
    SMEMCPY((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8);

    /* calculate checksum */
    tehdr->chksum = 0;
    tehdr->chksum = inet_chksum(tehdr, q->len);
    ICMP_STATS_INC(icmp.xmit);
    ip_output(q, NULL,
              (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
    pbuf_free(q);
}
Example #17
0
/**
 * SNTP request
 */
static void sntp_request()
{
	int                sock;
	struct sockaddr_in local;
	struct sockaddr_in to;
	int                tolen;
	int                size;
	int                timeout;
	u8_t               sntp_request [SNTP_MAX_DATA_LEN];
	u8_t               sntp_response[SNTP_MAX_DATA_LEN];
	u32_t              sntp_server_address;
	u32_t              timestamp;
	time_t             t;

	/* initialize SNTP server address */
	sntp_server_address = SNTP_SERVER_ADDRESS;

	/* if we got a valid SNTP server address... */
	if (sntp_server_address!=0)
	{
		/* create new socket */
		sock = socket( AF_INET, SOCK_DGRAM, 0);
		if (sock>=0)
		{
			/* prepare local address */
			memset(&local, 0, sizeof(local));
			local.sin_family      = AF_INET;
			local.sin_port        = htons(INADDR_ANY);
			local.sin_addr.s_addr = htonl(INADDR_ANY);

			/* bind to local address */
			if (bind( sock, (struct sockaddr *)&local, sizeof(local))==0)
			{
				/* set recv timeout */
				timeout = SNTP_RECV_TIMEOUT;
				setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));

				/* prepare SNTP request */
				memset( sntp_request, 0, sizeof(sntp_request));
				sntp_request[0] = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT;

				/* prepare SNTP server address */
				memset(&to, 0, sizeof(to));
				to.sin_family      = AF_INET;
				to.sin_port        = htons(SNTP_PORT);
				to.sin_addr.s_addr = sntp_server_address;

				/* send SNTP request to server */
				if (sendto( sock, sntp_request, sizeof(sntp_request), 0, (struct sockaddr *)&to, sizeof(to))>=0)
				{
					/* receive SNTP server response */
					tolen = sizeof(to);
					size  = recvfrom( sock, sntp_response, sizeof(sntp_response), 0, (struct sockaddr *)&to, (socklen_t *)&tolen);

					/* if the response size is good */
					if (size == SNTP_MAX_DATA_LEN)
					{
						/* if this is a SNTP response... */
						if (((sntp_response[0] & SNTP_MODE_MASK) == SNTP_MODE_SERVER) || ((sntp_response[0] & SNTP_MODE_MASK) == SNTP_MODE_BROADCAST))
						{
							/* extract GMT time from response */
							SMEMCPY( &timestamp, (sntp_response+SNTP_RCV_TIME_OFS), sizeof(timestamp));
							t = (ntohl(timestamp) - DIFF_SEC_1900_1970);

							/* do time processing */
							sntp_process(t);

						}
						else
						{
							LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not response frame code\n"));
						}
					}
					else
					{
						LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not recvfrom==%i\n", errno));
					}
				}
				else
				{
					LWIP_DEBUGF( SNTP_DEBUG, ("sntp_request: not sendto==%i\n", errno));
				}
			}
			/* close the socket */
			closesocket(sock);
		}
	}
}
Example #18
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, const ip_addr_t *ipaddr)
{
  err_t err;
  struct netif *netif;
  ipX_addr_t *src_ip;
  struct pbuf *q; /* q will be sent down the stack */
  s16_t header_size;
  const ipX_addr_t *dst_ip = ip_2_ipX(ipaddr);

  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));

  header_size = (
#if LWIP_IPV6
    PCB_ISIPV6(pcb) ? IP6_HLEN :
#endif /* LWIP_IPV6 */
    IP_HLEN);

  /* not enough space to add an IP header to first pbuf in given p chain? */
  if (pbuf_header(p, header_size)) {
    /* 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, -header_size)) {
      LWIP_ASSERT("Can't restore header we just removed!", 0);
      return ERR_MEM;
    }
  }

  netif = ipX_route(PCB_ISIPV6(pcb), &pcb->local_ip, dst_ip);
  if (netif == NULL) {
    LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to "));
    ipX_addr_debug_print(PCB_ISIPV6(pcb), RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, dst_ip);
    /* free any temporary header pbuf allocated by pbuf_header() */
    if (q != p) {
      pbuf_free(q);
    }
    return ERR_RTE;
  }

#if IP_SOF_BROADCAST
#if LWIP_IPV6
  if (!PCB_ISIPV6(pcb))
#endif /* LWIP_IPV6 */
  {
    /* 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 (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) {
    /* use outgoing network interface IP address as source address */
    src_ip = ipX_netif_get_local_ipX(PCB_ISIPV6(pcb), netif, dst_ip);
#if LWIP_IPV6
    if (src_ip == NULL) {
      if (q != p) {
        pbuf_free(q);
      }
      return ERR_RTE;
    }
#endif /* LWIP_IPV6 */
  } else {
    /* use RAW PCB local IP address as source address */
    src_ip = &pcb->local_ip;
  }

#if LWIP_IPV6
  /* If requested, based on the IPV6_CHECKSUM socket option per RFC3542,
     compute the checksum and update the checksum in the payload. */
  if (PCB_ISIPV6(pcb) && pcb->chksum_reqd) {
    u16_t chksum = ip6_chksum_pseudo(p, pcb->protocol, p->tot_len, ipX_2_ip6(src_ip), ipX_2_ip6(dst_ip));
    LWIP_ASSERT("Checksum must fit into first pbuf", p->len >= (pcb->chksum_offset + 2));
    SMEMCPY(((u8_t *)p->payload) + pcb->chksum_offset, &chksum, sizeof(u16_t));
  }
#endif

  NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
  err = ipX_output_if(PCB_ISIPV6(pcb), q, ipX_2_ip(src_ip), ipX_2_ip(dst_ip), 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;
}
Example #19
0
/**
 * Fragment an IPv6 datagram if too large for the netif or path MTU.
 *
 * Chop the datagram in MTU sized chunks and send them in order
 * by pointing PBUF_REFs into p
 *
 * @param p ipv6 packet to send
 * @param netif the netif on which to send
 * @param dest destination ipv6 address to which to send
 *
 * @return ERR_OK if sent successfully, err_t otherwise
 */
err_t
ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest)
{
  struct ip6_hdr *original_ip6hdr;
  struct ip6_hdr *ip6hdr;
  struct ip6_frag_hdr *frag_hdr;
  struct pbuf *rambuf;
#if !LWIP_NETIF_TX_SINGLE_PBUF
  struct pbuf *newpbuf;
  u16_t newpbuflen = 0;
  u16_t left_to_copy;
#endif
  static u32_t identification;
  u16_t nfb;
  u16_t left, cop;
  u16_t mtu;
  u16_t fragment_offset = 0;
  u16_t last;
  u16_t poff = IP6_HLEN;

  identification++;

  original_ip6hdr = (struct ip6_hdr *)p->payload;

  mtu = nd6_get_destination_mtu(dest, netif);

  /* @todo we assume there are no options in the unfragmentable part (IPv6 header). */
  left = p->tot_len - IP6_HLEN;

  nfb = (mtu - (IP6_HLEN + IP6_FRAG_HLEN)) & IP6_FRAG_OFFSET_MASK;

  while (left) {
    last = (left <= nfb);

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

#if LWIP_NETIF_TX_SINGLE_PBUF
    rambuf = pbuf_alloc(PBUF_IP, cop + IP6_FRAG_HLEN, PBUF_RAM);
    if (rambuf == NULL) {
      IP6_FRAG_STATS_INC(ip6_frag.memerr);
      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, (u8_t*)rambuf->payload + IP6_FRAG_HLEN, cop, poff);
    /* make room for the IP header */
    if (pbuf_header(rambuf, IP6_HLEN)) {
      pbuf_free(rambuf);
      IP6_FRAG_STATS_INC(ip6_frag.memerr);
      return ERR_MEM;
    }
    /* fill in the IP header */
    SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN);
    ip6hdr = (struct ip6_hdr *)rambuf->payload;
    frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN);
#else
    /* When not using a static buffer, create a chain of pbufs.
     * The first will be a PBUF_RAM holding the link, IPv6, and Fragment 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, IP6_HLEN + IP6_FRAG_HLEN, PBUF_RAM);
    if (rambuf == NULL) {
      IP6_FRAG_STATS_INC(ip6_frag.memerr);
      return ERR_MEM;
    }
    LWIP_ASSERT("this needs a pbuf in one piece!",
                (p->len >= (IP6_HLEN)));
    SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN);
    ip6hdr = (struct ip6_hdr *)rambuf->payload;
    frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN);

    /* Can just adjust p directly for needed offset. */
    p->payload = (u8_t *)p->payload + poff;
    p->len -= poff;
    p->tot_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 = ip6_frag_alloc_pbuf_custom_ref();
      if (pcr == NULL) {
        pbuf_free(rambuf);
        IP6_FRAG_STATS_INC(ip6_frag.memerr);
        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) {
        ip6_frag_free_pbuf_custom_ref(pcr);
        pbuf_free(rambuf);
        IP6_FRAG_STATS_INC(ip6_frag.memerr);
        return ERR_MEM;
      }
      pbuf_ref(p);
      pcr->original = p;
      pcr->pc.custom_free_function = ip6_frag_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 */

    /* Set headers */
    frag_hdr->_nexth = original_ip6hdr->_nexth;
    frag_hdr->reserved = 0;
    frag_hdr->_fragment_offset = lwip_htons((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG));
    frag_hdr->_identification = lwip_htonl(identification);

    IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT);
    IP6H_PLEN_SET(ip6hdr, cop + IP6_FRAG_HLEN);

    /* No need for separate header pbuf - we allowed room for it in rambuf
     * when allocated.
     */
    IP6_FRAG_STATS_INC(ip6_frag.xmit);
    netif->output_ip6(netif, rambuf, dest);

    /* 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);
    left -= cop;
    fragment_offset += cop;
  }
  return ERR_OK;
}
Example #20
0
/**
 * Send an ICMPv6 packet in response to an incoming packet.
 *
 * @param p the input packet for which the response should be sent,
 *          p->payload pointing to the IPv6 header
 * @param code Code of the ICMPv6 header
 * @param data Additional 32-bit parameter in the ICMPv6 header
 * @param type Type of the ICMPv6 header
 */
static void
icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type)
{
  struct pbuf *q;
  struct icmp6_hdr *icmp6hdr;
  ip6_addr_t *reply_src, *reply_dest;
  ip6_addr_t reply_src_local, reply_dest_local;
  struct ip6_hdr *ip6hdr;
  struct interface *netif;

  /* ICMPv6 header + IPv6 header + data */
  q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE,
                 PBUF_RAM);
  if (q == NULL) {
    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n"));
    ICMP6_STATS_INC(icmp6.memerr);
    return;
  }
  LWIP_ASSERT("check that first pbuf can hold icmp 6message",
             (q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE)));

  icmp6hdr = (struct icmp6_hdr *)q->payload;
  icmp6hdr->type = type;
  icmp6hdr->code = code;
  icmp6hdr->data = data;

  /* copy fields from original packet */
  SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload,
          IP6_HLEN + LWIP_ICMP6_DATASIZE);

  /* Get the destination address and netif for this ICMP message. */
  if ((ip_current_netif() == NULL) ||
      ((code == ICMP6_TE_FRAG) && (type == ICMP6_TYPE_TE))) {
    /* Special case, as ip6_current_xxx is either NULL, or points
     * to a different packet than the one that expired.
     * We must use the addresses that are stored in the expired packet. */
    ip6hdr = (struct ip6_hdr *)p->payload;
    /* copy from packed address to aligned address */
    ip6_addr_copy(reply_dest_local, ip6hdr->src);
    ip6_addr_copy(reply_src_local, ip6hdr->dest);
    reply_dest = &reply_dest_local;
    reply_src = &reply_src_local;
    netif = ip6_route(reply_src, reply_dest);
    if (netif == NULL) {
      /* drop */
      pbuf_free(q);
      ICMP6_STATS_INC(icmp6.rterr);
      return;
    }
  }
  else {
    netif = ip_current_netif();
    reply_dest = ip6_current_src_addr();

    /* Select an address to use as source. */
    reply_src = ip6_select_source_address(netif, reply_dest);
    if (reply_src == NULL) {
      /* drop */
      pbuf_free(q);
      ICMP6_STATS_INC(icmp6.rterr);
      return;
    }
  }

  /* calculate checksum */
  icmp6hdr->chksum = 0;
  icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len,
    reply_src, reply_dest);

  ICMP6_STATS_INC(icmp6.xmit);
  ip6_output_if(q, reply_src, reply_dest, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif);
  pbuf_free(q);
}
Example #21
0
/** State machine-like implementation of an SMTP client.
 */
static void
smtp_process(void *arg, struct tcp_pcb *pcb, struct pbuf *p)
{
  struct smtp_session* s = arg;
  u16_t response_code = 0;
  u16_t tx_buf_len = 0;
  enum smtp_session_state next_state;

  if (arg == NULL) {
    /* already closed SMTP connection */
    if (p != NULL) {
      LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("Received %d bytes after closing: %s\n",
        p->tot_len, smtp_pbuf_str(p)));
      pbuf_free(p);
    }
    return;
  }

  next_state = s->state;

  if (p != NULL) {
    /* received data */
    if (s->p == NULL) {
      s->p = p;
    } else {
      pbuf_cat(s->p, p);
    }
  } else {
    /* idle timer, close connection if timed out */
    if (s->timer == 0) {
      LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_process: connection timed out, closing\n"));
      smtp_close(s, pcb, SMTP_RESULT_ERR_TIMEOUT, 0, ERR_TIMEOUT);
      return;
    }
    if (s->state == SMTP_BODY) {
      smtp_send_body(s, pcb);
      return;
    }
  }
  response_code = smtp_is_response(s);
  if (response_code) {
    LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process: received response code: %d\n", response_code));
    if (smtp_is_response_finished(s) != ERR_OK) {
      LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process: partly received response code: %d\n", response_code));
      /* wait for next packet to complete the respone */
      return;
    }
  } else {
    if (s->p != NULL) {
      LWIP_DEBUGF(SMTP_DEBUG_WARN, ("smtp_process: unknown data received (%s)\n",
        smtp_pbuf_str(s->p)));
      pbuf_free(s->p);
      s->p = NULL;
    }
    return;
  }

  switch(s->state)
  {
  case(SMTP_NULL):
    /* wait for 220 */
    if (response_code == 220) {
      /* then send EHLO */
      next_state = smtp_prepare_helo(s, &tx_buf_len, pcb);
    }
    break;
  case(SMTP_HELO):
    /* wait for 250 */
    if (response_code == 250) {
#if SMTP_SUPPORT_AUTH_AUTH || SMTP_SUPPORT_AUTH_LOGIN
      /* then send AUTH or MAIL */
      next_state = smtp_prepare_auth_or_mail(s, &tx_buf_len);
    }
    break;
  case(SMTP_AUTH_LOGIN):
  case(SMTP_AUTH_PLAIN):
    /* wait for 235 */
    if (response_code == 235) {
#endif /* SMTP_SUPPORT_AUTH_AUTH || SMTP_SUPPORT_AUTH_LOGIN */
      /* send MAIL */
      next_state = smtp_prepare_mail(s, &tx_buf_len);
    }
    break;
#if SMTP_SUPPORT_AUTH_LOGIN
  case(SMTP_AUTH_LOGIN_UNAME):
    /* wait for 334 Username */
    if (response_code == 334) {
      if (pbuf_strstr(s->p, SMTP_RESP_LOGIN_UNAME) != 0xFFFF) {
        /* send username */
        next_state = smtp_prepare_auth_login_uname(s, &tx_buf_len);
      }
    }
    break;
  case(SMTP_AUTH_LOGIN_PASS):
    /* wait for 334 Password */
    if (response_code == 334) {
      if (pbuf_strstr(s->p, SMTP_RESP_LOGIN_PASS) != 0xFFFF) {
        /* send username */
        next_state = smtp_prepare_auth_login_pass(s, &tx_buf_len);
      }
    }
    break;
#endif /* SMTP_SUPPORT_AUTH_LOGIN */
  case(SMTP_MAIL):
    /* wait for 250 */
    if (response_code == 250) {
      /* send RCPT */
      next_state = smtp_prepare_rcpt(s, &tx_buf_len);
    }
    break;
  case(SMTP_RCPT):
    /* wait for 250 */
    if (response_code == 250) {
      /* send DATA */
      SMEMCPY(s->tx_buf, SMTP_CMD_DATA, SMTP_CMD_DATA_LEN);
      tx_buf_len = SMTP_CMD_DATA_LEN;
      next_state = SMTP_DATA;
    }
    break;
  case(SMTP_DATA):
    /* wait for 354 */
    if (response_code == 354) {
      /* send email header */
      next_state = smtp_prepare_header(s, &tx_buf_len);
    }
    break;
  case(SMTP_BODY):
    /* nothing to be done here, handled somewhere else */
    break;
  case(SMTP_QUIT):
    /* wait for 250 */
    if (response_code == 250) {
      /* send QUIT */
      next_state = smtp_prepare_quit(s, &tx_buf_len);
    }
    break;
  case(SMTP_CLOSED):
    /* nothing to do, wait for connection closed from server */
    return;
  default:
    LWIP_DEBUGF(SMTP_DEBUG_SERIOUS, ("Invalid state: %d/%s\n", (int)s->state,
      smtp_state_str[s->state]));
    break;
  }
  if (s->state == next_state) {
    LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_process[%s]: unexpected response_code, closing: %d (%s)\n",
      smtp_state_str[s->state], response_code, smtp_pbuf_str(s->p)));
    /* close connection */
    smtp_close(s, pcb, SMTP_RESULT_ERR_SVR_RESP, response_code, ERR_OK);
    return;
  }
  if (tx_buf_len > 0) {
    SMTP_TX_BUF_MAX(tx_buf_len);
    if (tcp_write(pcb, s->tx_buf, tx_buf_len, TCP_WRITE_FLAG_COPY) == ERR_OK) {
      LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process[%s]: received command %d (%s)\n",
        smtp_state_str[s->state], response_code, smtp_pbuf_str(s->p)));
      LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process[%s]: sent %"U16_F" bytes: \"%s\"\n",
        smtp_state_str[s->state], tx_buf_len, s->tx_buf));
      s->timer = SMTP_TIMEOUT;
      pbuf_free(s->p);
      s->p = NULL;
      LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_process: changing state from %s to %s\n",
        smtp_state_str[s->state], smtp_state_str[next_state]));
      s->state = next_state;
      if (next_state == SMTP_BODY) {
        /* try to stream-send body data right now */
        smtp_send_body(s, pcb);
      } else if (next_state == SMTP_CLOSED) {
        /* sent out all data, delete structure */
        tcp_arg(pcb, NULL);
        smtp_free(s, SMTP_RESULT_OK, 0, ERR_OK);
      }
    }
  }
}
Example #22
0
File: sip_api.c Project: lzjsqn/19
int recvfrom(int s, void *mem, int len, unsigned int flags,
        struct sockaddr *from, socklen_t *fromlen)
{
	struct lwip_socket *sock;
	struct skbuff      *buf;
	u16_t               buflen, copylen, off = 0;
	struct ip_addr     *addr;
	u16_t               port;
	u8_t                done = 0;

	sock = get_socket(s);
	if (!sock)
		return -1;

	do {
		/* Check if there is data left from the last recv operation. */
		if (sock->lastdata) 
		{
			buf = sock->lastdata;
		} 
		else 
		{
			/* If this is non-blocking call, then check first */
			if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) && !sock->rcvevent) 
			{
				return -1;
			}

			/* No data was left from the previous operation, so we try to get
			some from the network. */
			sock->lastdata = buf = netconn_recv(sock->conn);

			if (!buf) 
			{
				/* We should really do some error checking here. */
				return 0;
			}
		}

		buflen = netbuf_len(buf);

		buflen -= sock->lastoffset;
		if (len > buflen) 
		{
			copylen = buflen;
		} 
		else 
		{
			copylen = len;
		}

		/* copy the contents of the received buffer into
		the supplied memory pointer mem */
		netbuf_copy_partial(buf, (u8_t*)mem + off, copylen, sock->lastoffset);
		off += copylen;

		if (netconn_type(sock->conn) == NETCONN_TCP) 
		{
			len -= copylen;
			if ( (len <= 0) || (buf->p->flags & PBUF_FLAG_PUSH) || !sock->rcvevent) 
			{
				done = 1;
			}
		} 
		else 
		{
			done = 1;
		}

		/* If we don't peek the incoming message... */
		if ((flags & MSG_PEEK)==0) 
		{
			/* If this is a TCP socket, check if there is data left in the
			buffer. If so, it should be saved in the sock structure for next
			time around. */
			if ((sock->conn->type == NETCONN_TCP) && (buflen - copylen > 0)) 
			{
				sock->lastdata = buf;
				sock->lastoffset += copylen;
			} 
			else 
			{
				sock->lastdata = NULL;
				sock->lastoffset = 0;
				netbuf_delete(buf);
			}
		} 
		else 
		{
			done = 1;
		}
	} while (!done);

	/* Check to see from where the data was.*/
	if (from && fromlen) 
	{
		struct sockaddr_in sin;

		if (netconn_type(sock->conn) == NETCONN_TCP) 
		{
			addr = (struct ip_addr*)&(sin.sin_addr.s_addr);
			netconn_getaddr(sock->conn, addr, &port, 0);
		} 
		else 
		{
			addr = netbuf_fromaddr(buf);
			port = netbuf_fromport(buf);
		}

		memset(&sin, 0, sizeof(sin));
		sin.sin_len = sizeof(sin);
		sin.sin_family = AF_INET;
		sin.sin_port = htons(port);
		sin.sin_addr.s_addr = addr->addr;

		if (*fromlen > sizeof(sin))
			*fromlen = sizeof(sin);

		SMEMCPY(from, &sin, *fromlen);
	} 

	return off;
}
/**
 * Reassembles incoming IPv6 fragments into an IPv6 datagram.
 *
 * @param p points to the IPv6 Fragment Header
 * @param len the length of the payload (after Fragment Header)
 * @return NULL if reassembly is incomplete, pbuf pointing to
 *         IPv6 Header if reassembly is complete
 */
struct pbuf *
ip6_reass(struct pbuf *p)
{
  struct ip6_reassdata *ipr, **pipr;
  struct ip6_reass_helper *iprh, *iprh_tmp;
  struct ip6_reass_helper **pnext;
  struct ip6_frag_hdr * frag_hdr;
  size_t unfrag_len;
  u16_t offset, len, start, end, validlen;
  u8_t clen;

  IP6_FRAG_STATS_INC(ip6_frag.recv);

  frag_hdr = (struct ip6_frag_hdr *) p->payload;

  clen = pbuf_clen(p);

  offset = ntohs(frag_hdr->_fragment_offset);

  /* Calculate fragment length from IPv6 payload length.
   * Adjust for headers before Fragment Header.
   * And finally adjust by Fragment Header length. */
  len = ntohs(ip6_current_header()->_plen);
  len -= ((u8_t*)p->payload - (u8_t*)ip6_current_header()) - IP6_HLEN;
  len -= IP6_FRAG_HLEN;

  start = (offset & IP6_FRAG_OFFSET_MASK);
  end = start + len;


  /* Look for the datagram the fragment belongs to in the current datagram queue,
   * remembering the previous in the queue for later dequeueing. */
  for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {
    /* Check if the incoming fragment matches the one currently present
       in the reassembly buffer. If so, we proceed with copying the
       fragment into the buffer. */
    if ((frag_hdr->_identification == ipr->identification) &&
        ip6_addr_cmp(ip6_current_src_addr(), &(ipr->iphdr.src)) &&
        ip6_addr_cmp(ip6_current_dest_addr(), &(ipr->iphdr.dest))) {
      IP6_FRAG_STATS_INC(ip6_frag.cachehit);
      break;
    }
  }

  if (ipr == NULL) {
  /* Enqueue a new datagram into the datagram queue */
    ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA);
    if (ipr == NULL) {
#if IP_REASS_FREE_OLDEST
      /* Make room and try again. */
      ip6_reass_remove_oldest_datagram(ipr, clen);
      ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA);
      if (ipr == NULL)
#endif /* IP_REASS_FREE_OLDEST */
      {
        IP6_FRAG_STATS_INC(ip6_frag.memerr);
        IP6_FRAG_STATS_INC(ip6_frag.drop);
        goto nullreturn;
      }
    }

    memset(ipr, 0, sizeof(struct ip6_reassdata));
    ipr->timer = IP_REASS_MAXAGE;

    /* enqueue the new structure to the front of the list */
    ipr->next = reassdatagrams;
    reassdatagrams = ipr;

    /* Use the current IPv6 header for src/dest address reference.
     * Eventually, we will replace it when we get the first fragment
     * (it might be this one, in any case, it is done later). */
    SMEMCPY(&ipr->iphdr, ip6_current_header(), IP6_HLEN);
    if (start == 0) {
      ipr->iphdr0 = (struct ip6_hdr *)ip6_current_header();
    }

    /* copy the fragmented packet id. */
    ipr->identification = frag_hdr->_identification;
  }

  /* If this is the last fragment, save total packet length. */
  if ((offset & IP6_FRAG_MORE_FLAG) == 0) {
#if IP_REASS_CHECK_OVERLAP
    if (ipr->datagram_len != 0) {
      IP6_FRAG_STATS_INC(ip6_frag.proterr);
      IP6_FRAG_STATS_INC(ip6_frag.drop);
      goto nullreturn;
    }
#endif /* IP_REASS_CHECK_OVERLAP */
    ipr->datagram_len = end;
  }

  /* find the place to insert this pbuf */
  validlen = 0;
  for (pnext = &ipr->iprh; *pnext != NULL; pnext = &(*pnext)->next) {
    iprh_tmp = *pnext;

    if (start < iprh_tmp->start) {
      /* the new pbuf should be inserted before this */
#if IP_REASS_CHECK_OVERLAP
      if (end > iprh_tmp->start) {
        /* fragment overlaps with following, throw away */
        IP6_FRAG_STATS_INC(ip6_frag.proterr);
        IP6_FRAG_STATS_INC(ip6_frag.drop);
        goto nullreturn;
      }
#endif /* IP_REASS_CHECK_OVERLAP */
      break;
    }
    else if (start == iprh_tmp->start) {
      /* received the same datagram twice: no need to keep the datagram */
      IP6_FRAG_STATS_INC(ip6_frag.drop);
      goto nullreturn;
    }
#if IP_REASS_CHECK_OVERLAP
    else if (start < iprh_tmp->end) {
      /* overlap: no need to keep the new datagram */
      IP6_FRAG_STATS_INC(ip6_frag.proterr);
      IP6_FRAG_STATS_INC(ip6_frag.drop);
      goto nullreturn;
    }
#endif /* IP_REASS_CHECK_OVERLAP */
    else {
      /* Check if the fragments received so far have no gaps. */
      if (validlen == iprh_tmp->start) {
        validlen = iprh_tmp->end;
      }
      else {
        validlen = 0;
      }
    }
  }

  /* Check if we are allowed to enqueue more datagrams. */
  if ((ip6_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {
#if IP_REASS_FREE_OLDEST
    ip6_reass_remove_oldest_datagram(ipr, clen);
    if ((ip6_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS)
#endif /* IP_REASS_FREE_OLDEST */
    {
      /* @todo: send ICMPv6 time exceeded here? */
      /* drop this pbuf */
      IP6_FRAG_STATS_INC(ip6_frag.memerr);
      IP6_FRAG_STATS_INC(ip6_frag.drop);
      goto nullreturn;
    }
  }

  if (start == 0 && ipr->iphdr0 == NULL) {
    /*
     * We've got the fragment with offset 0 out of order, remember its
     * IPv6 header location (in the hidden part of the current pbuf)
     * and update the copy in ip6_reassdata::iphdr.  We don't need to
     * copy complete header since src and dest are the same as in the
     * first fragment we received.
     */
    ipr->iphdr0 = (struct ip6_hdr *)ip6_current_header();
    SMEMCPY(&ipr->iphdr, ip6_current_header(),
            IP6_HLEN - 2 * sizeof(ip_addr_p_t));
  }

  /* Overwrite IPv6 Header with our own helper struct (aligned). */
  iprh = (struct ip6_reass_helper *)
    (((uintptr_t)(u8_t *)ip6_current_header() + sizeof(void *) - 1)
     & ~(sizeof(void *) - 1));
  iprh->p = p;
  iprh->start = start;
  iprh->end = end;

  /* insert it into the list */
  iprh->next = *pnext;
  *pnext = iprh;

  /* Track the current number of pbufs current 'in-flight', in order to limit
  the number of fragments that may be enqueued at any one time */
  ip6_reass_pbufcount += clen;

  if (ipr->datagram_len == 0) {
    /* We still don't have the last fragment. */
    return NULL;
  }

  if (validlen == start) {
    validlen = end;
  }
  else {
    /* There are gaps before this fragment. */
    return NULL;
  }

  if (validlen != 0) {
    /*
     * We know we have all the data up to the end of this fragment and
     * we know the total length.  Check if the reassembly is complete.
     */
    for (iprh_tmp = iprh->next; iprh_tmp != NULL; iprh_tmp = iprh_tmp->next) {
      if (validlen == iprh_tmp->start) {
        validlen = iprh_tmp->end;
      }
      else {
        validlen = 0;
        break;
      }
    }

    if (validlen != ipr->datagram_len) {
      /* the datagram is not yet reassembled completely */
      return NULL;
    }
  }

  /*
   * All fragments have been received.  Reassemble original datagram
   * and return it to ip6_input() to be processed instead of the final
   * fragment that completed the reassembly.
   */

  /* chain together the pbufs contained within the ip6_reassdata list. */
  p = NULL;
  for (iprh = ipr->iprh; iprh != NULL; iprh = iprh->next) {
    if (p == NULL) {
      p = iprh->p;
    }
    else {
      /* hide the fragment header for every succeeding fragment */
      pbuf_header(iprh->p, -IP6_FRAG_HLEN);
      pbuf_cat(p, iprh->p);
    }
  }

  /* Adjust datagram length by adding preceding header lengths. */
  unfrag_len = (u8_t *)p->payload - (u8_t *)ipr->iphdr0;
# ifndef VBOX
  ipr->datagram_len += unfrag_len - IP6_HLEN + IP6_FRAG_HLEN;
# else
  LWIP_ASSERT("overflow", (s16_t)unfrag_len == (ssize_t)unfrag_len); /* s16_t because of pbuf_header call */
  ipr->datagram_len += (u16_t)(unfrag_len - IP6_HLEN + IP6_FRAG_HLEN);
# endif

  /* Set payload length in ip header. */
  ipr->iphdr._plen = htons(ipr->datagram_len);

  /* restore IPv6 header (overwritten with ip6_reass_helper) */
  SMEMCPY(ipr->iphdr0, &ipr->iphdr, IP6_HLEN);

  /* Mark as "single fragment" packet (see caller). */
  frag_hdr = (struct ip6_frag_hdr *) p->payload;
  frag_hdr->_fragment_offset = 0;

  /* Unlink from the reassdatagrams list */
  for (pipr = &reassdatagrams; *pipr != NULL; pipr = &(*pipr)->next) {
    if (*pipr == ipr) {
      (*pipr) = ipr->next;
      break;
    }
  }
  memp_free(MEMP_IP6_REASSDATA, ipr);

  /* adjust the number of pbufs currently queued for reassembly. */
  ip6_reass_pbufcount -= pbuf_clen(p);

  /* Move pbuf back to IPv6 header. */
# ifndef VBOX
  if (pbuf_header(p, unfrag_len) != 0) {
# else
  if (pbuf_header(p, (s16_t)unfrag_len) != 0) {
# endif
    LWIP_ASSERT("ip6_reass: moving p->payload to ip6 header failed\n", 0);
    goto nullreturn;
  }

  /* Return the pbuf chain */
  return p;

nullreturn:
  pbuf_free(p);
  return NULL;
}

#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */

#if LWIP_IPV6 && LWIP_IPV6_FRAG

/** Allocate a new struct pbuf_custom_ref */
static struct pbuf_custom_ref*
ip6_frag_alloc_pbuf_custom_ref(void)
{
  return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF);
}

/** Free a struct pbuf_custom_ref */
static void
ip6_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p)
{
  LWIP_ASSERT("p != NULL", p != NULL);
  memp_free(MEMP_FRAG_PBUF, p);
}
Example #24
0
/**
 * Reassembles incoming IP fragments into an IP datagram.
 *
 * @param p points to a pbuf chain of the fragment
 * @return NULL if reassembly is incomplete, ? otherwise
 */
struct pbuf *
ip_reass(struct pbuf *p)
{
  struct pbuf *r;
  struct ip_hdr *fraghdr;
  struct ip_reassdata *ipr;
  struct ip_reass_helper *iprh;
  u16_t offset, len;
  u8_t clen;
  struct ip_reassdata *ipr_prev = NULL;

  IPFRAG_STATS_INC(ip_frag.recv);
  snmp_inc_ipreasmreqds();

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

  if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {
    LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n"));
    IPFRAG_STATS_INC(ip_frag.err);
    goto nullreturn;
  }

  offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
  len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;

  /* Check if we are allowed to enqueue more datagrams. */
  clen = pbuf_clen(p);
  if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {
#if IP_REASS_FREE_OLDEST
    if (!ip_reass_remove_oldest_datagram(fraghdr, clen) ||
        ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS))
#endif /* IP_REASS_FREE_OLDEST */
    {
      /* No datagram could be freed and still too many pbufs enqueued */
      LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",
        ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS));
      IPFRAG_STATS_INC(ip_frag.memerr);
      /* @todo: send ICMP time exceeded here? */
      /* drop this pbuf */
      goto nullreturn;
    }
  }

  /* Look for the datagram the fragment belongs to in the current datagram queue,
   * remembering the previous in the queue for later dequeueing. */
  for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {
    /* Check if the incoming fragment matches the one currently present
       in the reassembly buffer. If so, we proceed with copying the
       fragment into the buffer. */
    if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n",
        ntohs(IPH_ID(fraghdr))));
      IPFRAG_STATS_INC(ip_frag.cachehit);
      break;
    }
    ipr_prev = ipr;
  }

  if (ipr == NULL) {
  /* Enqueue a new datagram into the datagram queue */
    ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);
    /* Bail if unable to enqueue */
    if(ipr == NULL) {
      goto nullreturn;
    }
  } else {
    if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) && 
      ((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
      /* ipr->iphdr is not the header from the first fragment, but fraghdr is
       * -> copy fraghdr into ipr->iphdr since we want to have the header
       * of the first fragment (for ICMP time exceeded and later, for copying
       * all options, if supported)*/
      SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);
    }
  }
  /* Track the current number of pbufs current 'in-flight', in order to limit 
  the number of fragments that may be enqueued at any one time */
  ip_reass_pbufcount += clen;

  /* At this point, we have either created a new entry or pointing 
   * to an existing one */

  /* check for 'no more fragments', and update queue entry*/
  if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) {
    ipr->flags |= IP_REASS_FLAG_LASTFRAG;
    ipr->datagram_len = offset + len;
    LWIP_DEBUGF(IP_REASS_DEBUG,
     ("ip_reass: last fragment seen, total len %"S16_F"\n",
      ipr->datagram_len));
  }
  /* find the right place to insert this pbuf */
  /* @todo: trim pbufs if fragments are overlapping */
  if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {
    /* the totally last fragment (flag more fragments = 0) was received at least
     * once AND all fragments are received */
    ipr->datagram_len += IP_HLEN;

    /* save the second pbuf before copying the header over the pointer */
    r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf;

    /* copy the original ip header back to the first pbuf */
    fraghdr = (struct ip_hdr*)(ipr->p->payload);
    SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);
    IPH_LEN_SET(fraghdr, htons(ipr->datagram_len));
    IPH_OFFSET_SET(fraghdr, 0);
    IPH_CHKSUM_SET(fraghdr, 0);
    /* @todo: do we need to set calculate the correct checksum? */
    IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));

    p = ipr->p;

    /* chain together the pbufs contained within the reass_data list. */
    while(r != NULL) {
      iprh = (struct ip_reass_helper*)r->payload;

      /* hide the ip header for every succeding fragment */
      pbuf_header(r, -IP_HLEN);
      pbuf_cat(p, r);
      r = iprh->next_pbuf;
    }
    /* release the sources allocate for the fragment queue entry */
    ip_reass_dequeue_datagram(ipr, ipr_prev);

    /* and adjust the number of pbufs currently queued for reassembly. */
    ip_reass_pbufcount -= pbuf_clen(p);

    /* Return the pbuf chain */
    return p;
  }
  /* the datagram is not (yet?) reassembled completely */
  LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount));
  return NULL;

nullreturn:
  LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n"));
  IPFRAG_STATS_INC(ip_frag.drop);
  pbuf_free(p);
  return NULL;
}
Example #25
0
/**
 * @ingroup lwip_nosys
 * Process received ethernet frames. Using this function instead of directly
 * calling ip_input and passing ARP frames through etharp in ethernetif_input,
 * the ARP cache is protected from concurrent access.\n
 * Don't call directly, pass to netif_add() and call netif->input().
 *
 * @param p the received packet, p->payload pointing to the ethernet header
 * @param netif the network interface on which the packet was received
 *
 * @see LWIP_HOOK_UNKNOWN_ETH_PROTOCOL
 * @see ETHARP_SUPPORT_VLAN
 * @see LWIP_HOOK_VLAN_CHECK
 */
err_t
ethernet_input(struct pbuf *p, struct netif *netif)
{
  struct eth_hdr *ethhdr;
  u16_t type;
#if LWIP_ARP || ETHARP_SUPPORT_VLAN || LWIP_IPV6
  u16_t next_hdr_offset = SIZEOF_ETH_HDR;
#endif /* LWIP_ARP || ETHARP_SUPPORT_VLAN */

  LWIP_ASSERT_CORE_LOCKED();

  if (p->len <= SIZEOF_ETH_HDR) {
    /* a packet with only an ethernet header (or less) is not valid for us */
    ETHARP_STATS_INC(etharp.proterr);
    ETHARP_STATS_INC(etharp.drop);
    MIB2_STATS_NETIF_INC(netif, ifinerrors);
    goto free_and_return;
  }

  if (p->if_idx == NETIF_NO_INDEX) {
    p->if_idx = netif_get_index(netif);
  }

  /* points to packet payload, which starts with an Ethernet header */
  ethhdr = (struct eth_hdr *)p->payload;
  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
              ("ethernet_input: dest:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", src:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", type:%"X16_F"\n",
               (unsigned char)ethhdr->dest.addr[0], (unsigned char)ethhdr->dest.addr[1], (unsigned char)ethhdr->dest.addr[2],
               (unsigned char)ethhdr->dest.addr[3], (unsigned char)ethhdr->dest.addr[4], (unsigned char)ethhdr->dest.addr[5],
               (unsigned char)ethhdr->src.addr[0],  (unsigned char)ethhdr->src.addr[1],  (unsigned char)ethhdr->src.addr[2],
               (unsigned char)ethhdr->src.addr[3],  (unsigned char)ethhdr->src.addr[4],  (unsigned char)ethhdr->src.addr[5],
               lwip_htons(ethhdr->type)));

  type = ethhdr->type;
#if ETHARP_SUPPORT_VLAN
  if (type == PP_HTONS(ETHTYPE_VLAN)) {
    struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr *)(((char *)ethhdr) + SIZEOF_ETH_HDR);
    if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) {
      /* a packet with only an ethernet/vlan header (or less) is not valid for us */
      ETHARP_STATS_INC(etharp.proterr);
      ETHARP_STATS_INC(etharp.drop);
      MIB2_STATS_NETIF_INC(netif, ifinerrors);
      goto free_and_return;
    }
#if defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */
#ifdef LWIP_HOOK_VLAN_CHECK
    if (!LWIP_HOOK_VLAN_CHECK(netif, ethhdr, vlan)) {
#elif defined(ETHARP_VLAN_CHECK_FN)
    if (!ETHARP_VLAN_CHECK_FN(ethhdr, vlan)) {
#elif defined(ETHARP_VLAN_CHECK)
    if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) {
#endif
      /* silently ignore this packet: not for our VLAN */
      pbuf_free(p);
      return ERR_OK;
    }
#endif /* defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */
    type = vlan->tpid;
    next_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR;
  }
#endif /* ETHARP_SUPPORT_VLAN */

#if LWIP_ARP_FILTER_NETIF
  netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, lwip_htons(type));
#endif /* LWIP_ARP_FILTER_NETIF*/

  if (ethhdr->dest.addr[0] & 1) {
    /* this might be a multicast or broadcast packet */
    if (ethhdr->dest.addr[0] == LL_IP4_MULTICAST_ADDR_0) {
#if LWIP_IPV4
      if ((ethhdr->dest.addr[1] == LL_IP4_MULTICAST_ADDR_1) &&
          (ethhdr->dest.addr[2] == LL_IP4_MULTICAST_ADDR_2)) {
        /* mark the pbuf as link-layer multicast */
        p->flags |= PBUF_FLAG_LLMCAST;
      }
#endif /* LWIP_IPV4 */
    }
#if LWIP_IPV6
    else if ((ethhdr->dest.addr[0] == LL_IP6_MULTICAST_ADDR_0) &&
             (ethhdr->dest.addr[1] == LL_IP6_MULTICAST_ADDR_1)) {
      /* mark the pbuf as link-layer multicast */
      p->flags |= PBUF_FLAG_LLMCAST;
    }
#endif /* LWIP_IPV6 */
    else if (eth_addr_cmp(&ethhdr->dest, &ethbroadcast)) {
      /* mark the pbuf as link-layer broadcast */
      p->flags |= PBUF_FLAG_LLBCAST;
    }
  }

  switch (type) {
#if LWIP_IPV4 && LWIP_ARP
    /* IP packet? */
    case PP_HTONS(ETHTYPE_IP):
      if (!(netif->flags & NETIF_FLAG_ETHARP)) {
        goto free_and_return;
      }
      /* skip Ethernet header */
      if ((p->len < next_hdr_offset) || pbuf_remove_header(p, next_hdr_offset)) {
        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
                    ("ethernet_input: IPv4 packet dropped, too short (%"U16_F"/%"U16_F")\n",
                     p->tot_len, next_hdr_offset));
        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet"));
        goto free_and_return;
      } else {
        /* pass to IP layer */
        ip4_input(p, netif);
      }
      break;

    case PP_HTONS(ETHTYPE_ARP):
      if (!(netif->flags & NETIF_FLAG_ETHARP)) {
        goto free_and_return;
      }
      /* skip Ethernet header */
      if ((p->len < next_hdr_offset) || pbuf_remove_header(p, next_hdr_offset)) {
        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
                    ("ethernet_input: ARP response packet dropped, too short (%"U16_F"/%"U16_F")\n",
                     p->tot_len, next_hdr_offset));
        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet"));
        ETHARP_STATS_INC(etharp.lenerr);
        ETHARP_STATS_INC(etharp.drop);
        goto free_and_return;
      } else {
        /* pass p to ARP module */
        etharp_input(p, netif);
      }
      break;
#endif /* LWIP_IPV4 && LWIP_ARP */
#if PPPOE_SUPPORT
    case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */
      pppoe_disc_input(netif, p);
      break;

    case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */
      pppoe_data_input(netif, p);
      break;
#endif /* PPPOE_SUPPORT */

#if LWIP_IPV6
    case PP_HTONS(ETHTYPE_IPV6): /* IPv6 */
      /* skip Ethernet header */
      if ((p->len < next_hdr_offset) || pbuf_remove_header(p, next_hdr_offset)) {
        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
                    ("ethernet_input: IPv6 packet dropped, too short (%"U16_F"/%"U16_F")\n",
                     p->tot_len, next_hdr_offset));
        goto free_and_return;
      } else {
        /* pass to IPv6 layer */
        ip6_input(p, netif);
      }
      break;
#endif /* LWIP_IPV6 */

    default:
#ifdef LWIP_HOOK_UNKNOWN_ETH_PROTOCOL
      if (LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(p, netif) == ERR_OK) {
        break;
      }
#endif
      ETHARP_STATS_INC(etharp.proterr);
      ETHARP_STATS_INC(etharp.drop);
      MIB2_STATS_NETIF_INC(netif, ifinunknownprotos);
      goto free_and_return;
  }

  /* This means the pbuf is freed or consumed,
     so the caller doesn't have to free it again */
  return ERR_OK;

free_and_return:
  pbuf_free(p);
  return ERR_OK;
}

/**
 * @ingroup ethernet
 * Send an ethernet packet on the network using netif->linkoutput().
 * The ethernet header is filled in before sending.
 *
 * @see LWIP_HOOK_VLAN_SET
 *
 * @param netif the lwIP network interface on which to send the packet
 * @param p the packet to send. pbuf layer must be @ref PBUF_LINK.
 * @param src the source MAC address to be copied into the ethernet header
 * @param dst the destination MAC address to be copied into the ethernet header
 * @param eth_type ethernet type (@ref lwip_ieee_eth_type)
 * @return ERR_OK if the packet was sent, any other err_t on failure
 */
err_t
ethernet_output(struct netif * netif, struct pbuf * p,
                const struct eth_addr * src, const struct eth_addr * dst,
                u16_t eth_type) {
  struct eth_hdr *ethhdr;
  u16_t eth_type_be = lwip_htons(eth_type);

#if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET)
  s32_t vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type);
  if (vlan_prio_vid >= 0) {
    struct eth_vlan_hdr *vlanhdr;

    LWIP_ASSERT("prio_vid must be <= 0xFFFF", vlan_prio_vid <= 0xFFFF);

    if (pbuf_add_header(p, SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) != 0) {
      goto pbuf_header_failed;
    }
    vlanhdr = (struct eth_vlan_hdr *)(((u8_t *)p->payload) + SIZEOF_ETH_HDR);
    vlanhdr->tpid     = eth_type_be;
    vlanhdr->prio_vid = lwip_htons((u16_t)vlan_prio_vid);

    eth_type_be = PP_HTONS(ETHTYPE_VLAN);
  } else
#endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */
  {
    if (pbuf_add_header(p, SIZEOF_ETH_HDR) != 0) {
      goto pbuf_header_failed;
    }
  }

  LWIP_ASSERT_CORE_LOCKED();

  ethhdr = (struct eth_hdr *)p->payload;
  ethhdr->type = eth_type_be;
  SMEMCPY(&ethhdr->dest, dst, ETH_HWADDR_LEN);
  SMEMCPY(&ethhdr->src,  src, ETH_HWADDR_LEN);

  LWIP_ASSERT("netif->hwaddr_len must be 6 for ethernet_output!",
              (netif->hwaddr_len == ETH_HWADDR_LEN));
  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
              ("ethernet_output: sending packet %p\n", (void *)p));

  /* send the packet */
  return netif->linkoutput(netif, p);

pbuf_header_failed:
  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
              ("ethernet_output: could not allocate room for header.\n"));
  LINK_STATS_INC(link.lenerr);
  return ERR_BUF;
}
Example #26
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;
}
Example #27
0
/**
 * Initializes and sets up a netfront interface for lwIP.
 * This function should be passed as a parameter to netfrontif_add().
 *
 * @param netif
 *  the lwip network interface structure for this netfrontif
 * @return
 *  ERR_OK if the interface was successfully initialized;
 *  An err_t value otherwise
 */
err_t netfrontif_init(struct netif *netif)
{
    struct netfrontif *nfi;
    static uint8_t netfrontif_id = 0;

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

    if (!(netif->state)) {
	nfi = mem_calloc(1, sizeof(*nfi));
	if (!nfi) {
	    LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_init: "
				      "Could not allocate \n"));
	    goto err_out;
	}
	netif->state = nfi;
	nfi->_state_is_private = 1;
	nfi->_dev_is_private = 1;
	nfi->_hwaddr_is_private = 1;
    } else {
	nfi = netif->state;
	nfi->_state_is_private = 0;
	nfi->_dev_is_private = !(nfi->dev);
	nfi->_hwaddr_is_private = eth_addr_cmp(&nfi->hwaddr, &ethzero);
    }

    /* Netfront */
    if (nfi->_dev_is_private) {
	/* user did not provide an opened netfront, we need to do it here */
	if (!nfi->_state_is_private) {
	    /* use vif_id to open an specific NIC interface */
	    /* Note: netfront will duplicate the passed nodename */
	    char nodename[128];

	    snprintf(nodename, sizeof(nodename), "device/vif/%u", nfi->vif_id);
	    nfi->dev = init_netfront(nodename, NULL, NULL, NULL);
	} else {
	    /* open the next available net interface */
	    nfi->dev = init_netfront(NULL, NULL, NULL, NULL);
	}
	if (!nfi->dev) {
	    LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_init: "
				      "Could not init netfront\n"));
	    goto err_free_nfi;
	}
    }

    netfront_set_rx_pbuf_handler(nfi->dev, netfrontif_rx_handler, netif);

    /* Interface identifier */
    netif->name[0] = NETFRONTIF_NPREFIX;
    netif->name[1] = '0' + netfrontif_id;
    netfrontif_id++;

    /* We directly use etharp_output() here to save a function call.
     * Instead, there could be function declared that calls etharp_output()
     * only if there is a link is available... */
    netif->output = etharp_output;
    netif->linkoutput = netfrontif_transmit;
#if LWIP_NETIF_REMOVE_CALLBACK
    netif->remove_callback = netfrontif_exit;
#endif /* CONFIG_NETIF_REMOVE_CALLBACK */

    /* Hardware address */
    if (nfi->_hwaddr_is_private) {
	if (!netfront_get_hwaddr(nfi->dev, &nfi->hwaddr)) {
	    LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_init: %c%c: "
				      "Could not retrieve hardware address\n",
				      netif->name[0], netif->name[1]));
	    goto err_shutdown_netfront;
	}
    } else {
	LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_init: %c%c: "
				  "Overwriting hardware address\n",
				  netif->name[0], netif->name[1]));
    }
    SMEMCPY(&netif->hwaddr, &nfi->hwaddr, ETHARP_HWADDR_LEN);
    netif->hwaddr_len = ETHARP_HWADDR_LEN;
    LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_init: %c%c: hardware address: "
			      "%02x:%02x:%02x:%02x:%02x:%02x\n",
			      netif->name[0], netif->name[1],
			      netif->hwaddr[0],
			      netif->hwaddr[1],
			      netif->hwaddr[2],
			      netif->hwaddr[3],
			      netif->hwaddr[4],
			      netif->hwaddr[5]));

    /* Initialize the snmp variables and counters inside the struct netif.
     * The last argument is the link speed, in units of bits per second. */
    NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, NETFRONTIF_SPEED);
    LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_init: %c%c: Link speed: %llu bps\n",
			      netif->name[0], netif->name[1], NETFRONTIF_SPEED));

    /* Device capabilities */
    netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;

    /* Maximum transfer unit */
    netif->mtu = NETFRONTIF_MTU;
    LWIP_DEBUGF(NETIF_DEBUG, ("netfrontif_init: %c%c: MTU: %u\n",
			      netif->name[0], netif->name[1], netif->mtu));

#if LWIP_NETIF_HOSTNAME
    /* Initialize interface hostname */
    if (!netif->hostname)
	netif->hostname = NULL;
#endif /* LWIP_NETIF_HOSTNAME */

#ifndef CONFIG_LWIP_NOTHREADS
  nfi->_thread_exit = 0;
  nfi->_thread_name[0] = netif->name[0];
  nfi->_thread_name[1] = netif->name[1];
  nfi->_thread_name[2] = '-';
  nfi->_thread_name[3] = 'r';
  nfi->_thread_name[4] = 'x';
  nfi->_thread_name[5] = '\0';
  create_thread(nfi->_thread_name, netfrontif_thread, netif);
#endif /* CONFIG_LWIP_NOTHREADS */

    return ERR_OK;

err_shutdown_netfront:
    if (nfi->_dev_is_private) {
        shutdown_netfront(nfi->dev);
        nfi->dev = NULL;
    }
err_free_nfi:
    if (nfi->_state_is_private) {
	mem_free(nfi);
	netif->state = NULL;
    }
err_out:
    return ERR_IF;
}