mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-12-28 09:19:53 +00:00
Fixed UDPLite SENDING: Checksum was always generated too short and also was generated wrong if checksum coverage != tot_len.
This commit is contained in:
parent
911ee4d9f9
commit
2ca113a218
@ -424,6 +424,10 @@ HISTORY
|
||||
|
||||
++ Bug fixes:
|
||||
|
||||
2007-10-07 Simon Goldschmidt
|
||||
* udp.c, inet.c, inet.h: Fixed UDPLite SENDING: Checksum was always generated
|
||||
too short and also was generated wrong if checksum coverage != tot_len.
|
||||
|
||||
2007-10-07 Frédéric Bernon
|
||||
* sockets.c, api.h, api_lib.c: First step to fix "bug #20900 : Potential
|
||||
crash error problem with netconn_peer & netconn_addr". VERY IMPORTANT:
|
||||
|
@ -294,6 +294,69 @@ inet_chksum_pseudo(struct pbuf *p,
|
||||
return (u16_t)~(acc & 0xffffUL);
|
||||
}
|
||||
|
||||
/* inet_chksum_pseudo:
|
||||
*
|
||||
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
|
||||
* IP addresses are expected to be in network byte order.
|
||||
*
|
||||
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
|
||||
* @param src source ip address (used for checksum of pseudo header)
|
||||
* @param dst destination ip address (used for checksum of pseudo header)
|
||||
* @param proto ip protocol (used for checksum of pseudo header)
|
||||
* @param proto_len length of the ip data part (used for checksum of pseudo header)
|
||||
* @return checksum (as u16_t) to be saved directly in the protocol header
|
||||
*/
|
||||
u16_t
|
||||
inet_chksum_pseudo_partial(struct pbuf *p,
|
||||
struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t proto, u16_t proto_len, u16_t chksum_len)
|
||||
{
|
||||
u32_t acc;
|
||||
struct pbuf *q;
|
||||
u8_t swapped;
|
||||
u16_t chklen;
|
||||
|
||||
acc = 0;
|
||||
swapped = 0;
|
||||
/* iterate through all pbuf in chain */
|
||||
for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) {
|
||||
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
|
||||
(void *)q, (void *)q->next));
|
||||
chklen = q->len;
|
||||
if (chklen > chksum_len) {
|
||||
chklen = chksum_len;
|
||||
}
|
||||
acc += LWIP_CHKSUM(q->payload, chklen);
|
||||
chksum_len -= chklen;
|
||||
LWIP_ASSERT("delete me", chksum_len < 0x7fff);
|
||||
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
||||
while ((acc >> 16) != 0) {
|
||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
||||
}
|
||||
if (q->len % 2 != 0) {
|
||||
swapped = 1 - swapped;
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
|
||||
}
|
||||
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
||||
}
|
||||
|
||||
if (swapped) {
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
|
||||
}
|
||||
acc += (src->addr & 0xffffUL);
|
||||
acc += ((src->addr >> 16) & 0xffffUL);
|
||||
acc += (dest->addr & 0xffffUL);
|
||||
acc += ((dest->addr >> 16) & 0xffffUL);
|
||||
acc += (u32_t)htons((u16_t)proto);
|
||||
acc += (u32_t)htons(proto_len);
|
||||
|
||||
while ((acc >> 16) != 0) {
|
||||
acc = (acc & 0xffffUL) + (acc >> 16);
|
||||
}
|
||||
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
|
||||
return (u16_t)~(acc & 0xffffUL);
|
||||
}
|
||||
|
||||
/* inet_chksum:
|
||||
*
|
||||
* Calculates the Internet checksum over a portion of memory. Used primarily for IP
|
||||
|
@ -39,10 +39,13 @@
|
||||
|
||||
/* udp.c
|
||||
*
|
||||
* The code for the User Datagram Protocol UDP.
|
||||
* The code for the User Datagram Protocol UDP & UDPLite (RFC 3828).
|
||||
*
|
||||
*/
|
||||
|
||||
/* @todo Check the use of '(struct udp_pcb).chksum_len_rx'!
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */
|
||||
@ -425,11 +428,11 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p)
|
||||
#if LWIP_UDPLITE
|
||||
/* UDP Lite protocol? */
|
||||
if (pcb->flags & UDP_FLAGS_UDPLITE) {
|
||||
u16_t chklen;
|
||||
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 = pcb->chksum_len_rx;
|
||||
if (chklen < sizeof(struct udp_hdr)) {
|
||||
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));
|
||||
}
|
||||
@ -439,13 +442,14 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p)
|
||||
checksum, therefore, if chksum_len has an illegal
|
||||
value, we generate the checksum over the complete
|
||||
packet to be safe. */
|
||||
chklen = p->tot_len;
|
||||
chklen_hdr = 0;
|
||||
chklen = q->tot_len;
|
||||
}
|
||||
udphdr->len = htons(chklen);
|
||||
udphdr->len = htons(chklen_hdr);
|
||||
/* calculate checksum */
|
||||
#if CHECKSUM_GEN_UDP
|
||||
udphdr->chksum = inet_chksum_pseudo(q, src_ip, &(pcb->remote_ip),
|
||||
IP_PROTO_UDP, chklen);
|
||||
udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, &(pcb->remote_ip),
|
||||
IP_PROTO_UDPLITE, q->tot_len, chklen);
|
||||
/* chksum zero must become 0xffff, as zero means 'no checksum' */
|
||||
if (udphdr->chksum == 0x0000)
|
||||
udphdr->chksum = 0xffff;
|
||||
|
@ -49,6 +49,9 @@ u16_t inet_chksum_pbuf(struct pbuf *p);
|
||||
u16_t inet_chksum_pseudo(struct pbuf *p,
|
||||
struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t proto, u16_t proto_len);
|
||||
u16_t inet_chksum_pseudo_partial(struct pbuf *p,
|
||||
struct ip_addr *src, struct ip_addr *dest,
|
||||
u8_t proto, u16_t proto_len, u16_t chksum_len);
|
||||
|
||||
u32_t inet_addr(const char *cp);
|
||||
int inet_aton(const char *cp, struct in_addr *addr);
|
||||
|
Loading…
Reference in New Issue
Block a user