From 046a2701567e3f198ea5ec78cd0f02191a35340a Mon Sep 17 00:00:00 2001 From: goldsimon Date: Mon, 11 Jun 2007 18:43:16 +0000 Subject: [PATCH] Added UDP lite support for sockets --- CHANGELOG | 3 ++ src/api/sockets.c | 103 ++++++++++++++++++++++++++++++++++++- src/core/udp.c | 4 +- src/include/lwip/sockets.h | 10 ++++ src/include/lwip/udp.h | 2 +- 5 files changed, 117 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index cec634a1..45c8ee3d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,9 @@ HISTORY ++ New features: + 2007-06-11 Simon Goldschmidt + * sockets.c, sockets.h: Added UDP lite support for sockets + 2007-06-10 Simon Goldschmidt * udp.h, opt.h, api_msg.c, ip.c, udp.c: Included switch LWIP_UDPLITE (enabled by default) to switch off UDP-Lite support if not needed (reduces udp.c code diff --git a/src/api/sockets.c b/src/api/sockets.c index 7dcf4884..568dfd3d 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -610,7 +610,8 @@ lwip_socket(int domain, int type, int protocol) domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); break; case SOCK_DGRAM: - conn = netconn_new_with_callback(NETCONN_UDP, event_callback); + conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ? + NETCONN_UDPLITE : NETCONN_UDP, event_callback); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); break; @@ -1057,6 +1058,7 @@ int lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optl } /* switch (optname) */ break; +#if LWIP_TCP /* Level: IPPROTO_TCP */ case IPPROTO_TCP: if (*optlen < sizeof(int)) { @@ -1082,9 +1084,33 @@ int lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optl LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; - } /* switch (optname */ + } /* switch (optname) */ break; +#endif /* LWIP_TCP */ +#if LWIP_UDP && LWIP_UDPLITE +/* Level: IPPROTO_UDPLITE */ + case IPPROTO_UDPLITE: + if (*optlen < sizeof(int)) { + err = EINVAL; + break; + } + + /* If this is no UDP lite socket, ignore any options. */ + if (sock->conn->type != NETCONN_UDPLITE) + return 0; + switch (optname) { + case UDPLITE_SEND_CSCOV: + case UDPLITE_RECV_CSCOV: + break; + + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + } /* switch (optname) */ + break; +#endif /* LWIP_UDP && LWIP_UDPLITE*/ /* UNDEFINED LEVEL */ default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", @@ -1208,6 +1234,7 @@ static void lwip_getsockopt_internal(void *arg) } /* switch (optname) */ break; +#if LWIP_TCP /* Level: IPPROTO_TCP */ case IPPROTO_TCP: switch (optname) { @@ -1242,6 +1269,24 @@ static void lwip_getsockopt_internal(void *arg) } /* switch (optname) */ break; +#endif /* LWIP_TCP */ +#if LWIP_UDP && LWIP_UDPLITE + /* Level: IPPROTO_UDPLITE */ + case IPPROTO_UDPLITE: + switch (optname) { + case UDPLITE_SEND_CSCOV: + *(int*)optval = sock->conn->pcb.udp->chksum_len_tx; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n", + s, (*(int*)optval)) ); + break; + case UDPLITE_RECV_CSCOV: + *(int*)optval = sock->conn->pcb.udp->chksum_len_rx; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n", + s, (*(int*)optval)) ); + break; + } /* switch (optname) */ + break; +#endif /* LWIP_UDP */ } /* switch (level) */ sys_mbox_post(sock->conn->mbox, NULL); } @@ -1332,6 +1377,7 @@ int lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t } /* switch (optname) */ break; +#if LWIP_TCP /* Level: IPPROTO_TCP */ case IPPROTO_TCP: if (optlen < sizeof(int)) { @@ -1359,7 +1405,31 @@ int lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t err = ENOPROTOOPT; } /* switch (optname) */ break; +#endif /* LWIP_TCP */ +#if LWIP_UDP && LWIP_UDPLITE +/* Level: IPPROTO_UDPLITE */ + case IPPROTO_UDPLITE: + if (optlen < sizeof(int)) { + err = EINVAL; + break; + } + /* If this is no UDP lite socket, ignore any options. */ + if (sock->conn->type != NETCONN_UDPLITE) + return 0; + + switch (optname) { + case UDPLITE_SEND_CSCOV: + case UDPLITE_RECV_CSCOV: + break; + + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", + s, optname)); + err = ENOPROTOOPT; + } /* switch (optname) */ + break; +#endif /* LWIP_UDP && LWIP_UDPLITE */ /* UNDEFINED LEVEL */ default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", @@ -1481,6 +1551,7 @@ static void lwip_setsockopt_internal(void *arg) } /* switch (optname) */ break; +#if LWIP_TCP /* Level: IPPROTO_TCP */ case IPPROTO_TCP: switch (optname) { @@ -1519,6 +1590,34 @@ static void lwip_setsockopt_internal(void *arg) } /* switch (optname) */ break; +#endif /* LWIP_TCP*/ +#if LWIP_UDP && LWIP_UDPLITE + /* Level: IPPROTO_UDPLITE */ + case IPPROTO_UDPLITE: + switch (optname) { + case UDPLITE_SEND_CSCOV: + if ((*(int*)optval != 0) && (*(int*)optval < 8)) { + /* don't allow illegal values! */ + sock->conn->pcb.udp->chksum_len_tx = 8; + } else { + sock->conn->pcb.udp->chksum_len_tx = *(int*)optval; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %lu\n", + s, (*(int*)optval)) ); + break; + case UDPLITE_RECV_CSCOV: + if ((*(int*)optval != 0) && (*(int*)optval < 8)) { + /* don't allow illegal values! */ + sock->conn->pcb.udp->chksum_len_rx = 8; + } else { + sock->conn->pcb.udp->chksum_len_rx = *(int*)optval; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %lu\n", + s, (*(int*)optval)) ); + break; + } /* switch (optname) */ + break; +#endif /* LWIP_UDP */ } /* switch (level) */ sys_mbox_post(sock->conn->mbox, NULL); } diff --git a/src/core/udp.c b/src/core/udp.c index 26ace444..6229fc8a 100644 --- a/src/core/udp.c +++ b/src/core/udp.c @@ -414,7 +414,7 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p) u16_t chklen; 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; + chklen = pcb->chksum_len_tx; if (chklen < sizeof(struct udp_hdr)) { if (chklen != 0) { LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen)); @@ -431,7 +431,7 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p) /* calculate checksum */ #if CHECKSUM_GEN_UDP udphdr->chksum = inet_chksum_pseudo(q, src_ip, &(pcb->remote_ip), - IP_PROTO_UDP, pcb->chksum_len); + IP_PROTO_UDP, chklen); /* chksum zero must become 0xffff, as zero means 'no checksum' */ if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff; diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index b0523561..92a4e0e1 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -118,6 +118,7 @@ struct linger { #define IPPROTO_IP 0 #define IPPROTO_TCP 6 #define IPPROTO_UDP 17 +#define IPPROTO_UDPLITE 136 #define INADDR_ANY 0 #define INADDR_BROADCAST 0xffffffff @@ -143,6 +144,15 @@ struct linger { #define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ #endif /* LWIP_TCP */ +#if LWIP_UDP && LWIP_UDPLITE +/* + * Options for level IPPROTO_UDPLITE + */ +#define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */ +#define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */ +#endif + + #if LWIP_IGMP /* * Options and types for UDP multicast traffic handling diff --git a/src/include/lwip/udp.h b/src/include/lwip/udp.h index 43e773ae..5b7cd5d5 100644 --- a/src/include/lwip/udp.h +++ b/src/include/lwip/udp.h @@ -70,7 +70,7 @@ struct udp_pcb { #if LWIP_UDPLITE /* used for UDP_LITE only */ - u16_t chksum_len; + u16_t chksum_len_rx, chksum_len_tx; #endif /* LWIP_UDPLITE */ /* addr and port are in same byte order as in the pcb */