static u8_t
udp_input_local_match(struct udp_pcb *pcb, struct netif *inp, u8_t broadcast)
{
/* Dual-stack: PCBs listening to any IP type also listen to any IP address */
if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) {
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())) {
/* 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 (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
/* Handle IPv4 and IPv6: 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;
}
/*在协议控制块中绑定本地IP地址和本地IP端口号*/
int udp_bind(struct udp_pcb *pcb, const in_addr_udp *ipaddr, u_short port) {
struct udp_pcb *ipcb;
u_char rebind;
/* 不要将空指针(IPv4任何)传播给后续函数 */
if (ipaddr == NULL) {
ipaddr = IP4_ADDR_ANY;
}
/* still need to check for ipaddr == NULL in IPv6 only case */
if ((pcb == NULL) || (ipaddr == NULL)
|| !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
return ERR_VAL;
}
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) {
rebind = 1;
break;
}
}
/* no port specified? */
if (port == 0) {
port = udp_new_port();
if (port == 0) {
/* no more ports available in local range */
return ERR_USE;
}
} else {
for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
if (pcb != ipcb) {
/* By default, we don't allow to bind to a port that any other udp
PCB is already bound to, unless *all* PCBs with that port have tha
REUSEADDR flag set. */
{
/* port matches that of PCB in list and REUSEADDR not set -> reject *//* IP address matches? */
if ((ipcb->local_port == port)
&& ip_addr_cmp(&ipcb->local_ip, ipaddr)) {
return ERR_USE;
}
}
}
}
}
ip_addr_set_ipaddr(&pcb->local_ip, ipaddr);
pcb->local_port = port;
/* 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;
}
return ERR_OK;
} /*udp_bind()*/
static u16_t udp_new_port(void) {
u16_t n = 0;
struct udp_pcb *pcb;
again: if (udp_port++ == UDP_LOCAL_PORT_RANGE_END) {
udp_port = UDP_LOCAL_PORT_RANGE_START;
}
/* Check all PCBs. */
for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
if (pcb->local_port == udp_port) {
if (++n > (UDP_LOCAL_PORT_RANGE_END - UDP_LOCAL_PORT_RANGE_START)) {
return 0;
}
goto again;
}
}
return udp_port;
} /*udp_new_port()*/