mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2025-03-10 16:14:31 +00:00
Add RFC3542-style checksum compuation on raw, IPv6 sockets
This patch adds support for RFC3542-style checksum computation on raw, IPv6 sockets via the IPV6_CHECKSUM socket option. This allows the development of application-layer utilities such as ping6 which are unable to compute the raw packet checksum without a prior knowledge of the source address selection.
This commit is contained in:
parent
e2c2afbbe0
commit
d74464e091
@ -1703,6 +1703,22 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
|
||||
} /* switch (optname) */
|
||||
break;
|
||||
#endif /* LWIP_UDP && LWIP_UDPLITE*/
|
||||
/* Level: IPPROTO_RAW */
|
||||
case IPPROTO_RAW:
|
||||
switch (optname) {
|
||||
#if LWIP_IPV6
|
||||
case IPV6_CHECKSUM:
|
||||
if (*optlen < sizeof(int)) {
|
||||
err = EINVAL;
|
||||
break;
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
default:
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n",
|
||||
s, optname));
|
||||
err = ENOPROTOOPT;
|
||||
} /* switch (optname) */
|
||||
break;
|
||||
/* UNDEFINED LEVEL */
|
||||
default:
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
|
||||
@ -1955,6 +1971,24 @@ lwip_getsockopt_internal(void *arg)
|
||||
} /* switch (optname) */
|
||||
break;
|
||||
#endif /* LWIP_UDP */
|
||||
/* Level: IPPROTO_RAW */
|
||||
case IPPROTO_RAW:
|
||||
switch (optname) {
|
||||
#if LWIP_IPV6
|
||||
case IPV6_CHECKSUM:
|
||||
if (sock->conn->pcb.raw->chksum_reqd == 0)
|
||||
*(int *)optval = -1;
|
||||
else
|
||||
*(int *)optval = sock->conn->pcb.raw->chksum_offset;
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n",
|
||||
s, (*(int*)optval)) );
|
||||
break;
|
||||
#endif /* LWIP_IPV6 */
|
||||
default:
|
||||
LWIP_ASSERT("unhandled optname", 0);
|
||||
break;
|
||||
} /* switch (optname) */
|
||||
break;
|
||||
default:
|
||||
LWIP_ASSERT("unhandled level", 0);
|
||||
break;
|
||||
@ -2128,6 +2162,9 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
|
||||
if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP)
|
||||
return 0;
|
||||
|
||||
break;
|
||||
case IPV6_CHECKSUM:
|
||||
err = EINVAL;
|
||||
break;
|
||||
default:
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n",
|
||||
@ -2135,6 +2172,17 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
|
||||
err = ENOPROTOOPT;
|
||||
} /* switch (optname) */
|
||||
break;
|
||||
case IPPROTO_ICMPV6:
|
||||
switch (optname) {
|
||||
case IPV6_CHECKSUM:
|
||||
err = EINVAL;
|
||||
break;
|
||||
default:
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_ICMPV6, UNIMPL: optname=0x%x, ..)\n",
|
||||
s, optname));
|
||||
err = ENOPROTOOPT;
|
||||
} /* switch (optname) */
|
||||
break;
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#if LWIP_UDP && LWIP_UDPLITE
|
||||
@ -2161,6 +2209,22 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt
|
||||
} /* switch (optname) */
|
||||
break;
|
||||
#endif /* LWIP_UDP && LWIP_UDPLITE */
|
||||
/* Level: IPPROTO_RAW */
|
||||
case IPPROTO_RAW:
|
||||
switch (optname) {
|
||||
#if LWIP_IPV6
|
||||
case IPV6_CHECKSUM:
|
||||
/* Per RFC3542, odd offsets are not allowed */
|
||||
if ((*(int *)optval > 0) && (*(int *)optval & 1))
|
||||
err = EINVAL;
|
||||
break;
|
||||
#endif /* LWIP_IPV6 */
|
||||
default:
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n",
|
||||
s, optname));
|
||||
err = ENOPROTOOPT;
|
||||
} /* switch (optname) */
|
||||
break;
|
||||
/* UNDEFINED LEVEL */
|
||||
default:
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
|
||||
@ -2419,6 +2483,26 @@ lwip_setsockopt_internal(void *arg)
|
||||
} /* switch (optname) */
|
||||
break;
|
||||
#endif /* LWIP_UDP */
|
||||
/* Level: IPPROTO_RAW */
|
||||
case IPPROTO_RAW:
|
||||
switch (optname) {
|
||||
#if LWIP_IPV6
|
||||
case IPV6_CHECKSUM:
|
||||
if (*(int *)optval < 0) {
|
||||
sock->conn->pcb.raw->chksum_reqd = 0;
|
||||
} else {
|
||||
sock->conn->pcb.raw->chksum_reqd = 1;
|
||||
sock->conn->pcb.raw->chksum_offset = *(int *)optval;
|
||||
}
|
||||
LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n",
|
||||
s, sock->conn->pcb.raw->chksum_reqd));
|
||||
break;
|
||||
#endif /* LWIP_IPV6 */
|
||||
default:
|
||||
LWIP_ASSERT("unhandled optname", 0);
|
||||
break;
|
||||
} /* switch (optname) */
|
||||
break;
|
||||
default:
|
||||
LWIP_ASSERT("unhandled level", 0);
|
||||
break;
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "arch/perf.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@ -313,6 +314,16 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
|
||||
src_ip = &pcb->local_ip;
|
||||
}
|
||||
|
||||
#if LWIP_IPV6
|
||||
/* If requested, based on the IPV6_CHECKSUM socket option per RFC3542, */
|
||||
/* compute the checksum and update the checksum in the payload. */
|
||||
if (PCB_ISIPV6(pcb) && pcb->chksum_reqd) {
|
||||
u16_t chksum;
|
||||
chksum = ip6_chksum_pseudo(q, pcb->protocol, q->tot_len, ipX_2_ip6(src_ip), ipX_2_ip6(dst_ip));
|
||||
*(u16_t *)(((u8_t *)q->payload) + pcb->chksum_offset) = chksum;
|
||||
}
|
||||
#endif
|
||||
|
||||
NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
|
||||
err = ipX_output_if(PCB_ISIPV6(pcb), q, ipX_2_ip(src_ip), ipX_2_ip(dst_ip), pcb->ttl, pcb->tos, pcb->protocol, netif);
|
||||
NETIF_SET_HWADDRHINT(netif, NULL);
|
||||
|
@ -97,6 +97,11 @@ struct raw_pcb {
|
||||
} recv;
|
||||
/* user-supplied argument for the recv callback */
|
||||
void *recv_arg;
|
||||
#if LWIP_IPV6
|
||||
/* fields for handling checksum computations as per RFC3542. */
|
||||
u8_t chksum_reqd;
|
||||
u16_t chksum_offset;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* The following functions is the application layer interface to the
|
||||
|
@ -230,6 +230,7 @@ struct linger {
|
||||
/*
|
||||
* Options for level IPPROTO_IPV6
|
||||
*/
|
||||
#define IPV6_CHECKSUM 7 /* RFC3542: calculate and insert the ICMPv6 checksum for raw sockets. */
|
||||
#define IPV6_V6ONLY 27 /* RFC3493: boolean control to restrict AF_INET6 sockets to IPv6 communications only. */
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user