diff --git a/CHANGELOG b/CHANGELOG index e2f3b686..2221c25c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -499,6 +499,10 @@ HISTORY ++ Bug fixes: + 2007-11-27 Simon Goldschmidt + * udp.h, udp.c, dhcp.c: Implemented new function udp_sendto_if which takes the + netif to send as an argument (to be able to send on netifs that are down). + 2007-11-26 Simon Goldschmidt * tcp_in.c: Fixed bug #21582: pcb->acked accounting can be wrong when ACKs arrive out-of-order diff --git a/src/core/dhcp.c b/src/core/dhcp.c index 1c61208c..f9fb8e1f 100644 --- a/src/core/dhcp.c +++ b/src/core/dhcp.c @@ -269,10 +269,8 @@ dhcp_select(struct netif *netif) /* TODO: we really should bind to a specific local interface here but we cannot specify an unconfigured netif as it is addressless */ - udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); /* send broadcast to any DHCP server */ - udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); - udp_send(dhcp->pcb, dhcp->p_out); + udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); /* reconnect to any (or to server here?!) */ udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); dhcp_delete_request(netif); @@ -589,6 +587,11 @@ dhcp_start(struct netif *netif) netif->dhcp = dhcp = NULL; return ERR_MEM; } + /* set up local and remote port for the pcb */ + udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); + udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); + /* set up the recv callback and argument */ + udp_recv(dhcp->pcb, dhcp_recv, netif); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n")); /* (re)start the DHCP negotiation */ result = dhcp_discover(netif); @@ -613,7 +616,7 @@ dhcp_start(struct netif *netif) void dhcp_inform(struct netif *netif) { - struct dhcp *dhcp; + struct dhcp *dhcp, *old_dhcp = netif->dhcp; err_t result = ERR_OK; dhcp = mem_malloc(sizeof(struct dhcp)); if (dhcp == NULL) { @@ -649,7 +652,7 @@ dhcp_inform(struct netif *netif) udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n")); - udp_send(dhcp->pcb, dhcp->p_out); + udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); dhcp_delete_request(netif); } else { @@ -662,7 +665,7 @@ dhcp_inform(struct netif *netif) } dhcp->pcb = NULL; mem_free((void *)dhcp); - netif->dhcp = NULL; + netif->dhcp = old_dhcp; } } @@ -723,11 +726,10 @@ dhcp_decline(struct netif *netif) /* resize pbuf to reflect true size of options */ pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); /* @todo: should we really connect here? we are performing sendto() */ udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); /* per section 4.4.4, broadcast DECLINE messages */ - udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); + udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); dhcp_delete_request(netif); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n")); } else { @@ -776,12 +778,9 @@ dhcp_discover(struct netif *netif) LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: realloc()ing\n")); pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - /* set receive callback function with netif as user data */ - udp_recv(dhcp->pcb, dhcp_recv, netif); - udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n")); - udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); + udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n")); dhcp_delete_request(netif); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n")); @@ -924,9 +923,8 @@ dhcp_renew(struct netif *netif) pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT); - udp_send(dhcp->pcb, dhcp->p_out); + udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif); dhcp_delete_request(netif); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n")); @@ -977,11 +975,9 @@ dhcp_rebind(struct netif *netif) pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - /* set remote IP association to any DHCP server */ - udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); - udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); /* broadcast to server */ - udp_sendto(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); + udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); + udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); dhcp_delete_request(netif); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n")); } else { @@ -1026,9 +1022,8 @@ dhcp_release(struct netif *netif) pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT); - udp_send(dhcp->pcb, dhcp->p_out); + udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif); dhcp_delete_request(netif); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n")); } else { diff --git a/src/core/udp.c b/src/core/udp.c index 454834fa..c7995213 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -273,45 +273,6 @@ end: PERF_STOP("udp_input"); } -/** - * 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_t -udp_sendto(struct udp_pcb *pcb, struct pbuf *p, - struct ip_addr *dst_ip, u16_t dst_port) -{ - err_t err; - /* temporary space for current PCB remote address */ - struct ip_addr pcb_remote_ip; - u16_t pcb_remote_port; - /* remember current remote peer address of PCB */ - pcb_remote_ip.addr = pcb->remote_ip.addr; - pcb_remote_port = pcb->remote_port; - /* copy packet destination address to PCB remote peer address */ - pcb->remote_ip.addr = dst_ip->addr; - pcb->remote_port = dst_port; - /* send to the packet destination address */ - err = udp_send(pcb, p); - /* restore PCB remote peer address */ - pcb->remote_ip.addr = pcb_remote_ip.addr; - pcb->remote_port = pcb_remote_port; - return err; -} - /** * Send data using UDP. * @@ -333,14 +294,79 @@ udp_sendto(struct udp_pcb *pcb, struct pbuf *p, err_t udp_send(struct udp_pcb *pcb, struct pbuf *p) { - struct udp_hdr *udphdr; + /* send to the packet using remote ip and port stored in the pcb */ + return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port); +} + +/** + * 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_t +udp_sendto(struct udp_pcb *pcb, struct pbuf *p, + struct ip_addr *dst_ip, u16_t dst_port) +{ struct netif *netif; + + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("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 | 1, ("udp_send: No route to 0x%"X32_F"\n", dst_ip->addr)); + UDP_STATS_INC(udp.rterr); + return ERR_RTE; + } + return udp_sendto_if(pcb, p, dst_ip, dst_port, netif); +} + +/** + * 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_t +udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, + struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif) +{ + struct udp_hdr *udphdr; struct ip_addr *src_ip; err_t err; struct pbuf *q; /* q will be sent down the stack */ - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("udp_send\n")); - /* 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 | 2, ("udp_send: not yet bound to a port, binding now\n")); @@ -351,20 +377,6 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p) } } - /* find the outgoing network interface for this packet */ -#if LWIP_IGMP - netif = ip_route((ip_addr_ismulticast(&(pcb->remote_ip)))?(&(pcb->multicast_ip)):(&(pcb->remote_ip))); -#else - netif = ip_route(&(pcb->remote_ip)); -#endif /* LWIP_IGMP */ - - /* no outgoing network interface could be found? */ - if (netif == NULL) { - LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_send: No route to 0x%"X32_F"\n", pcb->remote_ip.addr)); - UDP_STATS_INC(udp.rterr); - return ERR_RTE; - } - /* 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 seperate new pbuf */ @@ -390,7 +402,7 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p) /* q now represents the packet to be sent */ udphdr = q->payload; udphdr->src = htons(pcb->local_port); - udphdr->dest = htons(pcb->remote_port); + udphdr->dest = htons(dst_port); /* in UDP, 0 checksum means 'no checksum' */ udphdr->chksum = 0x0000; @@ -440,7 +452,7 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p) udphdr->len = htons(chklen_hdr); /* calculate checksum */ #if CHECKSUM_GEN_UDP - udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, &(pcb->remote_ip), + udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDPLITE, q->tot_len, chklen); /* chksum zero must become 0xffff, as zero means 'no checksum' */ if (udphdr->chksum == 0x0000) @@ -451,7 +463,7 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p) #if LWIP_NETIF_HWADDRHINT netif->addr_hint = &(pcb->addr_hint); #endif /* LWIP_NETIF_HWADDRHINT*/ - err = ip_output_if(q, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif); + 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*/ @@ -463,7 +475,7 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p) /* calculate checksum */ #if CHECKSUM_GEN_UDP if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { - udphdr->chksum = inet_chksum_pseudo(q, src_ip, &pcb->remote_ip, IP_PROTO_UDP, q->tot_len); + udphdr->chksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len); /* chksum zero must become 0xffff, as zero means 'no checksum' */ if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff; } @@ -474,7 +486,7 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p) #if LWIP_NETIF_HWADDRHINT netif->addr_hint = &(pcb->addr_hint); #endif /* LWIP_NETIF_HWADDRHINT*/ - err = ip_output_if(q, src_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif); + err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif); #if LWIP_NETIF_HWADDRHINT netif->addr_hint = NULL; #endif /* LWIP_NETIF_HWADDRHINT*/ diff --git a/src/include/lwip/udp.h b/src/include/lwip/udp.h index 9955638b..d7b2a382 100644 --- a/src/include/lwip/udp.h +++ b/src/include/lwip/udp.h @@ -123,6 +123,7 @@ void udp_recv (struct udp_pcb *pcb, struct ip_addr *addr, u16_t port), void *recv_arg); +err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif); err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port); err_t udp_send (struct udp_pcb *pcb, struct pbuf *p);