/** * Add a network interface to the list of lwIP netifs. * * @param netif a pre-allocated netif structure * @param ipaddr IP address for the new netif * @param netmask network mask for the new netif * @param gw default gateway IP address for the new netif * @param state opaque data passed to the new netif * @param init callback function that initializes the interface * @param input callback function that is called to pass * ingress packets up in the protocol layer stack. * * @return netif, or NULL if failed. */ struct netif * netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, struct ip_addr *gw, void *state, err_t (* init)(struct netif *netif), err_t (* input)(struct pbuf *p, struct netif *netif)) { static int netifnum = 0; #if LWIP_DHCP /* netif not under DHCP control by default */ netif->dhcp = NULL; #endif /* remember netif specific state information data */ netif->state = state; netif->num = netifnum++; netif->input = input; netif_set_addr(netif, ipaddr, netmask, gw); /* call user specified initialization function for netif */ if (init(netif) != ERR_OK) { return NULL; } /* add this netif to the list */ netif->next = netif_list; netif_list = netif; LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ", netif->name[0], netif->name[1])); ip_addr_debug_print(NETIF_DEBUG, ipaddr); LWIP_DEBUGF(NETIF_DEBUG, (" netmask ")); ip_addr_debug_print(NETIF_DEBUG, netmask); LWIP_DEBUGF(NETIF_DEBUG, (" gw ")); ip_addr_debug_print(NETIF_DEBUG, gw); LWIP_DEBUGF(NETIF_DEBUG, ("\n")); return netif; }
static void ping_thread(void *arg) { int s; int timeout = PING_RCV_TIMEO; ip_addr_t ping_target; LWIP_UNUSED_ARG(arg); netif_set_up(&fsl_netif0); if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0) { return; } lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); while (1) { ping_target = PING_TARGET; if (ping_send(s, &ping_target) == ERR_OK) { LWIP_DEBUGF( PING_DEBUG, ("ping: send ")); ip_addr_debug_print(PING_DEBUG, &ping_target); LWIP_DEBUGF( PING_DEBUG, ("\r\n")); ping_time = sys_now(); ping_recv(s); } else { LWIP_DEBUGF( PING_DEBUG, ("ping: send ")); ip_addr_debug_print(PING_DEBUG, &ping_target); LWIP_DEBUGF( PING_DEBUG, (" - error\r\n")); } sys_msleep(PING_DELAY); } }
/** * Dump global IGMP groups list */ void igmp_dump_group_list() { struct igmp_group *group = igmp_group_list; while (group != NULL) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%" U32_F "] ", (u32_t) (group->group_state))); ip_addr_debug_print(IGMP_DEBUG, &group->group_address); LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif)); group = group->next; } LWIP_DEBUGF(IGMP_DEBUG, ("\n")); }
/** * Stop IGMP processing on interface * * @param netif network interface on which stop IGMP processing */ err_t igmp_stop(struct netif *netif) { struct igmp_group *group = igmp_group_list; struct igmp_group *prev = NULL; struct igmp_group *next; /* look for groups joined on this interface further down the list */ while (group != NULL) { next = group->next; /* is it a group joined on this interface? */ if (group->netif == netif) { /* is it the first group of the list? */ if (group == igmp_group_list) { igmp_group_list = next; } /* is there a "previous" group defined? */ if (prev != NULL) { prev->next = next; } /* disable the group at the MAC level */ if (netif->igmp_mac_filter != NULL) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL ")); ip_addr_debug_print(IGMP_DEBUG, &group->group_address); LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER); } /* free group */ memp_free(MEMP_IGMP_GROUP, group); } else { /* change the "previous" */ prev = group; } /* move to "next" */ group = next; } return ERR_OK; }
/*-----------------------------------------------------------------------------------*/ int lwip_connect(int s, struct sockaddr *name, socklen_t namelen) { struct lwip_socket *sock; err_t err; sock = get_socket(s); if (!sock) { return -1; } if (((struct sockaddr_in *)name)->sin_family == AF_UNSPEC) { DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); err = netconn_disconnect(sock->conn); } else { struct ip_addr remote_addr; u16_t remote_port; remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr; remote_port = ((struct sockaddr_in *)name)->sin_port; #if SOCKETS_DEBUG DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); ip_addr_debug_print(&remote_addr); DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(remote_port))); #endif err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port)); } if (err != ERR_OK) { DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); sock_set_errno(sock, err_to_errno(err)); return -1; } DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); sock_set_errno(sock, 0); return 0; }
/*-----------------------------------------------------------------------------------*/ int lwip_sendto(int s, void *data, int size, unsigned int flags, struct sockaddr *to, socklen_t tolen) { struct lwip_socket *sock; struct ip_addr remote_addr, addr; u16_t remote_port, port; int ret,connected; sock = get_socket(s); if (!sock) { return -1; } /* get the peer if currently connected */ connected = (netconn_peer(sock->conn, &addr, &port) == ERR_OK); remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr; remote_port = ((struct sockaddr_in *)to)->sin_port; #if SOCKETS_DEBUG DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, size=%d, flags=0x%x to=", s, data, size, flags)); ip_addr_debug_print(&remote_addr); DEBUGF(SOCKETS_DEBUG, (" port=%u\n", ntohs(remote_port))); #endif netconn_connect(sock->conn, &remote_addr, ntohs(remote_port)); ret = lwip_send(s, data, size, flags); /* reset the remote address and port number of the connection */ if (connected) netconn_connect(sock->conn, &addr, port); else netconn_disconnect(sock->conn); return ret; }
static void ping_recv(int s) { char buf[64]; int fromlen, len; struct sockaddr_in from; struct ip_hdr *iphdr; struct icmp_echo_hdr *iecho; fromlen = sizeof(from); while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0) { if (len >= (int)(sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr))) { iphdr = (struct ip_hdr *)buf; iecho = (struct icmp_echo_hdr *)(buf + (IPH_HL(iphdr) * 4)); if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num))) { ip_addr_t fromaddr; inet_addr_to_ipaddr(&fromaddr, &from.sin_addr); LWIP_DEBUGF( PING_DEBUG, ("ping: recv ")); ip_addr_debug_print(PING_DEBUG, &fromaddr); LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\r\n", (sys_now() - ping_time))); // do some ping result processing PING_RESULT((ICMPH_TYPE(iecho) == ICMP_ER)); return; } } } if (len == 0) { LWIP_DEBUGF( PING_DEBUG, ("ping: recv - %"U32_F" ms - timeout\r\n", (sys_now()-ping_time))); } // do some ping result processing PING_RESULT(0); }
/** * Process an incoming UDP datagram. * * Given an incoming UDP datagram (as a chain of pbufs) this function * finds a corresponding UDP PCB and hands over the pbuf to the pcbs * recv function. If no pcb is found or the datagram is incorrect, the * pbuf is freed. * * @param p pbuf to be demultiplexed to a UDP PCB (p->payload pointing to the UDP header) * @param inp network interface on which the datagram was received. * */ void udp_input(struct pbuf *p, struct netif *inp) { struct udp_hdr *udphdr; struct udp_pcb *pcb, *prev; struct udp_pcb *uncon_pcb; u16_t src, dest; u8_t broadcast; u8_t for_us = 0; LWIP_UNUSED_ARG(inp); PERF_START; UDP_STATS_INC(udp.recv); /* Check minimum length (UDP header) */ if (p->len < UDP_HLEN) { /* drop short packets */ LWIP_DEBUGF(UDP_DEBUG, ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len)); UDP_STATS_INC(udp.lenerr); UDP_STATS_INC(udp.drop); MIB2_STATS_INC(mib2.udpinerrors); pbuf_free(p); goto end; } udphdr = (struct udp_hdr *)p->payload; /* is broadcast packet ? */ broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()); LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); /* convert src and dest ports to host byte order */ src = lwip_ntohs(udphdr->src); dest = lwip_ntohs(udphdr->dest); udp_debug_print(udphdr); /* print the UDP source and destination */ LWIP_DEBUGF(UDP_DEBUG, ("udp (")); ip_addr_debug_print(UDP_DEBUG, ip_current_dest_addr()); LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", lwip_ntohs(udphdr->dest))); ip_addr_debug_print(UDP_DEBUG, ip_current_src_addr()); LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", lwip_ntohs(udphdr->src))); pcb = NULL; prev = NULL; uncon_pcb = NULL; /* Iterate through the UDP pcb list for a matching pcb. * 'Perfect match' pcbs (connected to the remote port & ip address) are * preferred. If no perfect match is found, the first unconnected pcb that * matches the local port and ip address gets the datagram. */ for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { /* print the PCB local and remote address */ LWIP_DEBUGF(UDP_DEBUG, ("pcb (")); ip_addr_debug_print(UDP_DEBUG, &pcb->local_ip); LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", pcb->local_port)); ip_addr_debug_print(UDP_DEBUG, &pcb->remote_ip); LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port)); /* compare PCB local addr+port to UDP destination addr+port */ if ((pcb->local_port == dest) && (udp_input_local_match(pcb, inp, broadcast) != 0)) { if (((pcb->flags & UDP_FLAGS_CONNECTED) == 0) && ((uncon_pcb == NULL) #if SO_REUSE /* prefer specific IPs over cath-all */ || !ip_addr_isany(&pcb->local_ip) #endif /* SO_REUSE */ )) { /* the first unconnected matching PCB */ uncon_pcb = pcb; } /* compare PCB remote addr+port to UDP source addr+port */ if ((pcb->remote_port == src) && (ip_addr_isany_val(pcb->remote_ip) || ip_addr_cmp(&pcb->remote_ip, ip_current_src_addr()))) { /* the first fully matching PCB */ if (prev != NULL) { /* move the pcb to the front of udp_pcbs so that is found faster next time */ prev->next = pcb->next; pcb->next = udp_pcbs; udp_pcbs = pcb; } else { UDP_STATS_INC(udp.cachehit); } break; } } prev = pcb; } /* no fully matching pcb found? then look for an unconnected pcb */ if (pcb == NULL) { pcb = uncon_pcb; } /* Check checksum if this is a match or if it was directed at us. */ if (pcb != NULL) { for_us = 1; } else { #if LWIP_IPV6 if (ip_current_is_v6()) { for_us = netif_get_ip6_addr_match(inp, ip6_current_dest_addr()) >= 0; } #endif /* LWIP_IPV6 */ #if LWIP_IPV4 if (!ip_current_is_v6()) { for_us = ip4_addr_cmp(netif_ip4_addr(inp), ip4_current_dest_addr()); } #endif /* LWIP_IPV4 */ } if (for_us) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n")); #if CHECKSUM_CHECK_UDP IF__NETIF_CHECKSUM_ENABLED(inp, CHECKSUM_CHECK_UDP) { #if LWIP_UDPLITE if (ip_current_header_proto() == IP_PROTO_UDPLITE) { /* Do the UDP Lite checksum */ u16_t chklen = lwip_ntohs(udphdr->len); if (chklen < sizeof(struct udp_hdr)) { if (chklen == 0) { /* For UDP-Lite, checksum length of 0 means checksum over the complete packet (See RFC 3828 chap. 3.1) */ chklen = p->tot_len; } else { /* At least the UDP-Lite header must be covered by the checksum! (Again, see RFC 3828 chap. 3.1) */ goto chkerr; } } if (ip_chksum_pseudo_partial(p, IP_PROTO_UDPLITE, p->tot_len, chklen, ip_current_src_addr(), ip_current_dest_addr()) != 0) { goto chkerr; } } else #endif /* LWIP_UDPLITE */ { if (udphdr->chksum != 0) { if (ip_chksum_pseudo(p, IP_PROTO_UDP, p->tot_len, ip_current_src_addr(), ip_current_dest_addr()) != 0) { goto chkerr; } } } } #endif /* CHECKSUM_CHECK_UDP */ if (pbuf_header(p, -UDP_HLEN)) { /* Can we cope with this failing? Just assert for now */ LWIP_ASSERT("pbuf_header failed\n", 0); UDP_STATS_INC(udp.drop); MIB2_STATS_INC(mib2.udpinerrors); pbuf_free(p); goto end; } if (pcb != NULL) { MIB2_STATS_INC(mib2.udpindatagrams); #if SO_REUSE && SO_REUSE_RXTOALL if (ip_get_option(pcb, SOF_REUSEADDR) && (broadcast || ip_addr_ismulticast(ip_current_dest_addr()))) { /* pass broadcast- or multicast packets to all multicast pcbs if SOF_REUSEADDR is set on the first match */ struct udp_pcb *mpcb; u8_t p_header_changed = 0; s16_t hdrs_len = (s16_t)(ip_current_header_tot_len() + UDP_HLEN); for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) { if (mpcb != pcb) { /* compare PCB local addr+port to UDP destination addr+port */ if ((mpcb->local_port == dest) && (udp_input_local_match(mpcb, inp, broadcast) != 0)) { /* pass a copy of the packet to all local matches */ if (mpcb->recv != NULL) { struct pbuf *q; /* for that, move payload to IP header again */ if (p_header_changed == 0) { pbuf_header_force(p, hdrs_len); p_header_changed = 1; } q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); if (q != NULL) { err_t err = pbuf_copy(q, p); if (err == ERR_OK) { /* move payload to UDP data */ pbuf_header(q, -hdrs_len); mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src); } } } } } } if (p_header_changed) { /* and move payload to UDP data again */ pbuf_header(p, -hdrs_len); } } #endif /* SO_REUSE && SO_REUSE_RXTOALL */ /* callback */ if (pcb->recv != NULL) { /* now the recv function is responsible for freeing p */ pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src); } else { /* no recv function registered? then we have to free the pbuf! */ pbuf_free(p); goto end; } } else { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n")); #if LWIP_ICMP || LWIP_ICMP6 /* No match was found, send ICMP destination port unreachable unless destination address was broadcast/multicast. */ if (!broadcast && !ip_addr_ismulticast(ip_current_dest_addr())) { /* move payload pointer back to ip header */ pbuf_header_force(p, ip_current_header_tot_len() + UDP_HLEN); icmp_port_unreach(ip_current_is_v6(), p); } #endif /* LWIP_ICMP || LWIP_ICMP6 */ UDP_STATS_INC(udp.proterr); UDP_STATS_INC(udp.drop); MIB2_STATS_INC(mib2.udpnoports); pbuf_free(p); } } else {
/** * Add a network interface to the list of lwIP netifs. * * @param netif a pre-allocated netif structure * @param ipaddr IP address for the new netif * @param netmask network mask for the new netif * @param gw default gateway IP address for the new netif * @param state opaque data passed to the new netif * @param init callback function that initializes the interface * @param input callback function that is called to pass * ingress packets up in the protocol layer stack. * * @return netif, or NULL if failed. */ struct netif * netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, struct ip_addr *gw, void *state, err_t (* init)(struct netif *netif), err_t (* input)(struct pbuf *p, struct netif *netif)) { static u8_t netifnum = 0; /* reset new interface configuration state */ netif->ip_addr.addr = 0; netif->netmask.addr = 0; netif->gw.addr = 0; netif->flags = 0; #if LWIP_DHCP /* netif not under DHCP control by default */ netif->dhcp = NULL; #endif /* LWIP_DHCP */ #if LWIP_AUTOIP /* netif not under AutoIP control by default */ netif->autoip = NULL; #endif /* LWIP_AUTOIP */ #if LWIP_NETIF_STATUS_CALLBACK netif->status_callback = NULL; #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK netif->link_callback = NULL; #endif /* LWIP_NETIF_LINK_CALLBACK */ #if LWIP_IGMP netif->igmp_mac_filter = NULL; #endif /* LWIP_IGMP */ /* remember netif specific state information data */ netif->state = state; netif->num = netifnum++; netif->input = input; #if LWIP_NETIF_HWADDRHINT netif->addr_hint = NULL; #endif /* LWIP_NETIF_HWADDRHINT*/ netif_set_addr(netif, ipaddr, netmask, gw); /* call user specified initialization function for netif */ if (init(netif) != ERR_OK) { return NULL; } /* add this netif to the list */ netif->next = netif_list; netif_list = netif; snmp_inc_iflist(); #if LWIP_IGMP /* start IGMP processing */ if (netif->flags & NETIF_FLAG_IGMP) { igmp_start( netif); } #endif /* LWIP_IGMP */ LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ", netif->name[0], netif->name[1])); ip_addr_debug_print(NETIF_DEBUG, ipaddr); LWIP_DEBUGF(NETIF_DEBUG, (" netmask ")); ip_addr_debug_print(NETIF_DEBUG, netmask); LWIP_DEBUGF(NETIF_DEBUG, (" gw ")); ip_addr_debug_print(NETIF_DEBUG, gw); LWIP_DEBUGF(NETIF_DEBUG, ("\n")); return netif; }
/** * Called from ip_input() if a new IGMP packet is received. * * @param p received igmp packet, p->payload pointing to the ip 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, ip_addr_t *dest) { struct ip_hdr * iphdr; 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 */ iphdr = (struct ip_hdr *)p->payload; if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (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 ")); ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src)); LWIP_DEBUGF(IGMP_DEBUG, (" to address ")); ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest)); LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", 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 ((ip_addr_cmp(dest, &allsystems)) && ip_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) && (!(ip_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 (!ip_addr_isany(&igmp->igmp_group_address)) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group ")); ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address); if (ip_addr_cmp(dest, &allsystems)) { ip_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 */ ip_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, &group, group->netif)); IGMP_STATS_INC(igmp.proterr); break; } } pbuf_free(p); return; }
/** * Add a network interface to the list of lwIP netifs. * * @param netif a pre-allocated netif structure * @param ipaddr IP address for the new netif * @param netmask network mask for the new netif * @param gw default gateway IP address for the new netif * @param state opaque data passed to the new netif * @param init callback function that initializes the interface * @param input callback function that is called to pass * ingress packets up in the protocol layer stack. * * @return netif, or NULL if failed. */ struct netif * netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, struct ip_addr *gw, void *state, err_t (* init)(struct netif *netif), err_t (* input)(struct pbuf *p, struct netif *netif)) { static u8_t netifnum = 0; /* reset new interface configuration state */ netif->ip_addr.addr = 0; netif->netmask.addr = 0; netif->gw.addr = 0; // [MS_CHANGE] - Previously the LWIP code // cleared this field which is used a few // lines below. Since we set this flag to // enable multicast we will clear all bits // except this one netif->flags &= (NETIF_FLAG_IGMP | NETIF_FLAG_BROADCAST | NETIF_FLAG_DYNAMIC_DNS); #if LWIP_DHCP /* netif not under DHCP control by default */ netif->dhcp = NULL; #endif /* LWIP_DHCP */ #if LWIP_AUTOIP /* netif not under AutoIP control by default */ netif->autoip = NULL; #endif /* LWIP_AUTOIP */ #if LWIP_NETIF_STATUS_CALLBACK netif->status_callback = NULL; #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK netif->link_callback = NULL; #endif /* LWIP_NETIF_LINK_CALLBACK */ #if LWIP_IGMP netif->igmp_mac_filter = NULL; #endif /* LWIP_IGMP */ #if ENABLE_LOOPBACK netif->loop_first = NULL; netif->loop_last = NULL; #endif /* ENABLE_LOOPBACK */ /* remember netif specific state information data */ netif->state = state; netif->num = netifnum++; netif->input = input; #if LWIP_NETIF_HWADDRHINT netif->addr_hint = NULL; #endif /* LWIP_NETIF_HWADDRHINT*/ #if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS netif->loop_cnt_current = 0; #endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */ netif_set_addr(netif, ipaddr, netmask, gw); /* call user specified initialization function for netif */ if (init(netif) != ERR_OK) { return NULL; } /* add this netif to the list */ netif->next = netif_list; netif_list = netif; snmp_inc_iflist(); #if LWIP_IGMP /* start IGMP processing */ if (netif->flags & NETIF_FLAG_IGMP) { igmp_start( netif); } #endif /* LWIP_IGMP */ LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ", netif->name[0], netif->name[1])); ip_addr_debug_print(NETIF_DEBUG, ipaddr); LWIP_DEBUGF(NETIF_DEBUG, (" netmask ")); ip_addr_debug_print(NETIF_DEBUG, netmask); LWIP_DEBUGF(NETIF_DEBUG, (" gw ")); ip_addr_debug_print(NETIF_DEBUG, gw); LWIP_DEBUGF(NETIF_DEBUG, ("\n")); return netif; }
/** * Send the raw IP packet to the given address. Note that actually you cannot * modify the IP headers (this is inconsistent with the receive callback where * you actually get the IP headers), you can only specify the IP payload here. * It requires some more changes in lwIP. (there will be a raw_send() function * then.) * * @param pcb the raw pcb which to send * @param p the IP payload to send * @param ipaddr the destination address of the IP packet * */ err_t raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr) { err_t err; struct netif *netif; const ip_addr_t *src_ip; struct pbuf *q; /* q will be sent down the stack */ s16_t header_size; const ip_addr_t *dst_ip = ipaddr; if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) { return ERR_VAL; } LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); header_size = ( #if LWIP_IPV4 && LWIP_IPV6 IP_IS_V6(ipaddr) ? IP6_HLEN : IP_HLEN); #elif LWIP_IPV4 IP_HLEN); #else IP6_HLEN); #endif /* not enough space to add an IP header to first pbuf in given p chain? */ if (pbuf_header(p, header_size)) { /* allocate header in new pbuf */ q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM); /* new header pbuf could not be allocated? */ if (q == NULL) { LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n")); return ERR_MEM; } if (p->tot_len != 0) { /* chain header q in front of given pbuf p */ pbuf_chain(q, p); } /* { first pbuf q points to header pbuf } */ LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); } else { /* first pbuf q equals given pbuf */ q = p; if (pbuf_header(q, -header_size)) { LWIP_ASSERT("Can't restore header we just removed!", 0); return ERR_MEM; } } netif = ip_route(&pcb->local_ip, dst_ip); if (netif == NULL) { LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to ")); ip_addr_debug_print(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, dst_ip); /* free any temporary header pbuf allocated by pbuf_header() */ if (q != p) { pbuf_free(q); } return ERR_RTE; } #if IP_SOF_BROADCAST if (IP_IS_V4(ipaddr)) { /* broadcast filter? */ if (!ip_get_option(pcb, SOF_BROADCAST) && ip_addr_isbroadcast(ipaddr, netif)) { LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); /* free any temporary header pbuf allocated by pbuf_header() */ if (q != p) { pbuf_free(q); } return ERR_VAL; } } #endif /* IP_SOF_BROADCAST */ if (ip_addr_isany(&pcb->local_ip)) { /* use outgoing network interface IP address as source address */ src_ip = ip_netif_get_local_ip(netif, dst_ip); #if LWIP_IPV6 if (src_ip == NULL) { if (q != p) { pbuf_free(q); } return ERR_RTE; } #endif /* LWIP_IPV6 */ } else { /* use RAW PCB local IP address as source address */ src_ip = &pcb->local_ip; } #if LWIP_IPV6 /* If requested, based on the IPV6_CHECKSUM socket option per RFC3542, compute the checksum and update the checksum in the payload. */ if (IP_IS_V6(dst_ip) && pcb->chksum_reqd) { u16_t chksum = ip6_chksum_pseudo(p, pcb->protocol, p->tot_len, ip_2_ip6(src_ip), ip_2_ip6(dst_ip)); LWIP_ASSERT("Checksum must fit into first pbuf", p->len >= (pcb->chksum_offset + 2)); SMEMCPY(((u8_t *)p->payload) + pcb->chksum_offset, &chksum, sizeof(u16_t)); } #endif NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint); err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, pcb->protocol, netif); NETIF_SET_HWADDRHINT(netif, NULL); /* did we chain a header earlier? */ if (q != p) { /* free the header */ pbuf_free(q); } return err; }
/** * Add a network interface to the list of lwIP netifs. * * @param netif a pre-allocated netif structure * @param ipaddr IP address for the new netif * @param netmask network mask for the new netif * @param gw default gateway IP address for the new netif * @param state opaque data passed to the new netif * @param init callback function that initializes the interface * @param input callback function that is called to pass * ingress packets up in the protocol layer stack. * * @return netif, or NULL if failed. */ struct netif * netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input) { struct netif *temp; LWIP_ASSERT("No init function given", init != NULL); /* reset new interface configuration state */ ip_addr_set_zero(&netif->ip_addr); ip_addr_set_zero(&netif->netmask); ip_addr_set_zero(&netif->gw); netif->flags = 0; #if LWIP_DHCP /* netif not under DHCP control by default */ netif->dhcp = NULL; #endif /* LWIP_DHCP */ #if LWIP_AUTOIP /* netif not under AutoIP control by default */ netif->autoip = NULL; #endif /* LWIP_AUTOIP */ #if LWIP_NETIF_STATUS_CALLBACK netif->status_callback = NULL; #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK netif->link_callback = NULL; #endif /* LWIP_NETIF_LINK_CALLBACK */ #if LWIP_IGMP netif->igmp_mac_filter = NULL; #endif /* LWIP_IGMP */ #if ENABLE_LOOPBACK netif->loop_first = NULL; netif->loop_last = NULL; #endif /* ENABLE_LOOPBACK */ /* remember netif specific state information data */ netif->state = state; netif->num = netif_num++; netif->input = input; NETIF_SET_HWADDRHINT(netif, NULL); #if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS netif->loop_cnt_current = 0; #endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */ netif_set_addr(netif, ipaddr, netmask, gw); /* call user specified initialization function for netif */ if (init(netif) != ERR_OK) { return NULL; } /* add this netif to the list */ /* 之前采用头部插入法,现在改为尾部插入法 */ // netif->next = netif_list; // netif_list = netif; if(netif_list == NULL){ netif_list = netif; }else{ temp = netif_list; while(temp->next){ temp = temp->next; } temp->next = netif; netif->next = NULL; } snmp_inc_iflist(); #if LWIP_IGMP /* start IGMP processing */ if (netif->flags & NETIF_FLAG_IGMP) { igmp_start(netif); } #endif /* LWIP_IGMP */ LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ", netif->name[0], netif->name[1])); ip_addr_debug_print(NETIF_DEBUG, ipaddr); LWIP_DEBUGF(NETIF_DEBUG, (" netmask ")); ip_addr_debug_print(NETIF_DEBUG, netmask); LWIP_DEBUGF(NETIF_DEBUG, (" gw ")); ip_addr_debug_print(NETIF_DEBUG, gw); LWIP_DEBUGF(NETIF_DEBUG, ("\n")); return netif; }
/** * Bind an UDP PCB. * * @param pcb UDP PCB to be bound with a local address ipaddr and port. * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to * bind to all local interfaces. * @param port local UDP port to bind with. Use 0 to automatically bind * to a random port between UDP_LOCAL_PORT_RANGE_START and * UDP_LOCAL_PORT_RANGE_END. * * ipaddr & port are expected to be in the same byte order as in the pcb. * * @return lwIP error code. * - ERR_OK. Successful. No error occured. * - ERR_USE. The specified ipaddr and port are already bound to by * another UDP PCB. * * @see udp_disconnect() */ err_t udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) { struct udp_pcb *ipcb; u8_t rebind; LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = ")); ip_addr_debug_print(UDP_DEBUG, ipaddr); LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port)); rebind = 0; /* Check for double bind and rebind of the same pcb */ for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { /* is this UDP PCB already on active list? */ if (pcb == ipcb) { /* pcb may occur at most once in active list */ LWIP_ASSERT("rebind == 0", rebind == 0); /* pcb already in list, just rebind */ rebind = 1; } /* this code does not allow upper layer to share a UDP port for listening to broadcast or multicast traffic (See SO_REUSE_ADDR and SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR combine with implementation of UDP PCB flags. Leon Woestenberg. */ #ifdef LWIP_UDP_TODO /* port matches that of PCB in list? */ else if ((ipcb->local_port == port) && /* IP address matches, or one is IP_ADDR_ANY? */ (ip_addr_isany(&(ipcb->local_ip)) || ip_addr_isany(ipaddr) || ip_addr_cmp(&(ipcb->local_ip), ipaddr))) { /* other PCB already binds to this local IP and port */ LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: local port %"U16_F" already bound by another pcb\n", port)); return ERR_USE; } #endif } ip_addr_set(&pcb->local_ip, ipaddr); /* no port specified? */ if (port == 0) { #ifndef UDP_LOCAL_PORT_RANGE_START #define UDP_LOCAL_PORT_RANGE_START 4096 #define UDP_LOCAL_PORT_RANGE_END 0x7fff #endif port = UDP_LOCAL_PORT_RANGE_START; ipcb = udp_pcbs; while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) { if (ipcb->local_port == port) { /* port is already used by another udp_pcb */ port++; /* restart scanning all udp pcbs */ ipcb = udp_pcbs; } else /* go on with next udp pcb */ ipcb = ipcb->next; } if (ipcb != NULL) { /* no more ports available in local range */ LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n")); return ERR_USE; } } pcb->local_port = port; snmp_insert_udpidx_tree(pcb); /* pcb not active yet? */ if (rebind == 0) { /* place the PCB on the active list if not already there */ pcb->next = udp_pcbs; udp_pcbs = pcb; } LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n", (u16_t)((ntohl(pcb->local_ip.addr) >> 24) & 0xff), (u16_t)((ntohl(pcb->local_ip.addr) >> 16) & 0xff), (u16_t)((ntohl(pcb->local_ip.addr) >> 8) & 0xff), (u16_t)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port)); return ERR_OK; }
static void recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) { u16_t *sbuf = (u16_t *) p->payload; int opcode; LWIP_UNUSED_ARG(arg); LWIP_UNUSED_ARG(upcb); if (((tftp_state.port != 0) && (port != tftp_state.port)) || (!ip_addr_isany_val(tftp_state.addr) && !ip_addr_cmp(&tftp_state.addr, addr))) { send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported"); pbuf_free(p); return; } opcode = sbuf[0]; tftp_state.last_pkt = tftp_state.timer; tftp_state.retries = 0; switch (opcode) { case PP_HTONS(TFTP_RRQ): /* fall through */ case PP_HTONS(TFTP_WRQ): { const char tftp_null = 0; char filename[TFTP_MAX_FILENAME_LEN]; char mode[TFTP_MAX_MODE_LEN]; u16_t filename_end_offset; u16_t mode_end_offset; if(tftp_state.handle != NULL) { send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported"); break; } sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL); /* find \0 in pbuf -> end of filename string */ filename_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), 2); if((u16_t)(filename_end_offset-2) > sizeof(filename)) { send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Filename too long/not NULL terminated"); break; } pbuf_copy_partial(p, filename, filename_end_offset-2, 2); /* find \0 in pbuf -> end of mode string */ mode_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), filename_end_offset+1); if((u16_t)(mode_end_offset-filename_end_offset) > sizeof(mode)) { send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Mode too long/not NULL terminated"); break; } pbuf_copy_partial(p, mode, mode_end_offset-filename_end_offset, filename_end_offset+1); tftp_state.handle = tftp_state.ctx->open(filename, mode, opcode == PP_HTONS(TFTP_WRQ)); tftp_state.blknum = 1; if (!tftp_state.handle) { send_error(addr, port, TFTP_ERROR_FILE_NOT_FOUND, "Unable to open requested file."); break; } LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: %s request from ", (opcode == PP_HTONS(TFTP_WRQ)) ? "write" : "read")); ip_addr_debug_print(TFTP_DEBUG | LWIP_DBG_STATE, addr); LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, (" for '%s' mode '%s'\n", filename, mode)); ip_addr_copy(tftp_state.addr, *addr); tftp_state.port = port; if (opcode == PP_HTONS(TFTP_WRQ)) { tftp_state.mode_write = 1; send_ack(0); } else { tftp_state.mode_write = 0; send_data(); } break; } case PP_HTONS(TFTP_DATA): { int ret; u16_t blknum; if (tftp_state.handle == NULL) { send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection"); break; } if (tftp_state.mode_write != 1) { send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a write connection"); break; } blknum = lwip_ntohs(sbuf[1]); pbuf_header(p, -TFTP_HEADER_LENGTH); ret = tftp_state.ctx->write(tftp_state.handle, p); if (ret < 0) { send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "error writing file"); close_handle(); } else { send_ack(blknum); } if (p->tot_len < TFTP_MAX_PAYLOAD_SIZE) { close_handle(); } break; } case PP_HTONS(TFTP_ACK): { u16_t blknum; int lastpkt; if (tftp_state.handle == NULL) { send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection"); break; } if (tftp_state.mode_write != 0) { send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a read connection"); break; } blknum = lwip_ntohs(sbuf[1]); if (blknum != tftp_state.blknum) { send_error(addr, port, TFTP_ERROR_UNKNOWN_TRFR_ID, "Wrong block number"); break; } lastpkt = 0; if (tftp_state.last_data != NULL) { lastpkt = tftp_state.last_data->tot_len != (TFTP_MAX_PAYLOAD_SIZE + TFTP_HEADER_LENGTH); } if (!lastpkt) { tftp_state.blknum++; send_data(); } else { close_handle(); } break; } default: send_error(addr, port, TFTP_ERROR_ILLEGAL_OPERATION, "Unknown operation"); break; } pbuf_free(p); }
/** * Add a network interface to the list of lwIP netifs. * * @param netif a pre-allocated netif structure * @param ipaddr IP address for the new netif * @param netmask network mask for the new netif * @param gw default gateway IP address for the new netif * @param state opaque data passed to the new netif * @param init callback function that initializes the interface * @param input callback function that is called to pass * ingress packets up in the protocol layer stack. * * @return netif, or NULL if failed. */ struct netif * netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input) { #if LWIP_IPV6 u32_t i; #endif LWIP_ASSERT("No init function given", init != NULL); /* reset new interface configuration state */ ip_addr_set_zero(&netif->ip_addr); ip_addr_set_zero(&netif->netmask); ip_addr_set_zero(&netif->gw); #if LWIP_IPV6 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { ip6_addr_set_zero(&netif->ip6_addr[i]); netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID); } netif->output_ip6 = netif_null_output_ip6; #endif /* LWIP_IPV6 */ netif->flags = 0; #if LWIP_DHCP /* netif not under DHCP control by default */ netif->dhcp = NULL; #endif /* LWIP_DHCP */ #if LWIP_AUTOIP /* netif not under AutoIP control by default */ netif->autoip = NULL; #endif /* LWIP_AUTOIP */ #if LWIP_IPV6_AUTOCONFIG /* IPv6 address autoconfiguration not enabled by default */ netif->ip6_autoconfig_enabled = 0; #endif /* LWIP_IPV6_AUTOCONFIG */ #if LWIP_IPV6_SEND_ROUTER_SOLICIT netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT; #endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ #if LWIP_IPV6_DHCP6 /* netif not under DHCPv6 control by default */ netif->dhcp6 = NULL; #endif /* LWIP_IPV6_DHCP6 */ #if LWIP_NETIF_STATUS_CALLBACK netif->status_callback = NULL; #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK netif->link_callback = NULL; #endif /* LWIP_NETIF_LINK_CALLBACK */ #if LWIP_IGMP netif->igmp_mac_filter = NULL; #endif /* LWIP_IGMP */ #if LWIP_IPV6 && LWIP_IPV6_MLD netif->mld_mac_filter = NULL; #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ #if ENABLE_LOOPBACK netif->loop_first = NULL; netif->loop_last = NULL; #endif /* ENABLE_LOOPBACK */ /* remember netif specific state information data */ netif->state = state; #ifdef PSIPHON /* tun2socks as a library, with a multi-run lifetime, may invoke this multiple times */ netif->num = netif_num; #else netif->num = netif_num++; #endif /* PSIPHON */ netif->input = input; NETIF_SET_HWADDRHINT(netif, NULL); #if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS netif->loop_cnt_current = 0; #endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */ netif_set_addr(netif, ipaddr, netmask, gw); /* call user specified initialization function for netif */ if (init(netif) != ERR_OK) { return NULL; } /* add this netif to the list */ netif->next = netif_list; netif_list = netif; snmp_inc_iflist(); #if LWIP_IGMP /* start IGMP processing */ if (netif->flags & NETIF_FLAG_IGMP) { igmp_start(netif); } #endif /* LWIP_IGMP */ LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ", netif->name[0], netif->name[1])); ip_addr_debug_print(NETIF_DEBUG, ipaddr); LWIP_DEBUGF(NETIF_DEBUG, (" netmask ")); ip_addr_debug_print(NETIF_DEBUG, netmask); LWIP_DEBUGF(NETIF_DEBUG, (" gw ")); ip_addr_debug_print(NETIF_DEBUG, gw); LWIP_DEBUGF(NETIF_DEBUG, ("\n")); return netif; }
void ip_input(struct pbuf *p, struct netif *inp) { struct ip_hdr *iphdr; struct netif *netif; PERF_START; #if IP_DEBUG ip_debug_print(p); #endif /* IP_DEBUG */ IP_STATS_INC(ip.recv); /* identify the IP header */ iphdr = p->payload; if (iphdr->v != 6) { LWIP_DEBUGF(IP_DEBUG, ("IP packet dropped due to bad version number\n")); #if IP_DEBUG ip_debug_print(p); #endif /* IP_DEBUG */ pbuf_free(p); IP_STATS_INC(ip.err); IP_STATS_INC(ip.drop); return; } /* is this packet for us? */ for(netif = netif_list; netif != NULL; netif = netif->next) { #if IP_DEBUG LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest ")); ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest))); LWIP_DEBUGF(IP_DEBUG, ("netif->ip_addr ")); ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest))); LWIP_DEBUGF(IP_DEBUG, ("\n")); #endif /* IP_DEBUG */ if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr))) { break; } } if (netif == NULL) { /* packet not for us, route or discard */ #if IP_FORWARD ip_forward(p, iphdr); #endif pbuf_free(p); return; } pbuf_realloc(p, IP_HLEN + ntohs(iphdr->len)); /* send to upper layers */ #if IP_DEBUG /* LWIP_DEBUGF("ip_input: \n"); ip_debug_print(p); LWIP_DEBUGF("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/ #endif /* IP_DEBUG */ if(pbuf_header(p, -IP_HLEN)) { LWIP_ASSERT("Can't move over header in packet", 0); return; } switch (iphdr->nexthdr) { case IP_PROTO_UDP: udp_input(p, inp); break; case IP_PROTO_TCP: tcp_input(p, inp); break; #if LWIP_ICMP case IP_PROTO_ICMP: icmp_input(p, inp); break; #endif /* LWIP_ICMP */ default: #if LWIP_ICMP /* send ICMP destination protocol unreachable */ icmp_dest_unreach(p, ICMP_DUR_PROTO); #endif /* LWIP_ICMP */ pbuf_free(p); LWIP_DEBUGF(IP_DEBUG, ("Unsupported transport protocol %"U16_F"\n", iphdr->nexthdr)); IP_STATS_INC(ip.proterr); IP_STATS_INC(ip.drop); } PERF_STOP("ip_input"); }
int lwip_recvfrom(int s, void *mem, int len, unsigned int flags, struct sockaddr *from, socklen_t *fromlen) { struct lwip_socket *sock; struct netbuf *buf; u16_t buflen, copylen; struct ip_addr *addr; u16_t port; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %d, 0x%x, ..)\n", s, mem, len, flags)); sock = get_socket(s); if (!sock) { set_errno(EBADF); return -1; } /* Check if there is data left from the last recv operation. */ if (sock->lastdata) { buf = sock->lastdata; } else { /* If this is non-blocking call, then check first */ if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) && !sock->rcvevent) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s)); sock_set_errno(sock, EWOULDBLOCK); return -1; } /* No data was left from the previous operation, so we try to get some from the network. */ buf = netconn_recv(sock->conn); if (!buf) { /* We should really do some error checking here. */ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s)); sock_set_errno(sock, 0); return 0; } } buflen = netbuf_len(buf); buflen -= sock->lastoffset; if (len > buflen) { copylen = buflen; } else { copylen = len; } /* copy the contents of the received buffer into the supplied memory pointer mem */ netbuf_copy_partial(buf, mem, copylen, sock->lastoffset); /* Check to see from where the data was. */ if (from && fromlen) { struct sockaddr_in sin; addr = netbuf_fromaddr(buf); port = netbuf_fromport(buf); memset(&sin, 0, sizeof(sin)); sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; sin.sin_port = htons(port); sin.sin_addr.s_addr = addr->addr; if (*fromlen > sizeof(sin)) *fromlen = sizeof(sin); memcpy(from, &sin, *fromlen); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); ip_addr_debug_print(SOCKETS_DEBUG, addr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen)); } else { #if SOCKETS_DEBUG addr = netbuf_fromaddr(buf); port = netbuf_fromport(buf); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); ip_addr_debug_print(SOCKETS_DEBUG, addr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen)); #endif } /* If this is a TCP socket, check if there is data left in the buffer. If so, it should be saved in the sock structure for next time around. */ if (netconn_type(sock->conn) == NETCONN_TCP && buflen - copylen > 0) { sock->lastdata = buf; sock->lastoffset += copylen; } else { sock->lastdata = NULL; sock->lastoffset = 0; netbuf_delete(buf); } sock_set_errno(sock, 0); return copylen; }
/* Ping using the raw ip */ static u8_t ICACHE_FLASH_ATTR ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr) { struct icmp_echo_hdr *iecho = NULL; static u16_t seqno = 0; // struct ping_msg *pingmsg = (struct ping_msg*)arg; LWIP_UNUSED_ARG(arg); LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(addr); LWIP_ASSERT("p != NULL", p != NULL); if (pbuf_header( p, -PBUF_IP_HLEN)==0) { iecho = (struct icmp_echo_hdr *)p->payload; if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num)) && iecho->type == ICMP_ER) { LWIP_DEBUGF( PING_DEBUG, ("ping: recv ")); ip_addr_debug_print(PING_DEBUG, addr); LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\n", (sys_now()-ping_time))); if (iecho->seqno != seqno){ /* do some ping result processing */ { struct ip_hdr *iphdr = NULL; char ipaddrstr[16]; ip_addr_t source_ip; sys_untimeout(ping_timeout, pingmsg); os_bzero(&source_ip, sizeof(ip_addr_t)); os_bzero(ipaddrstr, sizeof(ipaddrstr)); uint32 delay = system_relative_time(pingmsg->ping_sent); delay /= PING_COARSE; iphdr = (struct ip_hdr*)((u8*)iecho - PBUF_IP_HLEN); source_ip.addr = iphdr->src.addr; ipaddr_ntoa_r(&source_ip,ipaddrstr, sizeof(ipaddrstr)); if (pingmsg->ping_opt->recv_function == NULL){ os_printf("recv %s: byte = %d, time = %d ms, seq = %d\n",ipaddrstr, PING_DATA_SIZE, delay, ntohs(iecho->seqno)); } else { struct ping_resp pingresp; os_bzero(&pingresp, sizeof(struct ping_resp)); pingresp.bytes = PING_DATA_SIZE; pingresp.resp_time = delay; pingresp.seqno = ntohs(iecho->seqno); pingresp.ping_err = 0; pingmsg->ping_opt->recv_function(pingmsg->ping_opt,(void*) &pingresp); } } seqno = iecho->seqno; } PING_RESULT(1); pbuf_free(p); return 1; /* eat the packet */ } // } else if(iecho->type == ICMP_ECHO){ // struct pbuf *q = NULL; // os_printf("receive ping request:seq=%d\n", ntohs(iecho->seqno)); // q = pbuf_alloc(PBUF_IP, (u16_t)p->tot_len, PBUF_RAM); // if (q!=NULL) { // pbuf_copy(q, p); // iecho = (struct icmp_echo_hdr *)q->payload; // ping_prepare_er(iecho, q->tot_len); // raw_sendto(pcb, q, addr); // pbuf_free(q); // } // pbuf_free(p); // return 1; // } } return 0; /* don't eat the packet */ }
static void recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port) { struct tftp_state *ts = (struct tftp_state *) arg; char *buf = (char *) p->payload; u16_t *sbuf = (u16_t *) p->payload; int blknum; int lastpkt; if (ts->port != 0 && port != ts->port) { pbuf_free(p); return; } int opcode = ntohs(sbuf[0]); buf[p->len] = 0; ts->last_pkt = ts->timer; ts->retries = 0; switch (opcode) { case RRQ: case WRQ: close_handle(ts); char *filename = &buf[2]; char *mode = &buf[2]; while(*mode) mode++; mode++; if ((mode - buf) >= p->len) break; ts->handle = ts->ctx->open(filename, mode, opcode == WRQ); ts->blknum = 1; if (!ts->handle) { send_error(upcb, addr, port, ERROR_FILE_NOT_FOUND, "Unable to open requested file."); break; } LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: %s request from ", (opcode == WRQ) ? "write" : "read")); ip_addr_debug_print(TFTP_DEBUG | LWIP_DBG_STATE, addr); LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, (" for '%s' mode '%s'\n", filename, mode)); ts->upcb = upcb; ts->addr = addr; ts->port = port; if (opcode == WRQ) send_ack(upcb, addr, port, 0); else send_data(upcb, addr, port, ts); break; case DATA: if (ts->handle == NULL) break; blknum = ntohs(sbuf[1]); pbuf_header(p, -4); int ret = ts->ctx->write(ts->handle, p); if (ret < 0) { send_error(upcb, addr, port, ERROR_ACCESS_VIOLATION, "error writing file"); close_handle(ts); } else { send_ack(upcb, addr, port, blknum); } if (p->len < 512) close_handle(ts); break; case ACK: if (ts->handle == NULL) break; blknum = ntohs(sbuf[1]); if (blknum != ts->blknum) break; lastpkt = 0; if (ts->last_data != NULL) { lastpkt = ts->last_data->len != (512+4); pbuf_free(ts->last_data); ts->last_data = NULL; } if (!lastpkt) { ts->blknum++; send_data(upcb, addr, port, ts); } else { close_handle(ts); } break; } pbuf_free(p); }