|
|
@@ -2920,6 +2920,49 @@ lwip_sockopt_to_ipopt(int optname)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+#if LWIP_IPV6 && LWIP_RAW
|
|
|
+static void
|
|
|
+lwip_getsockopt_impl_ipv6_checksum(int s, struct lwip_sock* sock, void* optval)
|
|
|
+{
|
|
|
+ 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)));
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+lwip_setsockopt_impl_ipv6_checksum(int s, struct lwip_sock* sock, const void* optval, socklen_t optlen)
|
|
|
+{
|
|
|
+ /* It should not be possible to disable the checksum generation with ICMPv6
|
|
|
+ * as per RFC 3542 chapter 3.1 */
|
|
|
+ if (sock->conn->pcb.raw->protocol == IPPROTO_ICMPV6) {
|
|
|
+ done_socket(sock);
|
|
|
+ return EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW);
|
|
|
+ if (*(const int*)optval < 0) {
|
|
|
+ sock->conn->pcb.raw->chksum_reqd = 0;
|
|
|
+ }
|
|
|
+ else if (*(const int*)optval & 1) {
|
|
|
+ /* Per RFC3542, odd offsets are not allowed */
|
|
|
+ done_socket(sock);
|
|
|
+ return EINVAL;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ sock->conn->pcb.raw->chksum_reqd = 1;
|
|
|
+ sock->conn->pcb.raw->chksum_offset = (u16_t) * (const int*)optval;
|
|
|
+ }
|
|
|
+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n",
|
|
|
+ s, sock->conn->pcb.raw->chksum_reqd));
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
/** lwip_getsockopt_impl: the actual implementation of getsockopt:
|
|
|
* same argument as lwip_getsockopt, either called directly or through callback
|
|
|
*/
|
|
|
@@ -3169,6 +3212,12 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt
|
|
|
/* Level: IPPROTO_IPV6 */
|
|
|
case IPPROTO_IPV6:
|
|
|
switch (optname) {
|
|
|
+#if LWIP_IPV6 && LWIP_RAW
|
|
|
+ case IPV6_CHECKSUM:
|
|
|
+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_RAW);
|
|
|
+ lwip_getsockopt_impl_ipv6_checksum(s, sock, optval);
|
|
|
+ break;
|
|
|
+#endif /* LWIP_IPV6 && LWIP_RAW */
|
|
|
case IPV6_V6ONLY:
|
|
|
LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
|
|
|
*(int *)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0);
|
|
|
@@ -3219,13 +3268,7 @@ lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *opt
|
|
|
#if LWIP_IPV6 && LWIP_RAW
|
|
|
case IPV6_CHECKSUM:
|
|
|
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_RAW);
|
|
|
- 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)) );
|
|
|
+ lwip_getsockopt_impl_ipv6_checksum(s, sock, optval);
|
|
|
break;
|
|
|
#endif /* LWIP_IPV6 && LWIP_RAW */
|
|
|
default:
|
|
|
@@ -3646,7 +3689,15 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_
|
|
|
/* Level: IPPROTO_IPV6 */
|
|
|
case IPPROTO_IPV6:
|
|
|
switch (optname) {
|
|
|
- case IPV6_V6ONLY:
|
|
|
+#if LWIP_IPV6 && LWIP_RAW
|
|
|
+ case IPV6_CHECKSUM:
|
|
|
+ err = lwip_setsockopt_impl_ipv6_checksum(s, sock, optval, optlen);
|
|
|
+ if (err) {
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+#endif /* LWIP_IPV6 && LWIP_RAW */
|
|
|
+ case IPV6_V6ONLY:
|
|
|
LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
|
|
|
if (*(const int *)optval) {
|
|
|
netconn_set_ipv6only(sock->conn, 1);
|
|
|
@@ -3744,26 +3795,10 @@ lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_
|
|
|
switch (optname) {
|
|
|
#if LWIP_IPV6 && LWIP_RAW
|
|
|
case IPV6_CHECKSUM:
|
|
|
- /* It should not be possible to disable the checksum generation with ICMPv6
|
|
|
- * as per RFC 3542 chapter 3.1 */
|
|
|
- if (sock->conn->pcb.raw->protocol == IPPROTO_ICMPV6) {
|
|
|
- done_socket(sock);
|
|
|
- return EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW);
|
|
|
- if (*(const int *)optval < 0) {
|
|
|
- sock->conn->pcb.raw->chksum_reqd = 0;
|
|
|
- } else if (*(const int *)optval & 1) {
|
|
|
- /* Per RFC3542, odd offsets are not allowed */
|
|
|
- done_socket(sock);
|
|
|
- return EINVAL;
|
|
|
- } else {
|
|
|
- sock->conn->pcb.raw->chksum_reqd = 1;
|
|
|
- sock->conn->pcb.raw->chksum_offset = (u16_t) * (const int *)optval;
|
|
|
+ err = lwip_setsockopt_impl_ipv6_checksum(s, sock, optval, optlen);
|
|
|
+ if (err) {
|
|
|
+ return err;
|
|
|
}
|
|
|
- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n",
|
|
|
- s, sock->conn->pcb.raw->chksum_reqd));
|
|
|
break;
|
|
|
#endif /* LWIP_IPV6 && LWIP_RAW */
|
|
|
default:
|