📄 udp.c
字号:
} }#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 /* No match was found, send ICMP destination port unreachable unless destination address was broadcast/multicast. */ if (!broadcast && !ip_addr_ismulticast(¤t_iphdr_dest)) { /* move payload pointer back to ip header */ pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN); LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr)); icmp_dest_unreach(p, ICMP_DUR_PORT); }#endif /* LWIP_ICMP */ UDP_STATS_INC(udp.proterr); UDP_STATS_INC(udp.drop); snmp_inc_udpnoports(); pbuf_free(p); } } else { pbuf_free(p); }end: PERF_STOP("udp_input");}/** * Send data using UDP. * * @param pcb UDP PCB used to send the data. * @param p chain of pbuf's to be sent. * * The datagram will be sent to the current remote_ip & remote_port * stored in pcb. If the pcb is not bound to a port, it will * automatically be bound to a random port. * * @return lwIP error code. * - ERR_OK. Successful. No error occured. * - ERR_MEM. Out of memory. * - ERR_RTE. Could not find route to destination address. * - More errors could be returned by lower protocol layers. * * @see udp_disconnect() udp_sendto() */err_tudp_send(struct udp_pcb *pcb, struct pbuf *p){ /* send to the packet using remote ip and port stored in the pcb */ return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);}#if LWIP_CHECKSUM_ON_COPY/** Same as udp_send() but with checksum */err_tudp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, u8_t have_chksum, u16_t chksum){ /* send to the packet using remote ip and port stored in the pcb */ return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port, have_chksum, chksum);}#endif /* LWIP_CHECKSUM_ON_COPY *//** * Send data to a specified address using UDP. * * @param pcb UDP PCB used to send the data. * @param p chain of pbuf's to be sent. * @param dst_ip Destination IP address. * @param dst_port Destination UDP port. * * dst_ip & dst_port are expected to be in the same byte order as in the pcb. * * If the PCB already has a remote address association, it will * be restored after the data is sent. * * @return lwIP error code (@see udp_send for possible error codes) * * @see udp_disconnect() udp_send() */err_tudp_sendto(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port){#if LWIP_CHECKSUM_ON_COPY return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0);}/** Same as udp_sendto(), but with checksum */err_tudp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port, u8_t have_chksum, u16_t chksum){#endif /* LWIP_CHECKSUM_ON_COPY */ struct netif *netif; LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); /* find the outgoing network interface for this packet */#if LWIP_IGMP netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip));#else netif = ip_route(dst_ip);#endif /* LWIP_IGMP */ /* no outgoing network interface could be found? */ if (netif == NULL) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", ip4_addr1_16(dst_ip), ip4_addr2_16(dst_ip), ip4_addr3_16(dst_ip), ip4_addr4_16(dst_ip))); UDP_STATS_INC(udp.rterr); return ERR_RTE; }#if LWIP_CHECKSUM_ON_COPY return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum);#else /* LWIP_CHECKSUM_ON_COPY */ return udp_sendto_if(pcb, p, dst_ip, dst_port, netif);#endif /* LWIP_CHECKSUM_ON_COPY */}/** * Send data to a specified address using UDP. * The netif used for sending can be specified. * * This function exists mainly for DHCP, to be able to send UDP packets * on a netif that is still down. * * @param pcb UDP PCB used to send the data. * @param p chain of pbuf's to be sent. * @param dst_ip Destination IP address. * @param dst_port Destination UDP port. * @param netif the netif used for sending. * * dst_ip & dst_port are expected to be in the same byte order as in the pcb. * * @return lwIP error code (@see udp_send for possible error codes) * * @see udp_disconnect() udp_send() */err_tudp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif){#if LWIP_CHECKSUM_ON_COPY return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0);}/** Same as udp_sendto_if(), but with checksum */err_tudp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, u8_t have_chksum, u16_t chksum){#endif /* LWIP_CHECKSUM_ON_COPY */ struct udp_hdr *udphdr; ip_addr_t *src_ip; err_t err; struct pbuf *q; /* q will be sent down the stack */#if IP_SOF_BROADCAST /* broadcast filter? */ if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); return ERR_VAL; }#endif /* IP_SOF_BROADCAST */ /* if the PCB is not yet bound to a port, bind it here */ if (pcb->local_port == 0) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n")); err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); if (err != ERR_OK) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n")); return err; } } /* not enough space to add an UDP header to first pbuf in given p chain? */ if (pbuf_header(p, UDP_HLEN)) { /* allocate header in a separate new pbuf */ q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM); /* new header pbuf could not be allocated? */ if (q == NULL) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n")); return ERR_MEM; } if (p->tot_len != 0) { /* chain header q in front of given pbuf p (only if p contains data) */ pbuf_chain(q, p); } /* first pbuf q points to header pbuf */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); } else { /* adding space for header within p succeeded */ /* first pbuf q equals given pbuf */ q = p; LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p)); } LWIP_ASSERT("check that first pbuf can hold struct udp_hdr", (q->len >= sizeof(struct udp_hdr))); /* q now represents the packet to be sent */ udphdr = (struct udp_hdr *)q->payload; udphdr->src = htons(pcb->local_port); udphdr->dest = htons(dst_port); /* in UDP, 0 checksum means 'no checksum' */ udphdr->chksum = 0x0000; /* Multicast Loop? */#if LWIP_IGMP if (ip_addr_ismulticast(dst_ip) && ((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0)) { q->flags |= PBUF_FLAG_MCASTLOOP; }#endif /* LWIP_IGMP */ /* PCB local address is IP_ANY_ADDR? */ if (ip_addr_isany(&pcb->local_ip)) { /* use outgoing network interface IP address as source address */ src_ip = &(netif->ip_addr); } else { /* check if UDP PCB local IP address is correct * this could be an old address if netif->ip_addr has changed */ if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) { /* local_ip doesn't match, drop the packet */ if (q != p) { /* free the header pbuf */ pbuf_free(q); q = NULL; /* p is still referenced by the caller, and will live on */ } return ERR_VAL; } /* use UDP PCB local IP address as source address */ src_ip = &(pcb->local_ip); } LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len));#if LWIP_UDPLITE /* UDP Lite protocol? */ if (pcb->flags & UDP_FLAGS_UDPLITE) { u16_t chklen, chklen_hdr; LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len)); /* set UDP message length in UDP header */ chklen_hdr = chklen = pcb->chksum_len_tx; if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) { if (chklen != 0) { LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen)); } /* For UDP-Lite, checksum length of 0 means checksum over the complete packet. (See RFC 3828 chap. 3.1) At least the UDP-Lite header must be covered by the checksum, therefore, if chksum_len has an illegal value, we generate the checksum over the complete packet to be safe. */ chklen_hdr = 0; chklen = q->tot_len; } udphdr->len = htons(chklen_hdr); /* calculate checksum */#if CHECKSUM_GEN_UDP udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDPLITE, q->tot_len,#if !LWIP_CHECKSUM_ON_COPY chklen);#else /* !LWIP_CHECKSUM_ON_COPY */ (have_chksum ? UDP_HLEN : chklen)); if (have_chksum) { u32_t acc; acc = udphdr->chksum + (u16_t)~(chksum); udphdr->chksum = FOLD_U32T(acc); }#endif /* !LWIP_CHECKSUM_ON_COPY */ /* chksum zero must become 0xffff, as zero means 'no checksum' */ if (udphdr->chksum == 0x0000) { udphdr->chksum = 0xffff; }#endif /* CHECKSUM_GEN_UDP */ /* output to IP */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));#if LWIP_NETIF_HWADDRHINT netif->addr_hint = &(pcb->addr_hint);#endif /* LWIP_NETIF_HWADDRHINT*/ err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);#if LWIP_NETIF_HWADDRHINT netif->addr_hint = NULL;#endif /* LWIP_NETIF_HWADDRHINT*/ } else#endif /* LWIP_UDPLITE */ { /* UDP */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len)); udphdr->len = htons(q->tot_len); /* calculate checksum */#if CHECKSUM_GEN_UDP if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { u16_t udpchksum;#if LWIP_CHECKSUM_ON_COPY if (have_chksum) { u32_t acc; udpchksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len, UDP_HLEN); acc = udpchksum + (u16_t)~(chksum); udpchksum = FOLD_U32T(acc); } else#endif /* LWIP_CHECKSUM_ON_COPY */ { udpchksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -