コード例 #1
0
ファイル: icmp.c プロジェクト: ErichStyger/lwip_k60
/**
 * 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;
//#if CHECKSUM_GEN_ICMP/*FSL*/  
  icmphdr->chksum = inet_chksum(icmphdr, q->len);
//#endif
  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);
}
コード例 #2
0
ファイル: tcp_helper.c プロジェクト: 10code/lwip
/** Create a TCP segment usable for passing to tcp_input */
struct pbuf*
tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip,
                   u16_t src_port, u16_t dst_port, void* data, size_t data_len,
                   u32_t seqno, u32_t ackno, u8_t headerflags)
{
  struct pbuf* p;
  struct ip_hdr* iphdr;
  struct tcp_hdr* tcphdr;
  u16_t pbuf_len = (u16_t)(sizeof(struct ip_hdr) + sizeof(struct tcp_hdr) + data_len);

  p = pbuf_alloc(PBUF_RAW, pbuf_len, PBUF_POOL);
  EXPECT_RETNULL(p != NULL);
  EXPECT_RETNULL(p->next == NULL);

  memset(p->payload, 0, p->len);

  iphdr = p->payload;
  /* fill IP header */
  iphdr->dest.addr = dst_ip->addr;
  iphdr->src.addr = src_ip->addr;
  IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, 0);
  IPH_LEN_SET(iphdr, htons(p->tot_len));
  IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));

  pbuf_header(p, -(s16_t)sizeof(struct ip_hdr));

  tcphdr = p->payload;
  tcphdr->src   = htons(src_port);
  tcphdr->dest  = htons(dst_port);
  tcphdr->seqno = htonl(seqno);
  tcphdr->ackno = htonl(ackno);
  TCPH_HDRLEN_SET(tcphdr, sizeof(struct tcp_hdr)/4);
  TCPH_FLAGS_SET(tcphdr, headerflags);
  tcphdr->wnd   = htons(TCP_WND);

  /* copy data */
  memcpy((char*)tcphdr + sizeof(struct tcp_hdr), data, data_len);

  /* calculate checksum */

  tcphdr->chksum = inet_chksum_pseudo(p, src_ip, dst_ip,
          IP_PROTO_TCP, p->tot_len);

  pbuf_header(p, sizeof(struct ip_hdr));

  return p;
}
コード例 #3
0
ファイル: dhcp_server.c プロジェクト: gastonfeng/rt-thread
static rt_err_t _low_level_dhcp_send(struct netif *netif,
                                     const void *buffer,
                                     rt_size_t size)
{
    struct pbuf *p;
    struct eth_hdr *ethhdr;
    struct ip_hdr *iphdr;
    struct udp_hdr *udphdr;

    p = pbuf_alloc(PBUF_LINK,
                   SIZEOF_ETH_HDR + sizeof(struct ip_hdr)
                   + sizeof(struct udp_hdr) + size,
                   PBUF_RAM);
    if (p == RT_NULL) return -RT_ENOMEM;

    ethhdr = (struct eth_hdr *)p->payload;
    iphdr  = (struct ip_hdr *)((char *)ethhdr + SIZEOF_ETH_HDR);
    udphdr = (struct udp_hdr *)((char *)iphdr + sizeof(struct ip_hdr));

    ETHADDR32_COPY(&ethhdr->dest, (struct eth_addr *)&ethbroadcast);
    ETHADDR16_COPY(&ethhdr->src, netif->hwaddr);
    ethhdr->type = PP_HTONS(ETHTYPE_IP);

    iphdr->src.addr  = 0x00000000; /* src: 0.0.0.0 */
    iphdr->dest.addr = 0xFFFFFFFF; /* src: 255.255.255.255 */

    IPH_VHL_SET(iphdr, 4, IP_HLEN / 4);
    IPH_TOS_SET(iphdr, 0x00);
    IPH_LEN_SET(iphdr, htons(IP_HLEN + sizeof(struct udp_hdr) + size));
    IPH_ID_SET(iphdr, htons(2));
    IPH_OFFSET_SET(iphdr, 0);
    IPH_TTL_SET(iphdr, 255);
    IPH_PROTO_SET(iphdr, IP_PROTO_UDP);
    IPH_CHKSUM_SET(iphdr, 0);
    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));

    udphdr->src = htons(DHCP_SERVER_PORT);
    udphdr->dest = htons(DHCP_CLIENT_PORT);
    udphdr->len = htons(sizeof(struct udp_hdr) + size);
    udphdr->chksum = 0;

    memcpy((char *)udphdr + sizeof(struct udp_hdr),
           buffer, size);

    return netif->linkoutput(netif, p);
}
コード例 #4
0
ファイル: sr_ip.c プロジェクト: ZubairNabi/bir
void ip_look_up(byte* ip_packet, struct ip* ip_header) {
   printf(" ** ip_lookup(..) called \n");
   // get ptr to global router instance
   struct sr_router* subsystem = (struct sr_router*)sr_get_subsystem(get_sr());
   // get dst ip object
   addr_ip_t dst_ip;
   memcpy(&dst_ip, &ip_header->ip_dst, 4);
   // look up in routing table
   route_info_t route_info = rrtable_find_route(subsystem->rtable, dst_ip);
   if(route_info.intf == NULL) {
      printf(" ** ip_lookup(..) Error! No route found \n");
   } else {
   // display output interface
   printf(" ** ip_lookup(..) output interface for ip: %s\n", quick_ip_to_string(dst_ip));
   display_interface(route_info.intf);
   // set src ip as the ip of the output interface
   memcpy(&ip_header->ip_src, &route_info.intf->ip, 4);
   memcpy(ip_packet, ip_header, ip_header->ip_hl);
   // check if ttl expired
   if(ip_header->ip_ttl == 1) {
      printf(" ** ip_lookup(..) ttl expired, sending ICMP ttl error message \n");
      uint8_t code = ICMP_TYPE_CODE_TTL_TRANSIT;
      uint16_t len = ntohs(ip_header->ip_len);
      icmp_type_ttl_send(&code, ip_packet, &len, ip_header);
   } else {
      printf(" ** ip_lookup(..) decrementing ttl \n");
      // create new ip header
      struct ip* ip_header_ttl = (struct ip*) malloc_or_die(ip_header->ip_hl * 4);
      memcpy(ip_header_ttl, ip_header, ip_header->ip_hl * 4);
      // decrement ttl
      ip_header_ttl->ip_ttl = ip_header_ttl->ip_ttl - 1;
      // generate checksum
      ip_header_ttl->ip_sum = 0;
      ip_header_ttl->ip_sum = htons(htons(inet_chksum((void*)ip_header_ttl, ip_header_ttl->ip_hl * 4)));
      // get payload
      uint16_t payload_len = ntohs(ip_header_ttl->ip_len) - (ip_header_ttl->ip_hl * 4);
      printf(" ** ip_lookup(..) Payload size %u bytes \n", payload_len);
      memcpy(ip_packet, ip_header_ttl, ip_header_ttl->ip_hl * 4);
      // make new ip packet
      send_ip_packet(ip_packet, ip_header_ttl, route_info);

   }
   }
}
コード例 #5
0
ファイル: network2.c プロジェクト: AlexShiLucky/HelloX_STM32
/** Prepare a echo ICMP request */
static void
ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len)
{
  size_t i;
  size_t data_len = len - sizeof(struct icmp_echo_hdr);

  ICMPH_TYPE_SET(iecho, ICMP_ECHO);
  ICMPH_CODE_SET(iecho, 0);
  iecho->chksum = 0;
  iecho->id     = PING_ID;
  iecho->seqno  = htons(++ping_seq_num);

  /* fill the additional data buffer with some data */
  for(i = 0; i < data_len; i++) {
    ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i;
  }

  iecho->chksum = inet_chksum(iecho, len);
}
コード例 #6
0
ファイル: icmp.c プロジェクト: YTakami/makecontroller
/**
 * 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 = 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 = 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);
}
コード例 #7
0
ファイル: ping.c プロジェクト: AndreyMostovov/asf
/** Prepare a echo ICMP request */
static void ping_prepare_echo(struct icmp_echo_hdr *iecho,
                              struct ping_info_t* ping_info)
{
        int i;

        ICMPH_TYPE_SET(iecho,ICMP_ECHO);
        ICMPH_CODE_SET(iecho, 0);
        iecho->chksum = 0;
        iecho->id     = PING_ID;
        iecho->seqno  = htons(++ping_info->seq_num);
        iecho->chksum = 0;

        /* fill the additional data buffer with some data */
        for(i = 0; i < ping_info->data_size; i++) {
                ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = i;
        }

        iecho->chksum = inet_chksum(iecho, ping_info->size);
}
コード例 #8
0
int16_t
eeprom_read_cfg(void) {
    uint8_t i;
    int16_t status;
    i2c_start(EEPROM_I2C);
    for (i = 0; i < EEPROM_SIZE; i += EEPROM_PAGE_SIZE) {
        status = eeprom_do(&i, 1,
            i == 0 ? (void*)&snum : (void*)&cfg_bytes[i-EEPROM_CFG_OFFSET],
            EEPROM_PAGE_SIZE);
        if (status != EERR_OK) {
            i2c_stop(EEPROM_I2C);
            return status;
        }
    }
    i2c_stop(EEPROM_I2C);
    /* Validate checksum of user data */
    if (inet_chksum(&cfg, sizeof(cfg) - 2) != cfg.crc) {
        return EERR_CRCFAIL;
    }
    return EERR_OK;
}
コード例 #9
0
ファイル: simhost.c プロジェクト: malooei/yeejoin-workspace
static void
ping_send(struct raw_pcb *raw, ip_addr_t *addr)
{
	struct pbuf *p;
	struct icmp_echo_hdr *iecho;

	p = pbuf_alloc(PBUF_IP,sizeof(struct icmp_echo_hdr),PBUF_RAM);
	if (!p) return;

	iecho = p->payload;
	ICMPH_TYPE_SET(iecho,ICMP_ECHO);
	iecho->chksum = 0;
	iecho->seqno = htons(seq_num);

	iecho->chksum = inet_chksum(iecho, p->len);
	raw_send_to(raw,p,addr);

	pbuf_free(p);

	seq_num++;
}
コード例 #10
0
ファイル: test_udp.c プロジェクト: 0xc0170/mbed
static struct pbuf *
test_udp_create_test_packet(u16_t length, u16_t port, u32_t dst_addr)
{
  err_t err;
  u8_t ret;
  struct udp_hdr *uh;
  struct ip_hdr *ih;
  struct pbuf *p;
  const u8_t test_data[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};

  p = pbuf_alloc(PBUF_TRANSPORT, length, PBUF_POOL);
  fail_unless(p != NULL);
  if (p == NULL) {
    return NULL;
  }
  fail_unless(p->next == NULL);
  err = pbuf_take(p, test_data, length);
  fail_unless(err == ERR_OK);

  /* add UDP header */
  ret = pbuf_add_header(p, sizeof(struct udp_hdr));
  fail_unless(!ret);
  uh = (struct udp_hdr *)p->payload;
  uh->chksum = 0;
  uh->dest = uh->src = lwip_htons(port);
  uh->len = lwip_htons(p->tot_len);
  /* add IPv4 header */
  ret = pbuf_add_header(p, sizeof(struct ip_hdr));
  fail_unless(!ret);
  ih = (struct ip_hdr *)p->payload;
  memset(ih, 0, sizeof(*ih));
  ih->dest.addr = dst_addr;
  ih->_len = lwip_htons(p->tot_len);
  ih->_ttl = 32;
  ih->_proto = IP_PROTO_UDP;
  IPH_VHL_SET(ih, 4, sizeof(struct ip_hdr) / 4);
  IPH_CHKSUM_SET(ih, inet_chksum(ih, sizeof(struct ip_hdr)));
  return p;
}
コード例 #11
0
ファイル: icmp.c プロジェクト: YTakami/makecontroller
/**
 * 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);
}
コード例 #12
0
ファイル: simhost.c プロジェクト: malooei/yeejoin-workspace
static void
ping_send(int s, ip_addr_t *addr)
{
	struct icmp_echo_hdr *iecho;
	struct sockaddr_in to;

	if (!(iecho = (struct icmp_echo_hdr *)malloc(sizeof(struct icmp_echo_hdr))))
		return;

	ICMPH_TYPE_SET(iecho,ICMP_ECHO);
	iecho->chksum = 0;
	iecho->seqno = htons(seq_num);
	iecho->chksum = inet_chksum(iecho, sizeof(*iecho));

	to.sin_len = sizeof(to);
	to.sin_family = AF_INET;
	to.sin_addr.s_addr = addr->addr;

	lwip_sendto(s,iecho,sizeof(*iecho),0,(struct sockaddr*)&to,sizeof(to));

	free(iecho);
	seq_num++;
}
コード例 #13
0
ファイル: simhost.c プロジェクト: aps243/2A-lwIP
static void
ping_send(int s, const ip_addr_t *addr)
{
  struct icmp_echo_hdr *iecho;
  struct sockaddr_storage to;

  if (!(iecho = (struct icmp_echo_hdr *)malloc(sizeof(struct icmp_echo_hdr))))
    return;

  ICMPH_TYPE_SET(iecho,ICMP_ECHO);
  iecho->chksum = 0;
  iecho->seqno  = htons(seq_num);
  iecho->chksum = inet_chksum(iecho, sizeof(*iecho));

#if LWIP_IPV4
  if(!IP_IS_V6(addr)) {
    struct sockaddr_in *to4 = (struct sockaddr_in*)&to;
    to4->sin_len    = sizeof(to);
    to4->sin_family = AF_INET;
    inet_addr_from_ipaddr(&to4->sin_addr, ip_2_ip4(addr));
  }
#endif /* LWIP_IPV4 */

#if LWIP_IPV6
  if(IP_IS_V6(addr)) {
    struct sockaddr_in6 *to6 = (struct sockaddr_in6*)&to;
    to6->sin6_len    = sizeof(to);
    to6->sin6_family = AF_INET6;
    inet6_addr_from_ip6addr(&to6->sin6_addr, ip_2_ip6(addr));
  }
#endif /* LWIP_IPV6 */

  lwip_sendto(s, iecho, sizeof(*iecho), 0, (struct sockaddr*)&to, sizeof(to));

  free(iecho);
  seq_num++;
}
コード例 #14
0
 int32_t MTD_FLASHMEM ICMP::ping(IPAddress const& dest)
 {       
     static uint32_t const TIMEOUT        = 4000;
     static int32_t const TIMEOUT_RESULT  = -1;
 
     uint32_t result = TIMEOUT_RESULT;
             
     // generate seq
     m_waitingSeq++;
     
     // prepare packet to send
     pbuf* hdrbuf = pbuf_alloc(PBUF_IP, sizeof(icmp_echo_hdr), PBUF_RAM);
     icmp_echo_hdr* hdr = (icmp_echo_hdr*)hdrbuf->payload;
     hdr->type   = ICMP_ECHO;
     hdr->code   = 0;
     hdr->chksum = 0;
     hdr->id     = htons(m_waitingID);
     hdr->seqno  = htons(m_waitingSeq);
     hdr->chksum = inet_chksum((uint16_t*)hdr, sizeof(icmp_echo_hdr));
     
     // send Echo request
     raw_pcb* pcb = raw_new(IP_PROTO_ICMP);
     raw_recv(pcb, ICMP::raw_recv_fn, this);
     raw_bind(pcb, IP_ADDR_ANY);            
     
     ip_addr_t addr = dest.get_ip_addr_t();
     raw_sendto(pcb, hdrbuf, &addr);
     pbuf_free(hdrbuf);
     
     uint32_t t1 = micros();
     if (m_queue.receive(TIMEOUT))
         result = (micros() - t1);
             
     raw_remove(pcb);
     
     return result;            
 }
コード例 #15
0
ファイル: icmp6.c プロジェクト: peterliu2/FreeRTOS
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);
}
コード例 #16
0
ファイル: ip_frag.c プロジェクト: 0wsqqsw/lantern
/**
 * 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;
}
コード例 #17
0
ファイル: ip.c プロジェクト: ChijunShen/wildfire_stm32_iso
/**
 * This function is called by the network interface device driver when
 * an IP packet is received. The function does the basic checks of the
 * IP header such as packet size being at least larger than the header
 * size etc. If the packet was not destined for us, the packet is
 * forwarded (using ip_forward). The IP checksum is always checked.
 *
 * Finally, the packet is sent to the upper layer protocol input function.
 * 
 * @param p the received IP packet (p->payload points to IP header)
 * @param inp the netif on which this packet was received
 * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't
 *         processed, but currently always returns ERR_OK)
 */
err_t
ip_input(struct pbuf *p, struct netif *inp)
{
  struct ip_hdr *iphdr;
  struct netif *netif;
  u16_t iphdr_hlen;
  u16_t iphdr_len;
#if LWIP_DHCP
  int check_ip_src=1;
#endif /* LWIP_DHCP */

  IP_STATS_INC(ip.recv);
  snmp_inc_ipinreceives();

  /* identify the IP header */
  iphdr = p->payload;
  if (IPH_V(iphdr) != 4) {
    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
    ip_debug_print(p);
    pbuf_free(p);
    IP_STATS_INC(ip.err);
    IP_STATS_INC(ip.drop);
    snmp_inc_ipinhdrerrors();
    return ERR_OK;
  }

  /* obtain IP header length in number of 32-bit words */
  iphdr_hlen = IPH_HL(iphdr);
  /* calculate IP header length in bytes */
  iphdr_hlen *= 4;
  /* obtain ip length in bytes */
  iphdr_len = ntohs(IPH_LEN(iphdr));

  /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
  if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
    if (iphdr_hlen > p->len) {
      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
        ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
        iphdr_hlen, p->len));
    }
    if (iphdr_len > p->tot_len) {
      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
        ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n",
        iphdr_len, p->tot_len));
    }
    /* free (drop) packet pbufs */
    pbuf_free(p);
    IP_STATS_INC(ip.lenerr);
    IP_STATS_INC(ip.drop);
    snmp_inc_ipindiscards();
    return ERR_OK;
  }

  /* verify checksum */
#if CHECKSUM_CHECK_IP
  if (inet_chksum(iphdr, iphdr_hlen) != 0) {

    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
      ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
    ip_debug_print(p);
    pbuf_free(p);
    IP_STATS_INC(ip.chkerr);
    IP_STATS_INC(ip.drop);
    snmp_inc_ipinhdrerrors();
    return ERR_OK;
  }
#endif

  /* Trim pbuf. This should have been done at the netif layer,
   * but we'll do it anyway just to be sure that its done. */
  pbuf_realloc(p, iphdr_len);

  /* match packet against an interface, i.e. is this packet for us? */
#if LWIP_IGMP
  if (ip_addr_ismulticast(&(iphdr->dest))) {
    if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &(iphdr->dest)))) {
      netif = inp;
    } else {
      netif = NULL;
    }
  } else
#endif /* LWIP_IGMP */
  {
    /* start trying with inp. if that's not acceptable, start walking the
       list of configured netifs.
       'first' is used as a boolean to mark whether we started walking the list */
    int first = 1;
    netif = inp;
    do {
      LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n",
          iphdr->dest.addr, netif->ip_addr.addr,
          iphdr->dest.addr & netif->netmask.addr,
          netif->ip_addr.addr & netif->netmask.addr,
          iphdr->dest.addr & ~(netif->netmask.addr)));

      /* interface is up and configured? */
      if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {
        /* unicast to this interface address? */
        if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||
            /* or broadcast on this interface network address? */
            ip_addr_isbroadcast(&(iphdr->dest), netif)) {
          LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
              netif->name[0], netif->name[1]));
          /* break out of for loop */
          break;
        }
      }
      if (first) {
        first = 0;
        netif = netif_list;
      } else {
        netif = netif->next;
      }
      if (netif == inp) {
        netif = netif->next;
      }
    } while(netif != NULL);
  }

#if LWIP_DHCP
  /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
   * using link layer addressing (such as Ethernet MAC) so we must not filter on IP.
   * According to RFC 1542 section 3.1.1, referred by RFC 2131).
   */
  if (netif == NULL) {
    /* remote port is DHCP server? */
    if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
        ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest)));
      if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) {
        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n"));
        netif = inp;
        check_ip_src = 0;
      }
    }
  }
#endif /* LWIP_DHCP */

  /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
#if LWIP_DHCP
  /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */
  if (check_ip_src && (iphdr->src.addr != 0))
#endif /* LWIP_DHCP */
  {  if ((ip_addr_isbroadcast(&(iphdr->src), inp)) ||
         (ip_addr_ismulticast(&(iphdr->src)))) {
      /* packet source is not valid */
      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n"));
      /* free (drop) packet pbufs */
      pbuf_free(p);
      IP_STATS_INC(ip.drop);
      snmp_inc_ipinaddrerrors();
      snmp_inc_ipindiscards();
      return ERR_OK;
    }
  }

  /* packet not for us? */
  if (netif == NULL) {
    /* packet not for us, route or discard */
    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n"));
#if IP_FORWARD
    /* non-broadcast packet? */
    if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) {
      /* try to forward IP packet on (other) interfaces */
      ip_forward(p, iphdr, inp);
    } else
#endif /* IP_FORWARD */
    {
      snmp_inc_ipinaddrerrors();
      snmp_inc_ipindiscards();
    }
    pbuf_free(p);
    return ERR_OK;
  }
  /* packet consists of multiple fragments? */
  if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
#if IP_REASSEMBLY /* packet fragment reassembly code present? */
    LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n",
      ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
    /* reassemble the packet*/
    p = ip_reass(p);
    /* packet not fully reassembled yet? */
    if (p == NULL) {
      return ERR_OK;
    }
    iphdr = p->payload;
#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
    pbuf_free(p);
    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
      ntohs(IPH_OFFSET(iphdr))));
    IP_STATS_INC(ip.opterr);
    IP_STATS_INC(ip.drop);
    /* unsupported protocol feature */
    snmp_inc_ipinunknownprotos();
    return ERR_OK;
#endif /* IP_REASSEMBLY */
  }

#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */

#if LWIP_IGMP
  /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */
  if((iphdr_hlen > IP_HLEN &&  (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {
#else
  if (iphdr_hlen > IP_HLEN) {
#endif /* LWIP_IGMP */
    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
    pbuf_free(p);
    IP_STATS_INC(ip.opterr);
    IP_STATS_INC(ip.drop);
    /* unsupported protocol feature */
    snmp_inc_ipinunknownprotos();
    return ERR_OK;
  }
#endif /* IP_OPTIONS_ALLOWED == 0 */

  /* send to upper layers */
  LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));
  ip_debug_print(p);
  LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));

  current_netif = inp;
  current_header = iphdr;

#if LWIP_RAW
  /* raw input did not eat the packet? */
  if (raw_input(p, inp) == 0)
#endif /* LWIP_RAW */
  {

    switch (IPH_PROTO(iphdr)) {
#if LWIP_UDP
    case IP_PROTO_UDP:
#if LWIP_UDPLITE
    case IP_PROTO_UDPLITE:
#endif /* LWIP_UDPLITE */
      snmp_inc_ipindelivers();
      udp_input(p, inp);
      break;
#endif /* LWIP_UDP */
#if LWIP_TCP
    case IP_PROTO_TCP:
      snmp_inc_ipindelivers();
      tcp_input(p, inp);
      break;
#endif /* LWIP_TCP */
#if LWIP_ICMP
    case IP_PROTO_ICMP:
      snmp_inc_ipindelivers();
      icmp_input(p, inp);
      break;
#endif /* LWIP_ICMP */
#if LWIP_IGMP
    case IP_PROTO_IGMP:
      igmp_input(p,inp,&(iphdr->dest));
      break;
#endif /* LWIP_IGMP */
    default:
#if LWIP_ICMP
      /* send ICMP destination protocol unreachable unless is was a broadcast */
      if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&
          !ip_addr_ismulticast(&(iphdr->dest))) {
        p->payload = iphdr;
        icmp_dest_unreach(p, ICMP_DUR_PROTO);
      }
#endif /* LWIP_ICMP */
      pbuf_free(p);

      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));

      IP_STATS_INC(ip.proterr);
      IP_STATS_INC(ip.drop);
      snmp_inc_ipinunknownprotos();
    }
  }

  current_netif = NULL;
  current_header = NULL;

  return ERR_OK;
}

/**
 * Sends an IP packet on a network interface. This function constructs
 * the IP header and calculates the IP header checksum. If the source
 * IP address is NULL, the IP address of the outgoing network
 * interface is filled in as source address.
 * If the destination IP address is IP_HDRINCL, p is assumed to already
 * include an IP header and p->payload points to it instead of the data.
 *
 * @param p the packet to send (p->payload points to the data, e.g. next
            protocol header; if dest == IP_HDRINCL, p already includes an IP
            header and p->payload points to that IP header)
 * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
 *         IP  address of the netif used to send is used as source address)
 * @param dest the destination IP address to send the packet to
 * @param ttl the TTL value to be set in the IP header
 * @param tos the TOS value to be set in the IP header
 * @param proto the PROTOCOL to be set in the IP header
 * @param netif the netif on which to send this packet
 * @return ERR_OK if the packet was sent OK
 *         ERR_BUF if p doesn't have enough space for IP/LINK headers
 *         returns errors returned by netif->output
 *
 * @note ip_id: RFC791 "some host may be able to simply use
 *  unique identifiers independent of destination"
 */
err_t
ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
             u8_t ttl, u8_t tos,
             u8_t proto, struct netif *netif)
{
#if IP_OPTIONS_SEND
  return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0);
}

/**
 * Same as ip_output_if() but with the possibility to include IP options:
 *
 * @ param ip_options pointer to the IP options, copied into the IP header
 * @ param optlen length of ip_options
 */
err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
       u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
       u16_t optlen)
{
#endif /* IP_OPTIONS_SEND */
  struct ip_hdr *iphdr;
  static u16_t ip_id = 0;

  snmp_inc_ipoutrequests();

  /* Should the IP header be generated or is it already included in p? */
  if (dest != IP_HDRINCL) {
    u16_t ip_hlen = IP_HLEN;
#if IP_OPTIONS_SEND
    u16_t optlen_aligned = 0;
    if (optlen != 0) {
      /* round up to a multiple of 4 */
      optlen_aligned = ((optlen + 3) & ~3);
      ip_hlen += optlen_aligned;
      /* First write in the IP options */
      if (pbuf_header(p, optlen_aligned)) {
        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n"));
        IP_STATS_INC(ip.err);
        snmp_inc_ipoutdiscards();
        return ERR_BUF;
      }
      MEMCPY(p->payload, ip_options, optlen);
      if (optlen < optlen_aligned) {
        /* zero the remaining bytes */
        memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen);
      }
    }
#endif /* IP_OPTIONS_SEND */
    /* generate IP header */
    if (pbuf_header(p, IP_HLEN)) {
      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n"));

      IP_STATS_INC(ip.err);
      snmp_inc_ipoutdiscards();
      return ERR_BUF;
    }

    iphdr = p->payload;
    LWIP_ASSERT("check that first pbuf can hold struct ip_hdr",
               (p->len >= sizeof(struct ip_hdr)));

    IPH_TTL_SET(iphdr, ttl);
    IPH_PROTO_SET(iphdr, proto);

    ip_addr_set(&(iphdr->dest), dest);

    IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos);
    IPH_LEN_SET(iphdr, htons(p->tot_len));
    IPH_OFFSET_SET(iphdr, 0);
    IPH_ID_SET(iphdr, htons(ip_id));
    ++ip_id;

    if (ip_addr_isany(src)) {
      ip_addr_set(&(iphdr->src), &(netif->ip_addr));
    } else {
      ip_addr_set(&(iphdr->src), src);
    }

    IPH_CHKSUM_SET(iphdr, 0);
#if CHECKSUM_GEN_IP
    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen));
#endif
  } else {
    /* IP header already included in p */
    iphdr = p->payload;
    dest = &(iphdr->dest);
  }

  IP_STATS_INC(ip.xmit);

  LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));
  ip_debug_print(p);

#if ENABLE_LOOPBACK
  if (ip_addr_cmp(dest, &netif->ip_addr)) {
    /* Packet to self, enqueue it for loopback */
    LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()"));
    return netif_loop_output(netif, p, dest);
  }
#endif /* ENABLE_LOOPBACK */
#if IP_FRAG
  /* don't fragment if interface has mtu set to 0 [loopif] */
  if (netif->mtu && (p->tot_len > netif->mtu)) {
    return ip_frag(p,netif,dest);
  }
#endif

  LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
  return netif->output(netif, p, dest);
}

/**
 * Simple interface to ip_output_if. It finds the outgoing network
 * interface and calls upon ip_output_if to do the actual work.
 *
 * @param p the packet to send (p->payload points to the data, e.g. next
            protocol header; if dest == IP_HDRINCL, p already includes an IP
            header and p->payload points to that IP header)
 * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
 *         IP  address of the netif used to send is used as source address)
 * @param dest the destination IP address to send the packet to
 * @param ttl the TTL value to be set in the IP header
 * @param tos the TOS value to be set in the IP header
 * @param proto the PROTOCOL to be set in the IP header
 *
 * @return ERR_RTE if no route is found
 *         see ip_output_if() for more return values
 */
err_t
ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
          u8_t ttl, u8_t tos, u8_t proto)
{
  struct netif *netif;

  if ((netif = ip_route(dest)) == NULL) {
    LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));
    IP_STATS_INC(ip.rterr);
    return ERR_RTE;
  }

  return ip_output_if(p, src, dest, ttl, tos, proto, netif);
}

#if LWIP_NETIF_HWADDRHINT
/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint
 *  before calling ip_output_if.
 *
 * @param p the packet to send (p->payload points to the data, e.g. next
            protocol header; if dest == IP_HDRINCL, p already includes an IP
            header and p->payload points to that IP header)
 * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
 *         IP  address of the netif used to send is used as source address)
 * @param dest the destination IP address to send the packet to
 * @param ttl the TTL value to be set in the IP header
 * @param tos the TOS value to be set in the IP header
 * @param proto the PROTOCOL to be set in the IP header
 * @param addr_hint address hint pointer set to netif->addr_hint before
 *        calling ip_output_if()
 *
 * @return ERR_RTE if no route is found
 *         see ip_output_if() for more return values
 */
err_t
ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
          u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)
{
  struct netif *netif;
  err_t err;

  if ((netif = ip_route(dest)) == NULL) {
    LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));
    IP_STATS_INC(ip.rterr);
    return ERR_RTE;
  }

  netif->addr_hint = addr_hint;
  err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
  netif->addr_hint = NULL;

  return err;
}
#endif /* LWIP_NETIF_HWADDRHINT*/

#if IP_DEBUG
/* Print an IP header by using LWIP_DEBUGF
 * @param p an IP packet, p->payload pointing to the IP header
 */
void
ip_debug_print(struct pbuf *p)
{
  struct ip_hdr *iphdr = p->payload;
  u8_t *payload;

  payload = (u8_t *)iphdr + IP_HLEN;

  LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
  LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" |  0x%02"X16_F" |     %5"U16_F"     | (v, hl, tos, len)\n",
                    IPH_V(iphdr),
                    IPH_HL(iphdr),
                    IPH_TOS(iphdr),
                    ntohs(IPH_LEN(iphdr))));
  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
  LWIP_DEBUGF(IP_DEBUG, ("|    %5"U16_F"      |%"U16_F"%"U16_F"%"U16_F"|    %4"U16_F"   | (id, flags, offset)\n",
                    ntohs(IPH_ID(iphdr)),
                    ntohs(IPH_OFFSET(iphdr)) >> 15 & 1,
                    ntohs(IPH_OFFSET(iphdr)) >> 14 & 1,
                    ntohs(IPH_OFFSET(iphdr)) >> 13 & 1,
                    ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK));
  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |    0x%04"X16_F"     | (ttl, proto, chksum)\n",
                    IPH_TTL(iphdr),
                    IPH_PROTO(iphdr),
                    ntohs(IPH_CHKSUM(iphdr))));
  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (src)\n",
                    ip4_addr1(&iphdr->src),
                    ip4_addr2(&iphdr->src),
                    ip4_addr3(&iphdr->src),
                    ip4_addr4(&iphdr->src)));
  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (dest)\n",
                    ip4_addr1(&iphdr->dest),
                    ip4_addr2(&iphdr->dest),
                    ip4_addr3(&iphdr->dest),
                    ip4_addr4(&iphdr->dest)));
  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
}
コード例 #18
0
ファイル: ip.c プロジェクト: Joel397/Ongoing_work_files
/*-----------------------------------------------------------------------------------*/
err_t
ip_input(struct pbuf *p, struct netif *inp) {
    static struct ip_hdr *iphdr;
    static struct netif *netif;
    static u8_t hl;



#ifdef IP_STATS
    ++stats.ip.recv;
#endif /* IP_STATS */

    /* identify the IP header */
    iphdr = p->payload;
    if(IPH_V(iphdr) != 4) {
        DEBUGF(IP_DEBUG, ("IP packet dropped due to bad version number %d\n", IPH_V(iphdr)));
#if IP_DEBUG
        ip_debug_print(p);
#endif /* IP_DEBUG */
        pbuf_free(p);
#ifdef IP_STATS
        ++stats.ip.err;
        ++stats.ip.drop;
#endif /* IP_STATS */
        return ERR_OK;
    }

    hl = IPH_HL(iphdr);

    if(hl * 4 > p->len) {
        DEBUGF(IP_DEBUG, ("IP packet dropped due to too short packet %d\n", p->len));

        pbuf_free(p);
#ifdef IP_STATS
        ++stats.ip.lenerr;
        ++stats.ip.drop;
#endif /* IP_STATS */
        return ERR_OK;
    }

    /* verify checksum */
    if(inet_chksum(iphdr, hl * 4) != 0) {

        DEBUGF(IP_DEBUG, ("IP packet dropped due to failing checksum 0x%x\n", inet_chksum(iphdr, hl * 4)));
#if IP_DEBUG
        ip_debug_print(p);
#endif /* IP_DEBUG */
        pbuf_free(p);
#ifdef IP_STATS
        ++stats.ip.chkerr;
        ++stats.ip.drop;
#endif /* IP_STATS */
        return ERR_OK;
    }

    /* Trim pbuf. This should have been done at the netif layer,
       but we'll do it anyway just to be sure that its done. */
    pbuf_realloc(p, ntohs(IPH_LEN(iphdr)));

    /* is this packet for us? */
    for(netif = netif_list; netif != NULL; netif = netif->next) {

        DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%lx netif->ip_addr 0x%lx (0x%lx, 0x%lx, 0x%lx)\n",
                          iphdr->dest.addr, netif->ip_addr.addr,
                          iphdr->dest.addr & netif->netmask.addr,
                          netif->ip_addr.addr & netif->netmask.addr,
                          iphdr->dest.addr & ~(netif->netmask.addr)));

        if(ip_addr_isany(&(netif->ip_addr)) ||
                ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||
                (ip_addr_isbroadcast(&(iphdr->dest), &(netif->netmask)) &&
                 ip_addr_maskcmp(&(iphdr->dest), &(netif->ip_addr), &(netif->netmask))) ||
                ip_addr_cmp(&(iphdr->dest), IP_ADDR_BROADCAST)) {
            break;
        }
    }

#if LWIP_DHCP
    /* If a DHCP packet has arrived on the interface, we pass it up the
       stack regardless of destination IP address. The reason is that
       DHCP replies are sent to the IP adress that will be given to this
       node (as recommended by RFC 1542 section 3.1.1, referred by RFC
       2131). */
    if(IPH_PROTO(iphdr) == IP_PROTO_UDP &&
            ((struct udp_hdr *)((u8_t *)iphdr + IPH_HL(iphdr) * 4/sizeof(u8_t)))->src ==
            DHCP_SERVER_PORT) {
        netif = inp;
    }
#endif /* LWIP_DHCP */

    if(netif == NULL) {
        /* packet not for us, route or discard */
        DEBUGF(IP_DEBUG, ("ip_input: packet not for us.\n"));
#if IP_FORWARD
        if(!ip_addr_isbroadcast(&(iphdr->dest), &(inp->netmask))) {
            ip_forward(p, iphdr, inp);
        }
#endif /* IP_FORWARD */
        pbuf_free(p);
        return ERR_OK;
    }

#if IP_REASSEMBLY
    if((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
        p = ip_reass(p);
        if(p == NULL) {
            return ERR_OK;
        }
        iphdr = p->payload;
    }
#else /* IP_REASSEMBLY */
    if((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
        pbuf_free(p);
        DEBUGF(IP_DEBUG, ("IP packet dropped since it was fragmented (0x%x).\n",
                          ntohs(IPH_OFFSET(iphdr))));
#ifdef IP_STATS
        ++stats.ip.opterr;
        ++stats.ip.drop;
#endif /* IP_STATS */
        return ERR_OK;
    }
#endif /* IP_REASSEMBLY */

#if IP_OPTIONS == 0
    if(hl * 4 > IP_HLEN) {
        DEBUGF(IP_DEBUG, ("IP packet dropped since there were IP options.\n"));

        pbuf_free(p);
#ifdef IP_STATS
        ++stats.ip.opterr;
        ++stats.ip.drop;
#endif /* IP_STATS */
        return ERR_OK;
    }
#endif /* IP_OPTIONS == 0 */


    /* send to upper layers */
#if IP_DEBUG
    DEBUGF(IP_DEBUG, ("ip_input: \n"));
    ip_debug_print(p);
    DEBUGF(IP_DEBUG, ("ip_input: p->len %d p->tot_len %d\n", p->len, p->tot_len));
#endif /* IP_DEBUG */

    switch(IPH_PROTO(iphdr)) {
#if LWIP_UDP > 0
    case IP_PROTO_UDP:
        udp_input(p, inp);
        break;
#endif /* LWIP_UDP */
#if LWIP_TCP > 0
    case IP_PROTO_TCP:
        tcp_input(p, inp);
        break;
#endif /* LWIP_TCP */
    case IP_PROTO_ICMP:
        icmp_input(p, inp);
        break;
    default:
        /* send ICMP destination protocol unreachable unless is was a broadcast */
        if(!ip_addr_isbroadcast(&(iphdr->dest), &(inp->netmask)) &&
                !ip_addr_ismulticast(&(iphdr->dest))) {
            p->payload = iphdr;
            icmp_dest_unreach(p, ICMP_DUR_PROTO);
        }
        pbuf_free(p);

        DEBUGF(IP_DEBUG, ("Unsupported transportation protocol %d\n", IPH_PROTO(iphdr)));

#ifdef IP_STATS
        ++stats.ip.proterr;
        ++stats.ip.drop;
#endif /* IP_STATS */

    }
    return ERR_OK;
}
コード例 #19
0
ファイル: tcp_helper.c プロジェクト: NCTU-ivan/embarc_osp
/** Create a TCP segment usable for passing to tcp_input */
static struct pbuf*
tcp_create_segment_wnd(ip_addr_t* src_ip, ip_addr_t* dst_ip,
                   u16_t src_port, u16_t dst_port, void* data, size_t data_len,
                   u32_t seqno, u32_t ackno, u8_t headerflags, u16_t wnd)
{
  struct pbuf *p, *q;
  struct ip_hdr* iphdr;
  struct tcp_hdr* tcphdr;
  u16_t pbuf_len = (u16_t)(sizeof(struct ip_hdr) + sizeof(struct tcp_hdr) + data_len);
  LWIP_ASSERT("data_len too big", data_len <= 0xFFFF);

  p = pbuf_alloc(PBUF_RAW, pbuf_len, PBUF_POOL);
  EXPECT_RETNULL(p != NULL);
  /* first pbuf must be big enough to hold the headers */
  EXPECT_RETNULL(p->len >= (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr)));
  if (data_len > 0) {
    /* first pbuf must be big enough to hold at least 1 data byte, too */
    EXPECT_RETNULL(p->len > (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr)));
  }

  for(q = p; q != NULL; q = q->next) {
    memset(q->payload, 0, q->len);
  }

  iphdr = (struct ip_hdr*)p->payload;
  /* fill IP header */
  iphdr->dest.addr = ip_2_ip4(dst_ip)->addr;
  iphdr->src.addr = ip_2_ip4(src_ip)->addr;
  IPH_VHL_SET(iphdr, 4, IP_HLEN / 4);
  IPH_TOS_SET(iphdr, 0);
  IPH_LEN_SET(iphdr, htons(p->tot_len));
  IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));

  /* let p point to TCP header */
  pbuf_header(p, -(s16_t)sizeof(struct ip_hdr));

  tcphdr = (struct tcp_hdr*)p->payload;
  tcphdr->src   = htons(src_port);
  tcphdr->dest  = htons(dst_port);
  tcphdr->seqno = htonl(seqno);
  tcphdr->ackno = htonl(ackno);
  TCPH_HDRLEN_SET(tcphdr, sizeof(struct tcp_hdr)/4);
  TCPH_FLAGS_SET(tcphdr, headerflags);
  tcphdr->wnd   = htons(wnd);

  if (data_len > 0) {
    /* let p point to TCP data */
    pbuf_header(p, -(s16_t)sizeof(struct tcp_hdr));
    /* copy data */
    pbuf_take(p, data, (u16_t)data_len);
    /* let p point to TCP header again */
    pbuf_header(p, sizeof(struct tcp_hdr));
  }

  /* calculate checksum */

  tcphdr->chksum = ip_chksum_pseudo(p,
          IP_PROTO_TCP, p->tot_len, src_ip, dst_ip);

  pbuf_header(p, sizeof(struct ip_hdr));

  return p;
}
コード例 #20
0
ファイル: icmp.c プロジェクト: fanqh/ETH_Mange
/**
 * 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;

  u8_t iptxt[20];
  volatile u8_t iptab[4];
  u32_t IPaddress;
  
  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;
  }

  IPaddress = iphdr->src.addr;
  
  /* read its IP address */
  iptab[0] = (u8_t)(IPaddress >> 24);
  iptab[1] = (u8_t)(IPaddress >> 16);
  iptab[2] = (u8_t)(IPaddress >> 8);
  iptab[3] = (u8_t)(IPaddress);

  sprintf((char*)iptxt, "Ping: %d.%d.%d.%d   ", iptab[3], iptab[2], iptab[1], iptab[0]);	
  
  LCD_DisplayStringLine(Line4, iptxt);

  printf("\n\r%s", iptxt);
  
  
  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);
    

/* This part of code has been modified by ST's MCD Application Team */
/* To use the Checksum Offload Engine for the putgoing ICMP packets,
   the ICMP checksum field should be set to 0, this is required only for Tx ICMP*/
#ifdef CHECKSUM_BY_HARDWARE
    iecho->chksum = 0;
#else	
	/* 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);
    }	
#endif

    /* Set the correct TTL and recalculate the header checksum. */
    IPH_TTL_SET(iphdr, ICMP_TTL);
    IPH_CHKSUM_SET(iphdr, 0);
#if CHECKSUM_GEN_IP
    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("Can't move over header in packet", 0);
    } else {
      err_t ret;
      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 */
}
コード例 #21
0
ファイル: sr_pwospf_types.c プロジェクト: ZubairNabi/bir
void pwospf_send_lsu() {
    printf(" ** pwospf_send_lsu(..) called\n");
    // get instance of router 
    struct sr_instance* sr_inst = get_sr();
    struct sr_router* router = (struct sr_router*)sr_get_subsystem(sr_inst);    
    int num_adverts = 0;
    byte* ls_adverts = get_ls_adverts_src(router, &num_adverts);
    int i = 0;
    node* first = NULL;
    neighbor_t* neighbor = NULL;
    printf(" ** pwospf_send_lsu(..) number of adverts: %d\n", num_adverts);
    printf(" ** pwospf_send_lsu(..) adverts:\n");
    display_neighbor_vertices_src(router);
    // now create lsu_packet
    pwospf_lsu_packet_t *lsu_packet = (pwospf_lsu_packet_t*) malloc_or_die(sizeof(pwospf_lsu_packet_t));
    //increment lsu sequence
    router->ls_info.lsu_seq = router->ls_info.lsu_seq + 1;
    lsu_packet->seq = htons(router->ls_info.lsu_seq);
    uint16_t ttl = PWOSPF_LSU_TTL;
    lsu_packet->ttl = htons(ttl);
    lsu_packet->no_of_adverts = htonl(num_adverts);
    // calculate length of entire pwospf packet
    uint16_t pwospf_packet_len = sizeof(pwospf_lsu_packet_t) + sizeof(pwospf_header_t) + sizeof(pwospf_ls_advert_t) * num_adverts;
    //make pwospf header
    pwospf_header_t* pwospf_header = (pwospf_header_t*) malloc_or_die(sizeof(pwospf_header_t));
    pwospf_header->version = PWOSPF_VER;
    pwospf_header->type = PWOSPF_TYPE_LSU;
    pwospf_header->len = htons(pwospf_packet_len);
    pwospf_header->router_id = router->ls_info.router_id;
    pwospf_header->area_id = router->ls_info.area_id;
    pwospf_header->checksum = 0;
    pwospf_header->au_type = PWOSPF_AU_TYPE;
    pwospf_header->authentication = PWOSPF_AUTHEN;
    // generate raw packet 
    byte* pwospf_packet = (byte*) malloc_or_die(pwospf_packet_len);
    memcpy(pwospf_packet, pwospf_header, sizeof(pwospf_header_t));
    memcpy(pwospf_packet + sizeof(pwospf_header_t), lsu_packet, sizeof(pwospf_lsu_packet_t));
    memcpy(pwospf_packet + sizeof(pwospf_header_t) + sizeof(pwospf_lsu_packet_t), ls_adverts, sizeof(pwospf_ls_advert_t) * num_adverts);
    // generate checksum
    pwospf_header->checksum = htons(htons(inet_chksum((void*) pwospf_packet, pwospf_packet_len)));
    memcpy(pwospf_packet, pwospf_header, sizeof(pwospf_header_t));
    free(ls_adverts);
    free(lsu_packet);
    free(pwospf_header);
    printf(" ** pwospf_send_lsu(..) pwospf packet with length %u generated\n", pwospf_packet_len);
    // now iterate through each interface
    for( i = 0; i < router->num_interfaces ; i++) {
       // now iterate this interface's neighbors list
       first = router->interface[i].neighbor_list;
       pthread_mutex_lock(&router->interface[i].neighbor_lock);
       while(first != NULL) {
          // get neighbor
          neighbor = (neighbor_t*) first->data;
          if(neighbor != NULL) {
             struct in_addr src, dst;
             src.s_addr = router->interface[i].ip;
             dst.s_addr = neighbor->ip;
             make_ip_packet(pwospf_packet, pwospf_packet_len, dst, src, IP_PROTOCOL_OSPF);
             
          }
          first = first->next;
       }
       pthread_mutex_unlock(&router->interface[i].neighbor_lock);
   }
}
コード例 #22
0
ファイル: ip.c プロジェクト: imaginegit/wifisdk
/**
 * This function is called by the network interface device driver when
 * an IP packet is received. The function does the basic checks of the
 * IP header such as packet size being at least larger than the header
 * size etc. If the packet was not destined for us, the packet is
 * forwarded (using ip_forward). The IP checksum is always checked.
 *
 * Finally, the packet is sent to the upper layer protocol input function.
 *
 * @param p the received IP packet (p->payload points to IP header)
 * @param inp the netif on which this packet was received
 * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't
 *         processed, but currently always returns ERR_OK)
 */
uint8 ip_input(PBUF *p, NETIF *inp)
{
    IP_HDR *iphdr;
    NETIF *netif;
    uint16 iphdr_hlen;
    uint16 iphdr_len;

    /* identify the IP header */
    iphdr = p->payload;
    if (IPH_V(iphdr) != 4)
    {
        pbuf_free(p);//this packet is not ipv4
        return ERR_OK;
    }

    /* obtain IP header length in number of 32-bit words */
    iphdr_hlen = IPH_HL(iphdr);
    /* calculate IP header length in bytes */
    iphdr_hlen *= 4;
	
    /* obtain ip pocket total length in bytes */
    iphdr_len = ntohs(IPH_LEN(iphdr));

    /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
    if ((iphdr_hlen > p->len) || (iphdr_len > p->len))
    {
        /* free (drop) packet pbufs */
        pbuf_free(p);
        return ERR_OK;
    }

    if (inet_chksum(iphdr, iphdr_hlen) != 0)
    {    
        pbuf_free(p);//ip header checksum error!
        return ERR_OK;
    }
    
    netif = inp;

    /* interface is up and configured? */
    if (ip_addr_isany(&(netif->ip_addr)))
    {
        netif = NULL;
    }
    else
    {
        /* unicast to this interface address? */
        if (!ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)))
        {
            netif = NULL;
        }
    }

    /* packet consists of multiple fragments? */
    if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0)
    {
		printf("received splited IP packet!! \n");
        pbuf_free(p);
        return ERR_OK;
    }
    if (iphdr_hlen > IP_HLEN)
    {
        pbuf_free(p);
        return ERR_OK;
    }
	
    switch (IPH_PROTO(iphdr))
    {
        case IP_PROTO_TCP://(6)
            //printf("get a tcp packet\n");
            tcp_input(p, inp);
            break;

        case IP_PROTO_UDP://(17)
        	printf("UDP\n");
            udp_input(p, inp);
            break;

        case IP_PROTO_ICMP://(1)
        	printf("gICMP\n");
            icmp_input(p, inp);
            break;

        default:
            /* send ICMP destination protocol unreachable unless is was a broadcast */
            printf("gerr\n");
            if (!ip_addr_isbroadcast(&(iphdr->dest), inp) && !ip_addr_ismulticast(&(iphdr->dest)))
            {
                p->payload = iphdr;
                icmp_dest_unreach(p, ICMP_DUR_PROTO);
            }
            pbuf_free(p);
    }

    return ERR_OK;
}
コード例 #23
0
ファイル: icmp.c プロジェクト: svn2github/virtualbox
/**
 * 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 icmp 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;
  s16_t hlen;

  ICMP_STATS_INC(icmp.recv);
  snmp_inc_icmpinmsgs();

  iphdr = (struct ip_hdr *)ip_current_header();
  hlen = IPH_HL(iphdr) * 4;
  if (p->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_ER:
    /* This is OK, echo reply might have been parsed by a raw PCB
       (as obviously, an echo request has been sent, too). */
    break; 
  case ICMP_ECHO:
#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
    {
      int accepted = 1;
#if !LWIP_MULTICAST_PING
      /* multicast destination address? */
      if (ip_addr_ismulticast(ip_current_dest_addr())) {
        accepted = 0;
      }
#endif /* LWIP_MULTICAST_PING */
#if !LWIP_BROADCAST_PING
      /* broadcast destination address? */
      if (ip_addr_isbroadcast(ip_current_dest_addr(), 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 CHECKSUM_CHECK_ICMP
    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;
    }
#endif
#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 = (struct ip_hdr *)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 = (struct icmp_echo_hdr *)p->payload;
    ip_addr_copy(iphdr->src, *ip_current_dest_addr());
    ip_addr_copy(iphdr->dest, *ip_current_src_addr());
    ICMPH_TYPE_SET(iecho, ICMP_ER);
#if CHECKSUM_GEN_ICMP
    /* adjust the checksum */
    if (iecho->chksum > PP_HTONS(0xffffU - (ICMP_ECHO << 8))) {
      iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1;
    } else {
      iecho->chksum += PP_HTONS(ICMP_ECHO << 8);
    }
#else /* CHECKSUM_GEN_ICMP */
    iecho->chksum = 0;
#endif /* CHECKSUM_GEN_ICMP */

    /* Set the correct TTL and recalculate the header checksum. */
    IPH_TTL_SET(iphdr, ICMP_TTL);
    IPH_CHKSUM_SET(iphdr, 0);
#if CHECKSUM_GEN_IP
    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("Can't move over header in packet", 0);
    } else {
      err_t ret;
      /* send an ICMP packet, src addr is the dest addr of the curren packet */
      ret = ip_output_if(p, ip_current_dest_addr(), 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 */
}
コード例 #24
0
ファイル: ip_frag.c プロジェクト: 0wsqqsw/lantern
/**
 * 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;
}
コード例 #25
0
err_t
ip_input(struct pbuf *p, struct netif *inp) {
  struct ip_hdr *iphdr;
  struct netif *netif;
  u16_t iphdrlen;

  IP_STATS_INC(ip.recv);
  snmp_inc_ipinreceives();

  /* identify the IP header */
  iphdr = p->payload;
  if (IPH_V(iphdr) != 4) {
    LWIP_DEBUGF(IP_DEBUG | 1, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
    ip_debug_print(p);
    pbuf_free(p);
    IP_STATS_INC(ip.err);
    IP_STATS_INC(ip.drop);
    snmp_inc_ipinhdrerrors();
    return ERR_OK;
  }
  /* obtain IP header length in number of 32-bit words */
  iphdrlen = IPH_HL(iphdr);
  /* calculate IP header length in bytes */
  iphdrlen *= 4;

  /* header length exceeds first pbuf length? */
  if (iphdrlen > p->len) {
    LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet droppped.\n",
      iphdrlen, p->len));
    /* free (drop) packet pbufs */
    pbuf_free(p);
    IP_STATS_INC(ip.lenerr);
    IP_STATS_INC(ip.drop);
    snmp_inc_ipindiscards();
    return ERR_OK;
  }

  /* verify checksum */
#if CHECKSUM_CHECK_IP
  if (inet_chksum(iphdr, iphdrlen) != 0) {

    LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdrlen)));
    ip_debug_print(p);
    pbuf_free(p);
    IP_STATS_INC(ip.chkerr);
    IP_STATS_INC(ip.drop);
    snmp_inc_ipinhdrerrors();
    return ERR_OK;
  }
#endif

  /* Trim pbuf. This should have been done at the netif layer,
   * but we'll do it anyway just to be sure that its done. */
  pbuf_realloc(p, ntohs(IPH_LEN(iphdr)));

  /* match packet against an interface, i.e. is this packet for us? */
  for (netif = netif_list; netif != NULL; netif = netif->next) {

    LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n",
      iphdr->dest.addr, netif->ip_addr.addr,
      iphdr->dest.addr & netif->netmask.addr,
      netif->ip_addr.addr & netif->netmask.addr,
      iphdr->dest.addr & ~(netif->netmask.addr)));

    /* interface is up and configured? */
    if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr))))
    {
      /* unicast to this interface address? */
      if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||
         /* or broadcast on this interface network address? */
         ip_addr_isbroadcast(&(iphdr->dest), netif)) {
        LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
          netif->name[0], netif->name[1]));
        /* break out of for loop */
        break;
      }
    }
  }
#if LWIP_DHCP
  /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
   * using link layer addressing (such as Ethernet MAC) so we must not filter on IP.
   * According to RFC 1542 section 3.1.1, referred by RFC 2131).
   */
  if (netif == NULL) {
    /* remote port is DHCP server? */
    if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
      LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
        ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdrlen))->dest)));
      if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdrlen))->dest) == DHCP_CLIENT_PORT) {
        LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n"));
        netif = inp;
      }
    }
  }
#endif /* LWIP_DHCP */
  /* packet not for us? */
  if (netif == NULL) {
    /* packet not for us, route or discard */
    LWIP_DEBUGF(IP_DEBUG | DBG_TRACE | 1, ("ip_input: packet not for us.\n"));
#if IP_FORWARD
    /* non-broadcast packet? */
    if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) {
      /* try to forward IP packet on (other) interfaces */
      ip_forward(p, iphdr, inp);
    }
    else
#endif /* IP_FORWARD */
    {
      snmp_inc_ipinaddrerrors();
      snmp_inc_ipindiscards();
    }
    pbuf_free(p);
    return ERR_OK;
  }
  /* packet consists of multiple fragments? */
  if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
#if IP_REASSEMBLY /* packet fragment reassembly code present? */
    LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n",
      ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
    /* reassemble the packet*/
    p = ip_reass(p);
    /* packet not fully reassembled yet? */
    if (p == NULL) {
      return ERR_OK;
    }
    iphdr = p->payload;
#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
    pbuf_free(p);
    LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
      ntohs(IPH_OFFSET(iphdr))));
    IP_STATS_INC(ip.opterr);
    IP_STATS_INC(ip.drop);
    /* unsupported protocol feature */
    snmp_inc_ipinunknownprotos();
    return ERR_OK;
#endif /* IP_REASSEMBLY */
  }

#if IP_OPTIONS == 0 /* no support for IP options in the IP header? */
  if (iphdrlen > IP_HLEN) {
    LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS == 0).\n"));
    pbuf_free(p);
    IP_STATS_INC(ip.opterr);
    IP_STATS_INC(ip.drop);
    /* unsupported protocol feature */
    snmp_inc_ipinunknownprotos();
    return ERR_OK;
  }
#endif /* IP_OPTIONS == 0 */

  /* send to upper layers */
  LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));
  ip_debug_print(p);
  LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));

#if LWIP_RAW
  /* raw input did not eat the packet? */
  if (raw_input(p, inp) == 0) {
#endif /* LWIP_RAW */

  switch (IPH_PROTO(iphdr)) {
#if LWIP_UDP
  case IP_PROTO_UDP:
  case IP_PROTO_UDPLITE:
    snmp_inc_ipindelivers();
    udp_input(p, inp);
    break;
#endif /* LWIP_UDP */
#if LWIP_TCP
  case IP_PROTO_TCP:
    snmp_inc_ipindelivers();
    tcp_input(p, inp);
    break;
#endif /* LWIP_TCP */
  case IP_PROTO_ICMP:
    snmp_inc_ipindelivers();
    icmp_input(p, inp);
    break;
  default:
    /* send ICMP destination protocol unreachable unless is was a broadcast */
    if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&
        !ip_addr_ismulticast(&(iphdr->dest))) {
      p->payload = iphdr;
      icmp_dest_unreach(p, ICMP_DUR_PROTO);
    }
    pbuf_free(p);

    LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));

    IP_STATS_INC(ip.proterr);
    IP_STATS_INC(ip.drop);
    snmp_inc_ipinunknownprotos();
  }
#if LWIP_RAW
  } /* LWIP_RAW */
#endif
  return ERR_OK;
}
コード例 #26
0
ファイル: pxping_win.c プロジェクト: bayasist/vbox
static void
pxping_icmp4_callback(struct pong4 *pong)
{
    ICMP_ECHO_REPLY *reply;
    DWORD nreplies;
    size_t icmplen;
    struct pbuf *p;
    struct icmp_echo_hdr *icmph;
    ip_addr_t src;
    int mapped;

    nreplies = IcmpParseReplies(pong->buf, (DWORD)pong->bufsize);
    if (nreplies == 0) {
        DWORD error = GetLastError();
        if (error == IP_REQ_TIMED_OUT) {
            DPRINTF2(("pong4: %p timed out\n", (void *)pong));
        }
        else {
            DPRINTF(("pong4: %p: IcmpParseReplies: error %d\n",
                     (void *)pong, error));
        }
        return;
    }

    reply = (ICMP_ECHO_REPLY *)pong->buf;

    if (reply->Options.OptionsSize != 0) { /* don't do options */
        return;
    }

    mapped = pxremap_inbound_ip4(&src, (ip_addr_t *)&reply->Address);
    if (mapped == PXREMAP_FAILED) {
        return;
    }
    if (mapped == PXREMAP_ASIS) {
        if (reply->Options.Ttl == 1) {
            return;
        }
        --reply->Options.Ttl;
    }

    if (reply->Status == IP_SUCCESS) {
        icmplen = sizeof(struct icmp_echo_hdr) + reply->DataSize;
        if ((reply->Options.Flags & IP_FLAG_DF) != 0
            && IP_HLEN + icmplen > pong->netif->mtu)
        {
            return;
        }

        p = pbuf_alloc(PBUF_IP, (u16_t)icmplen, PBUF_RAM);
        if (RT_UNLIKELY(p == NULL)) {
            return;
        }

        icmph = (struct icmp_echo_hdr *)p->payload;
        icmph->type = ICMP_ER;
        icmph->code = 0;
        icmph->chksum = 0;
        icmph->id = pong->reqicmph.id;
        icmph->seqno = pong->reqicmph.seqno;

        memcpy((u8_t *)p->payload + sizeof(*icmph),
               reply->Data, reply->DataSize);
    }
    else {
        u8_t type, code;

        switch (reply->Status) {
        case IP_DEST_NET_UNREACHABLE:
            type = ICMP_DUR; code = ICMP_DUR_NET;
            break;
        case IP_DEST_HOST_UNREACHABLE:
            type = ICMP_DUR; code = ICMP_DUR_HOST;
            break;
        case IP_DEST_PROT_UNREACHABLE:
            type = ICMP_DUR; code = ICMP_DUR_PROTO;
            break;
        case IP_PACKET_TOO_BIG:
            type = ICMP_DUR; code = ICMP_DUR_FRAG;
            break;
        case IP_SOURCE_QUENCH:
            type = ICMP_SQ; code = 0;
            break;
        case IP_TTL_EXPIRED_TRANSIT:
            type = ICMP_TE; code = ICMP_TE_TTL;
            break;
        case IP_TTL_EXPIRED_REASSEM:
            type = ICMP_TE; code = ICMP_TE_FRAG;
            break;
        default:
            DPRINTF(("pong4: reply status %d, dropped\n", reply->Status));
            return;
        }

        DPRINTF(("pong4: reply status %d -> type %d/code %d\n",
                 reply->Status, type, code));

        icmplen = sizeof(*icmph) + sizeof(pong->reqiph) + sizeof(pong->reqicmph);

        p = pbuf_alloc(PBUF_IP, (u16_t)icmplen, PBUF_RAM);
        if (RT_UNLIKELY(p == NULL)) {
            return;
        }

        icmph = (struct icmp_echo_hdr *)p->payload;
        icmph->type = type;
        icmph->code = code;
        icmph->chksum = 0;
        icmph->id = 0;
        icmph->seqno = 0;

        /*
         * XXX: we don't know the TTL of the request at the time this
         * ICMP error was generated (we can guess it was 1 for ttl
         * exceeded, but don't bother faking it).
         */
        memcpy((u8_t *)p->payload + sizeof(*icmph),
               &pong->reqiph, sizeof(pong->reqiph));

        memcpy((u8_t *)p->payload + sizeof(*icmph) + sizeof(pong->reqiph),
               &pong->reqicmph, sizeof(pong->reqicmph));
    }

    icmph->chksum = inet_chksum(p->payload, (u16_t)icmplen);
    ip_output_if(p, &src,
                 (ip_addr_t *)&pong->reqiph.src, /* dst */
                 reply->Options.Ttl,
                 reply->Options.Tos,
                 IPPROTO_ICMP,
                 pong->netif);
    pbuf_free(p);
}
コード例 #27
0
ファイル: igmp.c プロジェクト: EagleSmith/ESP31B
/**
 * Called from ip_input() if a new IGMP packet is received.
 *
 * @param p received igmp packet, p->payload pointing to the igmp header
 * @param inp network interface on which the packet was received
 * @param dest destination ip address of the igmp packet
 */
void
igmp_input(struct pbuf *p, struct netif *inp, const ip4_addr_t *dest)
{
  struct igmp_msg*   igmp;
  struct igmp_group* group;
  struct igmp_group* groupref;

  IGMP_STATS_INC(igmp.recv);

  /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */
  if (p->len < IGMP_MINLEN) {
    pbuf_free(p);
    IGMP_STATS_INC(igmp.lenerr);
    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
    return;
  }

  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
  ip4_addr_debug_print(IGMP_DEBUG, &(ip4_current_header()->src));
  LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
  ip4_addr_debug_print(IGMP_DEBUG, &(ip4_current_header()->dest));
  LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", (void*)inp));

  /* Now calculate and check the checksum */
  igmp = (struct igmp_msg *)p->payload;
  if (inet_chksum(igmp, p->len)) {
    pbuf_free(p);
    IGMP_STATS_INC(igmp.chkerr);
    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));
    return;
  }

  /* Packet is ok so find an existing group */
  group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */

  /* If group can be found or create... */
  if (!group) {
    pbuf_free(p);
    IGMP_STATS_INC(igmp.drop);
    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));
    return;
  }

  /* NOW ACT ON THE INCOMING MESSAGE TYPE... */
  switch (igmp->igmp_msgtype) {
  case IGMP_MEMB_QUERY:
    /* IGMP_MEMB_QUERY to the "all systems" address ? */
    if ((ip4_addr_cmp(dest, &allsystems)) && ip4_addr_isany(&igmp->igmp_group_address)) {
      /* THIS IS THE GENERAL QUERY */
      LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));

      if (igmp->igmp_maxresp == 0) {
        IGMP_STATS_INC(igmp.rx_v1);
        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
        igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
      } else {
        IGMP_STATS_INC(igmp.rx_general);
      }

      groupref = igmp_group_list;
      while (groupref) {
        /* Do not send messages on the all systems group address! */
        if ((groupref->netif == inp) && (!(ip4_addr_cmp(&(groupref->group_address), &allsystems)))) {
          igmp_delaying_member(groupref, igmp->igmp_maxresp);
        }
        groupref = groupref->next;
      }
    } else {
      /* IGMP_MEMB_QUERY to a specific group ? */
      if (!ip4_addr_isany(&igmp->igmp_group_address)) {
        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
        ip4_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address);
        if (ip4_addr_cmp(dest, &allsystems)) {
          ip4_addr_t groupaddr;
          LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
          /* we first need to re-look for the group since we used dest last time */
          ip4_addr_copy(groupaddr, igmp->igmp_group_address);
          group = igmp_lookfor_group(inp, &groupaddr);
        } else {
          LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
        }

        if (group != NULL) {
          IGMP_STATS_INC(igmp.rx_group);
          igmp_delaying_member(group, igmp->igmp_maxresp);
        } else {
          IGMP_STATS_INC(igmp.drop);
        }
      } else {
        IGMP_STATS_INC(igmp.proterr);
      }
    }
    break;
  case IGMP_V2_MEMB_REPORT:
    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
    IGMP_STATS_INC(igmp.rx_report);
    if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
      /* This is on a specific group we have already looked up */
      group->timer = 0; /* stopped */
      group->group_state = IGMP_GROUP_IDLE_MEMBER;
      group->last_reporter_flag = 0;
    }
    break;
  default:
    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
      igmp->igmp_msgtype, group->group_state, (void*)&group, (void*)group->netif));
    IGMP_STATS_INC(igmp.proterr);
    break;
  }

  pbuf_free(p);
  return;
}
コード例 #28
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 *q;
  struct ip_hdr *fraghdr, *iphdr;
  u16_t offset, len;
  u16_t i;

  IPFRAG_STATS_INC(ip_frag.recv);

  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) {
    LWIP_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. */
    memset(ip_reassbitmap, 0, 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)) {
    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n",
      ntohs(IPH_ID(fraghdr))));
    IPFRAG_STATS_INC(ip_frag.cachehit);
    /* 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) {
      LWIP_DEBUGF(IP_REASS_DEBUG,
       ("ip_reass: fragment outside of buffer (%"S16_F":%"S16_F"/%"S16_F").\n", offset,
        offset + len, IP_REASS_BUFSIZE));
      ip_reasstmr = 0;
      goto nullreturn;
    }

    /* Copy the fragment into the reassembly buffer, at the right
       offset. */
    LWIP_DEBUGF(IP_REASS_DEBUG,
     ("ip_reass: copying with offset %"S16_F" into %"S16_F":%"S16_F"\n", offset,
      IP_HLEN + offset, IP_HLEN + offset + len));
    i = IPH_HL(fraghdr) * 4;
    copy_from_pbuf(p, &i, &ip_reassbuf[IP_HLEN + offset], len);

    /* Update the bitmap. */
    if (offset / (8 * 8) == (offset + len) / (8 * 8)) {
      LWIP_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. */
      LWIP_ASSERT("offset / (8 * 8) < sizeof(ip_reassbitmap)",
                   offset / (8 * 8) < sizeof(ip_reassbitmap));
      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. */
      LWIP_ASSERT("offset / (8 * 8) < sizeof(ip_reassbitmap)",
                   offset / (8 * 8) < sizeof(ip_reassbitmap));
      ip_reassbitmap[offset / (8 * 8)] |= bitmap_bits[(offset / 8) & 7];
      LWIP_DEBUGF(IP_REASS_DEBUG,
       ("ip_reass: updating many bytes in bitmap (%"S16_F":%"S16_F").\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;
      }
      LWIP_ASSERT("(offset + len) / (8 * 8) < sizeof(ip_reassbitmap)",
                   (offset + len) / (8 * 8) < sizeof(ip_reassbitmap));
      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;
      LWIP_DEBUGF(IP_REASS_DEBUG,
       ("ip_reass: last fragment seen, total len %"S16_F"\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. */
      LWIP_ASSERT("ip_reasslen / (8 * 8) - 1 < sizeof(ip_reassbitmap)",
                   ip_reasslen / (8 * 8) - 1 < sizeof(ip_reassbitmap));
      for (i = 0; i < ip_reasslen / (8 * 8) - 1; ++i) {
        if (ip_reassbitmap[i] != 0xff) {
          LWIP_DEBUGF(IP_REASS_DEBUG,
           ("ip_reass: last fragment seen, bitmap %"S16_F"/%"S16_F" failed (%"X16_F")\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. */
      LWIP_ASSERT("ip_reasslen / (8 * 8) < sizeof(ip_reassbitmap)",
                   ip_reasslen / (8 * 8) < sizeof(ip_reassbitmap));
      if (ip_reassbitmap[ip_reasslen / (8 * 8)] !=
        (u8_t) ~ bitmap_bits[ip_reasslen / 8 & 7]) {
         LWIP_DEBUGF(IP_REASS_DEBUG,
          ("ip_reass: last fragment seen, bitmap %"S16_F" didn't contain %"X16_F" (%"X16_F")\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. */
      ip_reasslen += IP_HLEN;

      IPH_LEN_SET(iphdr, htons(ip_reasslen));
      IPH_OFFSET_SET(iphdr, 0);
      IPH_CHKSUM_SET(iphdr, 0);
      IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));

      /* 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
             available data in the pbuf is given by the q->len variable. */
          LWIP_DEBUGF(IP_REASS_DEBUG,
           ("ip_reass: memcpy from %p (%"S16_F") to %p, %"S16_F" bytes\n",
            (void *)&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;
        }
        IPFRAG_STATS_INC(ip_frag.fw);
      } else {
        IPFRAG_STATS_INC(ip_frag.memerr);
      }
      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: p %p\n", (void*)p));
      return p;
    }
  }

nullreturn:
  IPFRAG_STATS_INC(ip_frag.drop);
  pbuf_free(p);
  return NULL;
}
コード例 #29
0
err_t
ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
             u8_t ttl, u8_t tos,
             u8_t proto, struct netif *netif)
{
  struct ip_hdr *iphdr;
  static u16_t ip_id = 0;

  snmp_inc_ipoutrequests();

  if (dest != IP_HDRINCL) {
    if (pbuf_header(p, IP_HLEN)) {
      LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n"));

      IP_STATS_INC(ip.err);
      snmp_inc_ipoutdiscards();
      return ERR_BUF;
    }

    iphdr = p->payload;

    IPH_TTL_SET(iphdr, ttl);
    IPH_PROTO_SET(iphdr, proto);

    ip_addr_set(&(iphdr->dest), dest);

    IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, tos);
    IPH_LEN_SET(iphdr, htons(p->tot_len));
    IPH_OFFSET_SET(iphdr, htons(IP_DF));
    IPH_ID_SET(iphdr, htons(ip_id));
    ++ip_id;

    if (ip_addr_isany(src)) {
      ip_addr_set(&(iphdr->src), &(netif->ip_addr));
    } else {
      ip_addr_set(&(iphdr->src), src);
    }

    IPH_CHKSUM_SET(iphdr, 0);
#if CHECKSUM_GEN_IP
    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
#endif
  } else {
    iphdr = p->payload;
    dest = &(iphdr->dest);
  }

#if IP_FRAG
  /* don't fragment if interface has mtu set to 0 [loopif] */
  if (netif->mtu && (p->tot_len > netif->mtu))
    return ip_frag(p,netif,dest);
#endif

  IP_STATS_INC(ip.xmit);

  LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));
  ip_debug_print(p);

  LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));

  return netif->output(netif, p, dest);
}
コード例 #30
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_ROM)
 */
err_t 
ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
{
  struct pbuf *rambuf;
  struct pbuf *header;
  struct ip_hdr *iphdr;
  u16_t nfb = 0;
  u16_t left, cop;
  u16_t mtu = netif->mtu;
  u16_t ofo, omf;
  u16_t last;
  u16_t poff = IP_HLEN;
  u16_t tmp;

  /* Get a RAM based MTU sized pbuf */
  rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
  if (rambuf == NULL) {
    return ERR_MEM;
  }
  rambuf->tot_len = rambuf->len = mtu;
  rambuf->payload = MEM_ALIGN((void *)buf);

  /* Copy the IP header in it */
  iphdr = rambuf->payload;
  memcpy(iphdr, p->payload, IP_HLEN);

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

  left = p->tot_len - IP_HLEN;

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

    /* Set new offset and MF flag */
    ofo += nfb;
    tmp = omf | (IP_OFFMASK & (ofo));
    if (!last)
      tmp = tmp | IP_MF;
    IPH_OFFSET_SET(iphdr, htons(tmp));

    /* Fill this fragment */
    nfb = (mtu - IP_HLEN) / 8;
    cop = last ? left : nfb * 8;

    p = copy_from_pbuf(p, &poff, (u8_t *) iphdr + IP_HLEN, cop);

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

    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);
      pbuf_free(header);
    } else {
      pbuf_free(rambuf);      
      return ERR_MEM;    
    }
    left -= cop;
  }
  pbuf_free(rambuf);
  return ERR_OK;
}