/** Common code to see if the current input packet matches the pcb * (current input packet is accessed via ip(4/6)_current_* macros) * * @param pcb pcb to check * @param inp network interface on which the datagram was received (only used for IPv4) * @param broadcast 1 if his is an IPv4 broadcast (global or subnet-only), 0 otherwise (only used for IPv4) * @return 1 on match, 0 otherwise */ static u8_t ESP_IRAM_ATTR udp_input_local_match(struct udp_pcb *pcb, struct netif *inp, u8_t broadcast) { LWIP_UNUSED_ARG(inp); /* in IPv6 only case */ LWIP_UNUSED_ARG(broadcast); /* in IPv6 only case */ /* Dual-stack: PCBs listening to any IP type also listen to any IP address */ if(IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { #if LWIP_IPV4 && IP_SOF_BROADCAST_RECV if((broadcast != 0) && !ip_get_option(pcb, SOF_BROADCAST)) { return 0; } #endif /* LWIP_IPV4 && IP_SOF_BROADCAST_RECV */ return 1; } /* Only need to check PCB if incoming IP version matches PCB IP version */ if(IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ip_current_dest_addr())) { LWIP_ASSERT("UDP PCB: inconsistent local/remote IP versions", IP_IS_V6_VAL(pcb->local_ip) == IP_IS_V6_VAL(pcb->remote_ip)); #if LWIP_IPV4 /* Special case: IPv4 broadcast: all or broadcasts in my subnet * Note: broadcast variable can only be 1 if it is an IPv4 broadcast */ if(broadcast != 0) { #if IP_SOF_BROADCAST_RECV if(ip_get_option(pcb, SOF_BROADCAST)) #endif /* IP_SOF_BROADCAST_RECV */ { if(ip4_addr_isany(ip_2_ip4(&pcb->local_ip)) || ((ip4_current_dest_addr()->addr == IPADDR_BROADCAST)) || ip4_addr_netcmp(ip_2_ip4(&pcb->local_ip), ip4_current_dest_addr(), netif_ip4_netmask(inp))) { return 1; } } } else #endif /* LWIP_IPV4 */ /* Handle IPv4 and IPv6: all, multicast or exact match */ if(ip_addr_isany(&pcb->local_ip) || #if LWIP_IPV6_MLD (ip_current_is_v6() && ip6_addr_ismulticast(ip6_current_dest_addr())) || #endif /* LWIP_IPV6_MLD */ #if LWIP_IGMP (!ip_current_is_v6() && ip4_addr_ismulticast(ip4_current_dest_addr())) || #endif /* LWIP_IGMP */ ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { return 1; } } return 0; }
static u8_t raw_input_match(struct raw_pcb *pcb, u8_t broadcast) { LWIP_UNUSED_ARG(broadcast); /* in IPv6 only case */ #if LWIP_IPV4 && LWIP_IPV6 /* Dual-stack: PCBs listening to any IP type also listen to any IP address */ if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { #if IP_SOF_BROADCAST_RECV if ((broadcast != 0) && !ip_get_option(pcb, SOF_BROADCAST)) { return 0; } #endif /* IP_SOF_BROADCAST_RECV */ return 1; } #endif /* LWIP_IPV4 && LWIP_IPV6 */ /* Only need to check PCB if incoming IP version matches PCB IP version */ if (IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ip_current_dest_addr())) { #if LWIP_IPV4 /* Special case: IPv4 broadcast: receive all broadcasts * Note: broadcast variable can only be 1 if it is an IPv4 broadcast */ if (broadcast != 0) { #if IP_SOF_BROADCAST_RECV if (ip_get_option(pcb, SOF_BROADCAST)) #endif /* IP_SOF_BROADCAST_RECV */ { if (ip4_addr_isany(ip_2_ip4(&pcb->local_ip))) { return 1; } } } else #endif /* LWIP_IPV4 */ /* Handle IPv4 and IPv6: catch all or exact match */ if (ip_addr_isany(&pcb->local_ip) || ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { return 1; } } return 0; }
/** * @ingroup raw_raw * 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; 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; } } if(IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { /* Don't call ip_route() with IP_ANY_TYPE */ netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(ipaddr)), ipaddr, pcb->interface_name); } else { netif = ip_route(&pcb->local_ip, ipaddr, pcb->interface_name); } 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, ipaddr); /* 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, ipaddr); #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(ipaddr) && pcb->chksum_reqd) { u16_t chksum = ip6_chksum_pseudo(p, pcb->protocol, p->tot_len, ip_2_ip6(src_ip), ip_2_ip6(ipaddr)); 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, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif); NETIF_SET_HWADDRHINT(netif, NULL); /* did we chain a header earlier? */ if (q != p) { /* free the header */ pbuf_free(q); } return err; }