Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'icmp6-support-rfc-4884'

Willem de Bruijn says:

====================
icmp6: support rfc 4884

Extend the feature merged earlier this week for IPv4 to IPv6.

I expected this to be a single patch, but patch 1 seemed better to be
stand-alone

patch 1: small fix in length calculation
patch 2: factor out ipv4-specific
patch 3: add ipv6

changes v1->v2: add missing static keyword in patch 3
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+53 -21
+2 -1
include/linux/icmp.h
··· 37 37 } 38 38 39 39 void ip_icmp_error_rfc4884(const struct sk_buff *skb, 40 - struct sock_ee_data_rfc4884 *out); 40 + struct sock_ee_data_rfc4884 *out, 41 + int thlen, int off); 41 42 42 43 #endif /* _LINUX_ICMP_H */
+1
include/linux/ipv6.h
··· 283 283 autoflowlabel:1, 284 284 autoflowlabel_set:1, 285 285 mc_all:1, 286 + recverr_rfc4884:1, 286 287 rtalert_isolate:1; 287 288 __u8 min_hopcount; 288 289 __u8 tclass;
+1
include/uapi/linux/icmpv6.h
··· 68 68 #define icmp6_mtu icmp6_dataun.un_data32[0] 69 69 #define icmp6_unused icmp6_dataun.un_data32[0] 70 70 #define icmp6_maxdelay icmp6_dataun.un_data16[0] 71 + #define icmp6_datagram_len icmp6_dataun.un_data8[0] 71 72 #define icmp6_router icmp6_dataun.u_nd_advt.router 72 73 #define icmp6_solicited icmp6_dataun.u_nd_advt.solicited 73 74 #define icmp6_override icmp6_dataun.u_nd_advt.override
+1
include/uapi/linux/in6.h
··· 179 179 #define IPV6_LEAVE_ANYCAST 28 180 180 #define IPV6_MULTICAST_ALL 29 181 181 #define IPV6_ROUTER_ALERT_ISOLATE 30 182 + #define IPV6_RECVERR_RFC4884 31 182 183 183 184 /* IPV6_MTU_DISCOVER values */ 184 185 #define IPV6_PMTUDISC_DONT 0
+7 -19
net/ipv4/icmp.c
··· 1151 1151 } 1152 1152 1153 1153 void ip_icmp_error_rfc4884(const struct sk_buff *skb, 1154 - struct sock_ee_data_rfc4884 *out) 1154 + struct sock_ee_data_rfc4884 *out, 1155 + int thlen, int off) 1155 1156 { 1156 - int hlen, off; 1157 + int hlen; 1157 1158 1158 - switch (icmp_hdr(skb)->type) { 1159 - case ICMP_DEST_UNREACH: 1160 - case ICMP_TIME_EXCEEDED: 1161 - case ICMP_PARAMETERPROB: 1162 - break; 1163 - default: 1164 - return; 1165 - } 1166 - 1167 - /* outer headers up to inner iph. skb->data is at inner payload */ 1168 - hlen = -skb_transport_offset(skb) - sizeof(struct icmphdr); 1169 - 1170 - /* per rfc 791: maximum packet length of 576 bytes */ 1171 - if (hlen + skb->len > 576) 1172 - return; 1159 + /* original datagram headers: end of icmph to payload (skb->data) */ 1160 + hlen = -skb_transport_offset(skb) - thlen; 1173 1161 1174 1162 /* per rfc 4884: minimal datagram length of 128 bytes */ 1175 - off = icmp_hdr(skb)->un.reserved[1] * sizeof(u32); 1176 - if (off < 128) 1163 + if (off < 128 || off < hlen) 1177 1164 return; 1178 1165 1179 1166 /* kernel has stripped headers: return payload offset in bytes */ ··· 1173 1186 if (!ip_icmp_error_rfc4884_validate(skb, off)) 1174 1187 out->flags |= SO_EE_RFC4884_FLAG_INVALID; 1175 1188 } 1189 + EXPORT_SYMBOL_GPL(ip_icmp_error_rfc4884); 1176 1190 1177 1191 int icmp_err(struct sk_buff *skb, u32 info) 1178 1192 {
+13 -1
net/ipv4/ip_sockglue.c
··· 390 390 return 0; 391 391 } 392 392 393 + static void ipv4_icmp_error_rfc4884(const struct sk_buff *skb, 394 + struct sock_ee_data_rfc4884 *out) 395 + { 396 + switch (icmp_hdr(skb)->type) { 397 + case ICMP_DEST_UNREACH: 398 + case ICMP_TIME_EXCEEDED: 399 + case ICMP_PARAMETERPROB: 400 + ip_icmp_error_rfc4884(skb, out, sizeof(struct icmphdr), 401 + icmp_hdr(skb)->un.reserved[1] * 4); 402 + } 403 + } 404 + 393 405 void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err, 394 406 __be16 port, u32 info, u8 *payload) 395 407 { ··· 425 413 426 414 if (skb_pull(skb, payload - skb->data)) { 427 415 if (inet_sk(sk)->recverr_rfc4884) 428 - ip_icmp_error_rfc4884(skb, &serr->ee.ee_rfc4884); 416 + ipv4_icmp_error_rfc4884(skb, &serr->ee.ee_rfc4884); 429 417 430 418 skb_reset_transport_header(skb); 431 419 if (sock_queue_err_skb(sk, skb) == 0)
+16
net/ipv6/datagram.c
··· 19 19 #include <linux/route.h> 20 20 #include <linux/slab.h> 21 21 #include <linux/export.h> 22 + #include <linux/icmp.h> 22 23 23 24 #include <net/ipv6.h> 24 25 #include <net/ndisc.h> ··· 285 284 } 286 285 EXPORT_SYMBOL_GPL(ip6_datagram_connect_v6_only); 287 286 287 + static void ipv6_icmp_error_rfc4884(const struct sk_buff *skb, 288 + struct sock_ee_data_rfc4884 *out) 289 + { 290 + switch (icmp6_hdr(skb)->icmp6_type) { 291 + case ICMPV6_TIME_EXCEED: 292 + case ICMPV6_DEST_UNREACH: 293 + ip_icmp_error_rfc4884(skb, out, sizeof(struct icmp6hdr), 294 + icmp6_hdr(skb)->icmp6_datagram_len * 8); 295 + } 296 + } 297 + 288 298 void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, 289 299 __be16 port, u32 info, u8 *payload) 290 300 { ··· 325 313 serr->port = port; 326 314 327 315 __skb_pull(skb, payload - skb->data); 316 + 317 + if (inet6_sk(sk)->recverr_rfc4884) 318 + ipv6_icmp_error_rfc4884(skb, &serr->ee.ee_rfc4884); 319 + 328 320 skb_reset_transport_header(skb); 329 321 330 322 if (sock_queue_err_skb(sk, skb))
+12
net/ipv6/ipv6_sockglue.c
··· 965 965 np->rxopt.bits.recvfragsize = valbool; 966 966 retv = 0; 967 967 break; 968 + case IPV6_RECVERR_RFC4884: 969 + if (optlen < sizeof(int)) 970 + goto e_inval; 971 + if (val < 0 || val > 1) 972 + goto e_inval; 973 + np->recverr_rfc4884 = valbool; 974 + retv = 0; 975 + break; 968 976 } 969 977 970 978 release_sock(sk); ··· 1445 1437 1446 1438 case IPV6_ROUTER_ALERT_ISOLATE: 1447 1439 val = np->rtalert_isolate; 1440 + break; 1441 + 1442 + case IPV6_RECVERR_RFC4884: 1443 + val = np->recverr_rfc4884; 1448 1444 break; 1449 1445 1450 1446 default: