91 |
struct udp_pcb *pcb; |
struct udp_pcb *pcb; |
92 |
struct udp_hdr *udphdr; |
struct udp_hdr *udphdr; |
93 |
u16_t src, dest; |
u16_t src, dest; |
94 |
|
|
95 |
PERF_START; |
PERF_START; |
96 |
|
|
97 |
udphdr = (struct udp_hdr *)(u8_t *)iphdr + IPH_HL(iphdr) * 4; |
udphdr = (struct udp_hdr *)(u8_t *)iphdr + IPH_HL(iphdr) * 4; |
98 |
|
|
99 |
src = NTOHS(udphdr->src); |
src = NTOHS(udphdr->src); |
100 |
dest = NTOHS(udphdr->dest); |
dest = NTOHS(udphdr->dest); |
101 |
|
|
102 |
pcb = pcb_cache; |
pcb = pcb_cache; |
103 |
if(pcb != NULL && |
if(pcb != NULL && |
104 |
pcb->remote_port == src && |
pcb->remote_port == src && |
105 |
pcb->local_port == dest && |
pcb->local_port == dest && |
106 |
(ip_addr_isany(&pcb->remote_ip) || |
(ip_addr_isany(&pcb->remote_ip) || |
107 |
ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) && |
ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src))) && |
108 |
(ip_addr_isany(&pcb->local_ip) || |
(ip_addr_isany(&pcb->local_ip) || |
109 |
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { |
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { |
110 |
return 1; |
return 1; |
111 |
} else { |
} |
112 |
|
else { |
113 |
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { |
for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { |
114 |
if(pcb->remote_port == src && |
if(pcb->remote_port == src && |
115 |
pcb->local_port == dest && |
pcb->local_port == dest && |
118 |
(ip_addr_isany(&pcb->local_ip) || |
(ip_addr_isany(&pcb->local_ip) || |
119 |
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { |
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { |
120 |
pcb_cache = pcb; |
pcb_cache = pcb; |
121 |
break; |
break; |
122 |
} |
} |
123 |
} |
} |
124 |
|
|
125 |
if(pcb == NULL) { |
if(pcb == NULL) { |
131 |
(ip_addr_isany(&pcb->local_ip) || |
(ip_addr_isany(&pcb->local_ip) || |
132 |
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { |
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)))) { |
133 |
break; |
break; |
134 |
} |
} |
135 |
} |
} |
136 |
} |
} |
137 |
} |
} |
138 |
|
|
139 |
PERF_STOP("udp_lookup"); |
PERF_STOP("udp_lookup"); |
140 |
|
|
141 |
if(pcb != NULL) { |
if(pcb != NULL) { |
142 |
return 1; |
return 1; |
143 |
} else { |
} |
144 |
|
else { |
145 |
return 1; |
return 1; |
146 |
} |
} |
147 |
} |
} |
148 |
#endif /* LWIP_DEBUG */ |
#endif /* LWIP_DEBUG */ |
149 |
/*-----------------------------------------------------------------------------------*/ |
/** |
150 |
|
* Process an incoming UDP datagram. |
151 |
|
* |
152 |
|
* Given an incoming UDP datagram (as a chain of pbufs) this function |
153 |
|
* finds a corresponding UDP PCB and |
154 |
|
* |
155 |
|
* @param pbuf pbuf to be demultiplexed to a UDP PCB. |
156 |
|
* @param netif network interface on which the datagram was received. |
157 |
|
* |
158 |
|
* @see udp_disconnect() |
159 |
|
*/ |
160 |
void |
void |
161 |
udp_input(struct pbuf *p, struct netif *inp) |
udp_input(struct pbuf *p, struct netif *inp) |
162 |
{ |
{ |
311 |
|
|
312 |
PERF_STOP("udp_input"); |
PERF_STOP("udp_input"); |
313 |
} |
} |
314 |
/*-----------------------------------------------------------------------------------*/ |
/** |
315 |
|
* Send data using UDP. |
316 |
|
* |
317 |
|
* @param pcb UDP PCB used to send the data. |
318 |
|
* @param pbuf chain of pbuf's to be sent. |
319 |
|
* |
320 |
|
* @return lwIP error code. |
321 |
|
* - ERR_OK. Successful. No error occured. |
322 |
|
* - ERR_MEM. Out of memory. |
323 |
|
* - ERR_USE. The specified ipaddr and port are already bound to by |
324 |
|
* another UDP PCB. |
325 |
|
* |
326 |
|
* @see udp_disconnect() |
327 |
|
*/ |
328 |
err_t |
err_t |
329 |
udp_send(struct udp_pcb *pcb, struct pbuf *p) |
udp_send(struct udp_pcb *pcb, struct pbuf *p) |
330 |
{ |
{ |
334 |
err_t err; |
err_t err; |
335 |
struct pbuf *hdr; |
struct pbuf *hdr; |
336 |
|
|
|
|
|
337 |
DEBUGF(UDP_DEBUG, ("udp_send")); |
DEBUGF(UDP_DEBUG, ("udp_send")); |
338 |
/* hdr will point to the UDP header pbuf if an extra header pbuf has |
/* hdr will point to the UDP header pbuf if an extra header pbuf has |
339 |
to be allocated. */ |
to be allocated. */ |
340 |
hdr = NULL; |
hdr = NULL; |
341 |
|
|
342 |
|
/* succeeding in adding an UDP header to first given pbuf in chain? */ |
343 |
if(pbuf_header(p, UDP_HLEN)) { |
if(pbuf_header(p, UDP_HLEN)) { |
344 |
|
/* allocate header in new pbuf */ |
345 |
hdr = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM); |
hdr = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM); |
346 |
|
/* new header pbuf could not be allocated? */ |
347 |
if(hdr == NULL) { |
if(hdr == NULL) { |
348 |
return ERR_MEM; |
return ERR_MEM; |
349 |
} |
} |
350 |
|
/* chain header in front of given pbuf */ |
351 |
pbuf_chain(hdr, p); |
pbuf_chain(hdr, p); |
352 |
|
/* have p point to header pbuf */ |
353 |
p = hdr; |
p = hdr; |
354 |
} |
} |
355 |
DEBUGF(UDP_DEBUG, ("udp_send: got pbuf")); |
DEBUGF(UDP_DEBUG, ("udp_send: got pbuf")); |
366 |
#endif /* UDP_STATS */ |
#endif /* UDP_STATS */ |
367 |
return ERR_RTE; |
return ERR_RTE; |
368 |
} |
} |
369 |
|
/* using IP_ANY_ADDR? */ |
370 |
if(ip_addr_isany(&pcb->local_ip)) { |
if(ip_addr_isany(&pcb->local_ip)) { |
371 |
|
/* use network interface IP address as source address */ |
372 |
src_ip = &(netif->ip_addr); |
src_ip = &(netif->ip_addr); |
373 |
} else { |
} else { |
374 |
|
/* use UDP PCB local IP address as source address */ |
375 |
src_ip = &(pcb->local_ip); |
src_ip = &(pcb->local_ip); |
376 |
} |
} |
377 |
|
|
378 |
DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %d\n", p->tot_len)); |
DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %d\n", p->tot_len)); |
379 |
|
|
380 |
|
/* UDP Lite protocol? */ |
381 |
if(pcb->flags & UDP_FLAGS_UDPLITE) { |
if(pcb->flags & UDP_FLAGS_UDPLITE) { |
382 |
DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %u", p->tot_len)); |
DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %u", p->tot_len)); |
383 |
/* set UDP message length in UDP header */ |
/* set UDP message length in UDP header */ |
385 |
/* calculate checksum */ |
/* calculate checksum */ |
386 |
udphdr->chksum = inet_chksum_pseudo(p, src_ip, &(pcb->remote_ip), |
udphdr->chksum = inet_chksum_pseudo(p, src_ip, &(pcb->remote_ip), |
387 |
IP_PROTO_UDP, pcb->chksum_len); |
IP_PROTO_UDP, pcb->chksum_len); |
388 |
if(udphdr->chksum == 0x0000) { |
/* chksum zero must become 0xffff, as zero means 'no checksum' */ |
389 |
udphdr->chksum = 0xffff; |
if(udphdr->chksum == 0x0000) udphdr->chksum = 0xffff; |
390 |
} |
/* output to IP */ |
391 |
err = ip_output_if(p, src_ip, &pcb->remote_ip, UDP_TTL, IP_PROTO_UDPLITE, netif); |
err = ip_output_if(p, src_ip, &pcb->remote_ip, UDP_TTL, IP_PROTO_UDPLITE, netif); |
392 |
#if LWIP_SNMP > 0 |
#if LWIP_SNMP > 0 |
393 |
snmp_inc_udpoutdatagrams(); |
snmp_inc_udpoutdatagrams(); |
397 |
udphdr->len = htons(p->tot_len); |
udphdr->len = htons(p->tot_len); |
398 |
/* calculate checksum */ |
/* calculate checksum */ |
399 |
if((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { |
if((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { |
400 |
udphdr->chksum = inet_chksum_pseudo(p, src_ip, &pcb->remote_ip, |
udphdr->chksum = inet_chksum_pseudo(p, src_ip, &pcb->remote_ip, IP_PROTO_UDP, p->tot_len); |
401 |
IP_PROTO_UDP, p->tot_len); |
/* chksum zero must become 0xffff, as zero means 'no checksum' */ |
402 |
if(udphdr->chksum == 0x0000) { |
if(udphdr->chksum == 0x0000) udphdr->chksum = 0xffff; |
|
udphdr->chksum = 0xffff; |
|
|
} |
|
403 |
} |
} |
404 |
DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum %x", udphdr->chksum)); |
DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum %x", udphdr->chksum)); |
405 |
#if LWIP_SNMP > 0 |
#if LWIP_SNMP > 0 |
406 |
snmp_inc_udpoutdatagrams(); |
snmp_inc_udpoutdatagrams(); |
407 |
#endif |
#endif |
408 |
DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if(,,,,IP_PROTO_UDP,)")); |
DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if(,,,,IP_PROTO_UDP,)")); |
409 |
|
/* output to IP */ |
410 |
err = ip_output_if(p, src_ip, &pcb->remote_ip, UDP_TTL, IP_PROTO_UDP, netif); |
err = ip_output_if(p, src_ip, &pcb->remote_ip, UDP_TTL, IP_PROTO_UDP, netif); |
411 |
} |
} |
412 |
|
/* dechain and free the header pbuf */ |
413 |
if(hdr != NULL) { |
if(hdr != NULL) { |
414 |
pbuf_dechain(hdr); |
pbuf_dechain(hdr); |
415 |
pbuf_free(hdr); |
pbuf_free(hdr); |
420 |
#endif /* UDP_STATS */ |
#endif /* UDP_STATS */ |
421 |
return err; |
return err; |
422 |
} |
} |
423 |
/*-----------------------------------------------------------------------------------*/ |
/** |
424 |
|
* Bind an UDP PCB. |
425 |
|
* |
426 |
|
* @param pcb UDP PCB to be bound with a local address ipaddr and port. |
427 |
|
* @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to |
428 |
|
* bind to all local interfaces. |
429 |
|
* @param port local UDP port to bind with. |
430 |
|
* |
431 |
|
* @return lwIP error code. |
432 |
|
* - ERR_OK. Successful. No error occured. |
433 |
|
* - ERR_USE. The specified ipaddr and port are already bound to by |
434 |
|
* another UDP PCB. |
435 |
|
* |
436 |
|
* @see udp_disconnect() |
437 |
|
*/ |
438 |
err_t |
err_t |
439 |
udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) |
udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) |
440 |
{ |
{ |
441 |
struct udp_pcb *ipcb; |
struct udp_pcb *ipcb; |
442 |
u8_t rebind = 0; |
u8_t rebind = 0; |
443 |
|
|
444 |
/* Check for double bind and rebind of the same pcb */ |
/* Check for double bind and rebind of the same pcb */ |
445 |
for(ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { |
for(ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { |
446 |
|
/* is this UDP PCB already on active list? */ |
447 |
if (pcb == ipcb) { |
if (pcb == ipcb) { |
448 |
rebind = 1; |
rebind = 1; |
449 |
break; |
} |
450 |
} else |
/* port matches that of PCB in list? */ |
451 |
if (ipcb->local_port == port) { |
if ((ipcb->local_port == port) && |
452 |
if(ip_addr_isany(&(ipcb->local_ip)) || |
/* IP address matches, or one is IP_ADDR_ANY? */ |
453 |
ip_addr_isany(ipaddr) || |
(ip_addr_isany(&(ipcb->local_ip)) || |
454 |
ip_addr_cmp(&(ipcb->local_ip), ipaddr)) { |
ip_addr_isany(ipaddr) || |
455 |
/* Port/IP pair already bound */ |
ip_addr_cmp(&(ipcb->local_ip), ipaddr))) { |
456 |
return ERR_USE; |
/* other PCB already binds to this local IP and port */ |
457 |
} |
return ERR_USE; |
458 |
} |
} |
459 |
} |
} |
460 |
|
/* bind local address */ |
461 |
ip_addr_set(&pcb->local_ip, ipaddr); |
ip_addr_set(&pcb->local_ip, ipaddr); |
462 |
pcb->local_port = port; |
pcb->local_port = port; |
463 |
|
|
464 |
/* We need to place the PCB on the list if not already there. */ |
/* We need to place the PCB on the list if not already there. */ |
465 |
if (rebind == 0) { |
if (rebind == 0) { |
466 |
pcb->next = udp_pcbs; |
pcb->next = udp_pcbs; |
470 |
DEBUGF(UDP_DEBUG, ("udp_bind: bound to port %d\n", port)); |
DEBUGF(UDP_DEBUG, ("udp_bind: bound to port %d\n", port)); |
471 |
return ERR_OK; |
return ERR_OK; |
472 |
} |
} |
473 |
/*-----------------------------------------------------------------------------------*/ |
/** |
474 |
|
* Connect an UDP PCB. |
475 |
|
* |
476 |
|
* @param pcb UDP PCB to be connected with remote address ipaddr and port. |
477 |
|
* @param ipaddr remote IP address to connect with. |
478 |
|
* @param port remote UDP port to connect with. |
479 |
|
* |
480 |
|
* @return lwIP error code |
481 |
|
* |
482 |
|
* @see udp_disconnect() |
483 |
|
*/ |
484 |
err_t |
err_t |
485 |
udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) |
udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) |
486 |
{ |
{ |
492 |
/* Insert UDP PCB into the list of active UDP PCBs. */ |
/* Insert UDP PCB into the list of active UDP PCBs. */ |
493 |
for(ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { |
for(ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { |
494 |
if(pcb == ipcb) { |
if(pcb == ipcb) { |
495 |
/* Already on the list, just return. */ |
/* already on the list, just return */ |
496 |
return ERR_OK; |
return ERR_OK; |
497 |
} |
} |
498 |
} |
} |
499 |
/* We need to place the PCB on the list. */ |
/* PCB not yet on the list, add PCB now */ |
500 |
pcb->next = udp_pcbs; |
pcb->next = udp_pcbs; |
501 |
udp_pcbs = pcb; |
udp_pcbs = pcb; |
502 |
return ERR_OK; |
return ERR_OK; |
514 |
struct ip_addr *addr, u16_t port), |
struct ip_addr *addr, u16_t port), |
515 |
void *recv_arg) |
void *recv_arg) |
516 |
{ |
{ |
517 |
|
/* remember recv() callback and user data */ |
518 |
pcb->recv = recv; |
pcb->recv = recv; |
519 |
pcb->recv_arg = recv_arg; |
pcb->recv_arg = recv_arg; |
520 |
} |
} |
521 |
/*-----------------------------------------------------------------------------------*/ |
/** |
522 |
|
* Remove an UDP PCB. |
523 |
|
* |
524 |
|
* @param pcb UDP PCB to be removed. The PCB is removed from the list of |
525 |
|
* UDP PCB's and the data structure is freed from memory. |
526 |
|
* |
527 |
|
* @see udp_new() |
528 |
|
*/ |
529 |
void |
void |
530 |
udp_remove(struct udp_pcb *pcb) |
udp_remove(struct udp_pcb *pcb) |
531 |
{ |
{ |
532 |
struct udp_pcb *pcb2; |
struct udp_pcb *pcb2; |
533 |
|
/* pcb to be removed is first in list? */ |
534 |
if(udp_pcbs == pcb) { |
if (udp_pcbs == pcb) { |
535 |
|
/* make list start at 2nd pcb */ |
536 |
udp_pcbs = udp_pcbs->next; |
udp_pcbs = udp_pcbs->next; |
537 |
|
/* pcb not 1st in list */ |
538 |
} else for(pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { |
} else for(pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { |
539 |
|
/* find pcb in udp_pcbs list */ |
540 |
if(pcb2->next != NULL && pcb2->next == pcb) { |
if(pcb2->next != NULL && pcb2->next == pcb) { |
541 |
|
/* remove pcb from list */ |
542 |
pcb2->next = pcb->next; |
pcb2->next = pcb->next; |
543 |
} |
} |
544 |
} |
} |
|
|
|
545 |
memp_free(MEMP_UDP_PCB, pcb); |
memp_free(MEMP_UDP_PCB, pcb); |
546 |
} |
} |
547 |
/*-----------------------------------------------------------------------------------*/ |
/** |
548 |
|
* Create a UDP PCB. |
549 |
|
* |
550 |
|
* @return The UDP PCB which was created. NULL if the PCB data structure |
551 |
|
* could not be allocated. |
552 |
|
* |
553 |
|
* @see udp_remove() |
554 |
|
*/ |
555 |
struct udp_pcb * |
struct udp_pcb * |
556 |
udp_new(void) { |
udp_new(void) { |
557 |
struct udp_pcb *pcb; |
struct udp_pcb *pcb; |
558 |
pcb = memp_malloc(MEMP_UDP_PCB); |
pcb = memp_malloc(MEMP_UDP_PCB); |
559 |
|
/* could allocate UDP PCB? */ |
560 |
if(pcb != NULL) { |
if(pcb != NULL) { |
561 |
pcb->flags = 0; |
/* initialize PCB to all zeroes */ |
562 |
memset(pcb, 0, sizeof(struct udp_pcb)); |
memset(pcb, 0, sizeof(struct udp_pcb)); |
|
return pcb; |
|
563 |
} |
} |
564 |
return NULL; |
return pcb; |
|
|
|
565 |
} |
} |
566 |
/*-----------------------------------------------------------------------------------*/ |
/*-----------------------------------------------------------------------------------*/ |
567 |
#if UDP_DEBUG |
#if UDP_DEBUG |