aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ipv6_sockglue.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ipv6_sockglue.c')
-rw-r--r--net/ipv6/ipv6_sockglue.c365
1 files changed, 186 insertions, 179 deletions
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index bf2a686aa13d..06de9d0e1f6b 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -16,7 +16,6 @@
16 * 16 *
17 * FIXME: Make the setsockopt code POSIX compliant: That is 17 * FIXME: Make the setsockopt code POSIX compliant: That is
18 * 18 *
19 * o Return -EINVAL for setsockopt of short lengths
20 * o Truncate getsockopt returns 19 * o Truncate getsockopt returns
21 * o Return an optlen of the truncated length if need be 20 * o Return an optlen of the truncated length if need be
22 * 21 *
@@ -33,6 +32,7 @@
33#include <linux/sockios.h> 32#include <linux/sockios.h>
34#include <linux/net.h> 33#include <linux/net.h>
35#include <linux/in6.h> 34#include <linux/in6.h>
35#include <linux/mroute6.h>
36#include <linux/netdevice.h> 36#include <linux/netdevice.h>
37#include <linux/if_arp.h> 37#include <linux/if_arp.h>
38#include <linux/init.h> 38#include <linux/init.h>
@@ -57,118 +57,6 @@
57 57
58DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; 58DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly;
59 59
60static struct inet6_protocol *ipv6_gso_pull_exthdrs(struct sk_buff *skb,
61 int proto)
62{
63 struct inet6_protocol *ops = NULL;
64
65 for (;;) {
66 struct ipv6_opt_hdr *opth;
67 int len;
68
69 if (proto != NEXTHDR_HOP) {
70 ops = rcu_dereference(inet6_protos[proto]);
71
72 if (unlikely(!ops))
73 break;
74
75 if (!(ops->flags & INET6_PROTO_GSO_EXTHDR))
76 break;
77 }
78
79 if (unlikely(!pskb_may_pull(skb, 8)))
80 break;
81
82 opth = (void *)skb->data;
83 len = opth->hdrlen * 8 + 8;
84
85 if (unlikely(!pskb_may_pull(skb, len)))
86 break;
87
88 proto = opth->nexthdr;
89 __skb_pull(skb, len);
90 }
91
92 return ops;
93}
94
95static int ipv6_gso_send_check(struct sk_buff *skb)
96{
97 struct ipv6hdr *ipv6h;
98 struct inet6_protocol *ops;
99 int err = -EINVAL;
100
101 if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
102 goto out;
103
104 ipv6h = ipv6_hdr(skb);
105 __skb_pull(skb, sizeof(*ipv6h));
106 err = -EPROTONOSUPPORT;
107
108 rcu_read_lock();
109 ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
110 if (likely(ops && ops->gso_send_check)) {
111 skb_reset_transport_header(skb);
112 err = ops->gso_send_check(skb);
113 }
114 rcu_read_unlock();
115
116out:
117 return err;
118}
119
120static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
121{
122 struct sk_buff *segs = ERR_PTR(-EINVAL);
123 struct ipv6hdr *ipv6h;
124 struct inet6_protocol *ops;
125
126 if (!(features & NETIF_F_V6_CSUM))
127 features &= ~NETIF_F_SG;
128
129 if (unlikely(skb_shinfo(skb)->gso_type &
130 ~(SKB_GSO_UDP |
131 SKB_GSO_DODGY |
132 SKB_GSO_TCP_ECN |
133 SKB_GSO_TCPV6 |
134 0)))
135 goto out;
136
137 if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
138 goto out;
139
140 ipv6h = ipv6_hdr(skb);
141 __skb_pull(skb, sizeof(*ipv6h));
142 segs = ERR_PTR(-EPROTONOSUPPORT);
143
144 rcu_read_lock();
145 ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
146 if (likely(ops && ops->gso_segment)) {
147 skb_reset_transport_header(skb);
148 segs = ops->gso_segment(skb, features);
149 }
150 rcu_read_unlock();
151
152 if (unlikely(IS_ERR(segs)))
153 goto out;
154
155 for (skb = segs; skb; skb = skb->next) {
156 ipv6h = ipv6_hdr(skb);
157 ipv6h->payload_len = htons(skb->len - skb->mac_len -
158 sizeof(*ipv6h));
159 }
160
161out:
162 return segs;
163}
164
165static struct packet_type ipv6_packet_type = {
166 .type = __constant_htons(ETH_P_IPV6),
167 .func = ipv6_rcv,
168 .gso_send_check = ipv6_gso_send_check,
169 .gso_segment = ipv6_gso_segment,
170};
171
172struct ip6_ra_chain *ip6_ra_chain; 60struct ip6_ra_chain *ip6_ra_chain;
173DEFINE_RWLOCK(ip6_ra_lock); 61DEFINE_RWLOCK(ip6_ra_lock);
174 62
@@ -215,25 +103,59 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *))
215 return 0; 103 return 0;
216} 104}
217 105
106static
107struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
108 struct ipv6_txoptions *opt)
109{
110 if (inet_sk(sk)->is_icsk) {
111 if (opt &&
112 !((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) &&
113 inet_sk(sk)->daddr != LOOPBACK4_IPV6) {
114 struct inet_connection_sock *icsk = inet_csk(sk);
115 icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
116 icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
117 }
118 opt = xchg(&inet6_sk(sk)->opt, opt);
119 } else {
120 write_lock(&sk->sk_dst_lock);
121 opt = xchg(&inet6_sk(sk)->opt, opt);
122 write_unlock(&sk->sk_dst_lock);
123 }
124 sk_dst_reset(sk);
125
126 return opt;
127}
128
218static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, 129static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
219 char __user *optval, int optlen) 130 char __user *optval, int optlen)
220{ 131{
221 struct ipv6_pinfo *np = inet6_sk(sk); 132 struct ipv6_pinfo *np = inet6_sk(sk);
133 struct net *net = sock_net(sk);
222 int val, valbool; 134 int val, valbool;
223 int retv = -ENOPROTOOPT; 135 int retv = -ENOPROTOOPT;
224 136
225 if (optval == NULL) 137 if (optval == NULL)
226 val=0; 138 val=0;
227 else if (get_user(val, (int __user *) optval)) 139 else {
228 return -EFAULT; 140 if (optlen >= sizeof(int)) {
141 if (get_user(val, (int __user *) optval))
142 return -EFAULT;
143 } else
144 val = 0;
145 }
229 146
230 valbool = (val!=0); 147 valbool = (val!=0);
231 148
149 if (ip6_mroute_opt(optname))
150 return ip6_mroute_setsockopt(sk, optname, optval, optlen);
151
232 lock_sock(sk); 152 lock_sock(sk);
233 153
234 switch (optname) { 154 switch (optname) {
235 155
236 case IPV6_ADDRFORM: 156 case IPV6_ADDRFORM:
157 if (optlen < sizeof(int))
158 goto e_inval;
237 if (val == PF_INET) { 159 if (val == PF_INET) {
238 struct ipv6_txoptions *opt; 160 struct ipv6_txoptions *opt;
239 struct sk_buff *pktopt; 161 struct sk_buff *pktopt;
@@ -266,10 +188,9 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
266 188
267 if (sk->sk_protocol == IPPROTO_TCP) { 189 if (sk->sk_protocol == IPPROTO_TCP) {
268 struct inet_connection_sock *icsk = inet_csk(sk); 190 struct inet_connection_sock *icsk = inet_csk(sk);
269
270 local_bh_disable(); 191 local_bh_disable();
271 sock_prot_inuse_add(sk->sk_prot, -1); 192 sock_prot_inuse_add(net, sk->sk_prot, -1);
272 sock_prot_inuse_add(&tcp_prot, 1); 193 sock_prot_inuse_add(net, &tcp_prot, 1);
273 local_bh_enable(); 194 local_bh_enable();
274 sk->sk_prot = &tcp_prot; 195 sk->sk_prot = &tcp_prot;
275 icsk->icsk_af_ops = &ipv4_specific; 196 icsk->icsk_af_ops = &ipv4_specific;
@@ -282,8 +203,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
282 if (sk->sk_protocol == IPPROTO_UDPLITE) 203 if (sk->sk_protocol == IPPROTO_UDPLITE)
283 prot = &udplite_prot; 204 prot = &udplite_prot;
284 local_bh_disable(); 205 local_bh_disable();
285 sock_prot_inuse_add(sk->sk_prot, -1); 206 sock_prot_inuse_add(net, sk->sk_prot, -1);
286 sock_prot_inuse_add(prot, 1); 207 sock_prot_inuse_add(net, prot, 1);
287 local_bh_enable(); 208 local_bh_enable();
288 sk->sk_prot = prot; 209 sk->sk_prot = prot;
289 sk->sk_socket->ops = &inet_dgram_ops; 210 sk->sk_socket->ops = &inet_dgram_ops;
@@ -309,63 +230,86 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
309 goto e_inval; 230 goto e_inval;
310 231
311 case IPV6_V6ONLY: 232 case IPV6_V6ONLY:
312 if (inet_sk(sk)->num) 233 if (optlen < sizeof(int) ||
234 inet_sk(sk)->num)
313 goto e_inval; 235 goto e_inval;
314 np->ipv6only = valbool; 236 np->ipv6only = valbool;
315 retv = 0; 237 retv = 0;
316 break; 238 break;
317 239
318 case IPV6_RECVPKTINFO: 240 case IPV6_RECVPKTINFO:
241 if (optlen < sizeof(int))
242 goto e_inval;
319 np->rxopt.bits.rxinfo = valbool; 243 np->rxopt.bits.rxinfo = valbool;
320 retv = 0; 244 retv = 0;
321 break; 245 break;
322 246
323 case IPV6_2292PKTINFO: 247 case IPV6_2292PKTINFO:
248 if (optlen < sizeof(int))
249 goto e_inval;
324 np->rxopt.bits.rxoinfo = valbool; 250 np->rxopt.bits.rxoinfo = valbool;
325 retv = 0; 251 retv = 0;
326 break; 252 break;
327 253
328 case IPV6_RECVHOPLIMIT: 254 case IPV6_RECVHOPLIMIT:
255 if (optlen < sizeof(int))
256 goto e_inval;
329 np->rxopt.bits.rxhlim = valbool; 257 np->rxopt.bits.rxhlim = valbool;
330 retv = 0; 258 retv = 0;
331 break; 259 break;
332 260
333 case IPV6_2292HOPLIMIT: 261 case IPV6_2292HOPLIMIT:
262 if (optlen < sizeof(int))
263 goto e_inval;
334 np->rxopt.bits.rxohlim = valbool; 264 np->rxopt.bits.rxohlim = valbool;
335 retv = 0; 265 retv = 0;
336 break; 266 break;
337 267
338 case IPV6_RECVRTHDR: 268 case IPV6_RECVRTHDR:
269 if (optlen < sizeof(int))
270 goto e_inval;
339 np->rxopt.bits.srcrt = valbool; 271 np->rxopt.bits.srcrt = valbool;
340 retv = 0; 272 retv = 0;
341 break; 273 break;
342 274
343 case IPV6_2292RTHDR: 275 case IPV6_2292RTHDR:
276 if (optlen < sizeof(int))
277 goto e_inval;
344 np->rxopt.bits.osrcrt = valbool; 278 np->rxopt.bits.osrcrt = valbool;
345 retv = 0; 279 retv = 0;
346 break; 280 break;
347 281
348 case IPV6_RECVHOPOPTS: 282 case IPV6_RECVHOPOPTS:
283 if (optlen < sizeof(int))
284 goto e_inval;
349 np->rxopt.bits.hopopts = valbool; 285 np->rxopt.bits.hopopts = valbool;
350 retv = 0; 286 retv = 0;
351 break; 287 break;
352 288
353 case IPV6_2292HOPOPTS: 289 case IPV6_2292HOPOPTS:
290 if (optlen < sizeof(int))
291 goto e_inval;
354 np->rxopt.bits.ohopopts = valbool; 292 np->rxopt.bits.ohopopts = valbool;
355 retv = 0; 293 retv = 0;
356 break; 294 break;
357 295
358 case IPV6_RECVDSTOPTS: 296 case IPV6_RECVDSTOPTS:
297 if (optlen < sizeof(int))
298 goto e_inval;
359 np->rxopt.bits.dstopts = valbool; 299 np->rxopt.bits.dstopts = valbool;
360 retv = 0; 300 retv = 0;
361 break; 301 break;
362 302
363 case IPV6_2292DSTOPTS: 303 case IPV6_2292DSTOPTS:
304 if (optlen < sizeof(int))
305 goto e_inval;
364 np->rxopt.bits.odstopts = valbool; 306 np->rxopt.bits.odstopts = valbool;
365 retv = 0; 307 retv = 0;
366 break; 308 break;
367 309
368 case IPV6_TCLASS: 310 case IPV6_TCLASS:
311 if (optlen < sizeof(int))
312 goto e_inval;
369 if (val < -1 || val > 0xff) 313 if (val < -1 || val > 0xff)
370 goto e_inval; 314 goto e_inval;
371 np->tclass = val; 315 np->tclass = val;
@@ -373,11 +317,15 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
373 break; 317 break;
374 318
375 case IPV6_RECVTCLASS: 319 case IPV6_RECVTCLASS:
320 if (optlen < sizeof(int))
321 goto e_inval;
376 np->rxopt.bits.rxtclass = valbool; 322 np->rxopt.bits.rxtclass = valbool;
377 retv = 0; 323 retv = 0;
378 break; 324 break;
379 325
380 case IPV6_FLOWINFO: 326 case IPV6_FLOWINFO:
327 if (optlen < sizeof(int))
328 goto e_inval;
381 np->rxopt.bits.rxflow = valbool; 329 np->rxopt.bits.rxflow = valbool;
382 retv = 0; 330 retv = 0;
383 break; 331 break;
@@ -396,9 +344,9 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
396 if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW)) 344 if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW))
397 break; 345 break;
398 346
399 retv = -EINVAL; 347 if (optlen < sizeof(struct ipv6_opt_hdr) ||
400 if (optlen & 0x7 || optlen > 8 * 255) 348 optlen & 0x7 || optlen > 8 * 255)
401 break; 349 goto e_inval;
402 350
403 opt = ipv6_renew_options(sk, np->opt, optname, 351 opt = ipv6_renew_options(sk, np->opt, optname,
404 (struct ipv6_opt_hdr __user *)optval, 352 (struct ipv6_opt_hdr __user *)optval,
@@ -426,25 +374,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
426 } 374 }
427 375
428 retv = 0; 376 retv = 0;
429 if (inet_sk(sk)->is_icsk) { 377 opt = ipv6_update_options(sk, opt);
430 if (opt) {
431 struct inet_connection_sock *icsk = inet_csk(sk);
432 if (!((1 << sk->sk_state) &
433 (TCPF_LISTEN | TCPF_CLOSE))
434 && inet_sk(sk)->daddr != LOOPBACK4_IPV6) {
435 icsk->icsk_ext_hdr_len =
436 opt->opt_flen + opt->opt_nflen;
437 icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
438 }
439 }
440 opt = xchg(&np->opt, opt);
441 sk_dst_reset(sk);
442 } else {
443 write_lock(&sk->sk_dst_lock);
444 opt = xchg(&np->opt, opt);
445 write_unlock(&sk->sk_dst_lock);
446 sk_dst_reset(sk);
447 }
448sticky_done: 378sticky_done:
449 if (opt) 379 if (opt)
450 sock_kfree_s(sk, opt, opt->tot_len); 380 sock_kfree_s(sk, opt, opt->tot_len);
@@ -490,32 +420,15 @@ sticky_done:
490 goto done; 420 goto done;
491update: 421update:
492 retv = 0; 422 retv = 0;
493 if (inet_sk(sk)->is_icsk) { 423 opt = ipv6_update_options(sk, opt);
494 if (opt) {
495 struct inet_connection_sock *icsk = inet_csk(sk);
496 if (!((1 << sk->sk_state) &
497 (TCPF_LISTEN | TCPF_CLOSE))
498 && inet_sk(sk)->daddr != LOOPBACK4_IPV6) {
499 icsk->icsk_ext_hdr_len =
500 opt->opt_flen + opt->opt_nflen;
501 icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
502 }
503 }
504 opt = xchg(&np->opt, opt);
505 sk_dst_reset(sk);
506 } else {
507 write_lock(&sk->sk_dst_lock);
508 opt = xchg(&np->opt, opt);
509 write_unlock(&sk->sk_dst_lock);
510 sk_dst_reset(sk);
511 }
512
513done: 424done:
514 if (opt) 425 if (opt)
515 sock_kfree_s(sk, opt, opt->tot_len); 426 sock_kfree_s(sk, opt, opt->tot_len);
516 break; 427 break;
517 } 428 }
518 case IPV6_UNICAST_HOPS: 429 case IPV6_UNICAST_HOPS:
430 if (optlen < sizeof(int))
431 goto e_inval;
519 if (val > 255 || val < -1) 432 if (val > 255 || val < -1)
520 goto e_inval; 433 goto e_inval;
521 np->hop_limit = val; 434 np->hop_limit = val;
@@ -525,6 +438,8 @@ done:
525 case IPV6_MULTICAST_HOPS: 438 case IPV6_MULTICAST_HOPS:
526 if (sk->sk_type == SOCK_STREAM) 439 if (sk->sk_type == SOCK_STREAM)
527 goto e_inval; 440 goto e_inval;
441 if (optlen < sizeof(int))
442 goto e_inval;
528 if (val > 255 || val < -1) 443 if (val > 255 || val < -1)
529 goto e_inval; 444 goto e_inval;
530 np->mcast_hops = val; 445 np->mcast_hops = val;
@@ -532,6 +447,8 @@ done:
532 break; 447 break;
533 448
534 case IPV6_MULTICAST_LOOP: 449 case IPV6_MULTICAST_LOOP:
450 if (optlen < sizeof(int))
451 goto e_inval;
535 np->mc_loop = valbool; 452 np->mc_loop = valbool;
536 retv = 0; 453 retv = 0;
537 break; 454 break;
@@ -539,12 +456,14 @@ done:
539 case IPV6_MULTICAST_IF: 456 case IPV6_MULTICAST_IF:
540 if (sk->sk_type == SOCK_STREAM) 457 if (sk->sk_type == SOCK_STREAM)
541 goto e_inval; 458 goto e_inval;
459 if (optlen < sizeof(int))
460 goto e_inval;
542 461
543 if (val) { 462 if (val) {
544 if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val) 463 if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val)
545 goto e_inval; 464 goto e_inval;
546 465
547 if (__dev_get_by_index(&init_net, val) == NULL) { 466 if (__dev_get_by_index(net, val) == NULL) {
548 retv = -ENODEV; 467 retv = -ENODEV;
549 break; 468 break;
550 } 469 }
@@ -557,6 +476,9 @@ done:
557 { 476 {
558 struct ipv6_mreq mreq; 477 struct ipv6_mreq mreq;
559 478
479 if (optlen < sizeof(struct ipv6_mreq))
480 goto e_inval;
481
560 retv = -EPROTO; 482 retv = -EPROTO;
561 if (inet_sk(sk)->is_icsk) 483 if (inet_sk(sk)->is_icsk)
562 break; 484 break;
@@ -576,7 +498,7 @@ done:
576 { 498 {
577 struct ipv6_mreq mreq; 499 struct ipv6_mreq mreq;
578 500
579 if (optlen != sizeof(struct ipv6_mreq)) 501 if (optlen < sizeof(struct ipv6_mreq))
580 goto e_inval; 502 goto e_inval;
581 503
582 retv = -EFAULT; 504 retv = -EFAULT;
@@ -595,6 +517,9 @@ done:
595 struct group_req greq; 517 struct group_req greq;
596 struct sockaddr_in6 *psin6; 518 struct sockaddr_in6 *psin6;
597 519
520 if (optlen < sizeof(struct group_req))
521 goto e_inval;
522
598 retv = -EFAULT; 523 retv = -EFAULT;
599 if (copy_from_user(&greq, optval, sizeof(struct group_req))) 524 if (copy_from_user(&greq, optval, sizeof(struct group_req)))
600 break; 525 break;
@@ -619,7 +544,7 @@ done:
619 struct group_source_req greqs; 544 struct group_source_req greqs;
620 int omode, add; 545 int omode, add;
621 546
622 if (optlen != sizeof(struct group_source_req)) 547 if (optlen < sizeof(struct group_source_req))
623 goto e_inval; 548 goto e_inval;
624 if (copy_from_user(&greqs, optval, sizeof(greqs))) { 549 if (copy_from_user(&greqs, optval, sizeof(greqs))) {
625 retv = -EFAULT; 550 retv = -EFAULT;
@@ -693,27 +618,37 @@ done:
693 break; 618 break;
694 } 619 }
695 case IPV6_ROUTER_ALERT: 620 case IPV6_ROUTER_ALERT:
621 if (optlen < sizeof(int))
622 goto e_inval;
696 retv = ip6_ra_control(sk, val, NULL); 623 retv = ip6_ra_control(sk, val, NULL);
697 break; 624 break;
698 case IPV6_MTU_DISCOVER: 625 case IPV6_MTU_DISCOVER:
626 if (optlen < sizeof(int))
627 goto e_inval;
699 if (val<0 || val>3) 628 if (val<0 || val>3)
700 goto e_inval; 629 goto e_inval;
701 np->pmtudisc = val; 630 np->pmtudisc = val;
702 retv = 0; 631 retv = 0;
703 break; 632 break;
704 case IPV6_MTU: 633 case IPV6_MTU:
634 if (optlen < sizeof(int))
635 goto e_inval;
705 if (val && val < IPV6_MIN_MTU) 636 if (val && val < IPV6_MIN_MTU)
706 goto e_inval; 637 goto e_inval;
707 np->frag_size = val; 638 np->frag_size = val;
708 retv = 0; 639 retv = 0;
709 break; 640 break;
710 case IPV6_RECVERR: 641 case IPV6_RECVERR:
642 if (optlen < sizeof(int))
643 goto e_inval;
711 np->recverr = valbool; 644 np->recverr = valbool;
712 if (!val) 645 if (!val)
713 skb_queue_purge(&sk->sk_error_queue); 646 skb_queue_purge(&sk->sk_error_queue);
714 retv = 0; 647 retv = 0;
715 break; 648 break;
716 case IPV6_FLOWINFO_SEND: 649 case IPV6_FLOWINFO_SEND:
650 if (optlen < sizeof(int))
651 goto e_inval;
717 np->sndflow = valbool; 652 np->sndflow = valbool;
718 retv = 0; 653 retv = 0;
719 break; 654 break;
@@ -728,7 +663,70 @@ done:
728 retv = xfrm_user_policy(sk, optname, optval, optlen); 663 retv = xfrm_user_policy(sk, optname, optval, optlen);
729 break; 664 break;
730 665
666 case IPV6_ADDR_PREFERENCES:
667 {
668 unsigned int pref = 0;
669 unsigned int prefmask = ~0;
670
671 if (optlen < sizeof(int))
672 goto e_inval;
673
674 retv = -EINVAL;
675
676 /* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */
677 switch (val & (IPV6_PREFER_SRC_PUBLIC|
678 IPV6_PREFER_SRC_TMP|
679 IPV6_PREFER_SRC_PUBTMP_DEFAULT)) {
680 case IPV6_PREFER_SRC_PUBLIC:
681 pref |= IPV6_PREFER_SRC_PUBLIC;
682 break;
683 case IPV6_PREFER_SRC_TMP:
684 pref |= IPV6_PREFER_SRC_TMP;
685 break;
686 case IPV6_PREFER_SRC_PUBTMP_DEFAULT:
687 break;
688 case 0:
689 goto pref_skip_pubtmp;
690 default:
691 goto e_inval;
692 }
693
694 prefmask &= ~(IPV6_PREFER_SRC_PUBLIC|
695 IPV6_PREFER_SRC_TMP);
696pref_skip_pubtmp:
697
698 /* check HOME/COA conflicts */
699 switch (val & (IPV6_PREFER_SRC_HOME|IPV6_PREFER_SRC_COA)) {
700 case IPV6_PREFER_SRC_HOME:
701 break;
702 case IPV6_PREFER_SRC_COA:
703 pref |= IPV6_PREFER_SRC_COA;
704 case 0:
705 goto pref_skip_coa;
706 default:
707 goto e_inval;
708 }
709
710 prefmask &= ~IPV6_PREFER_SRC_COA;
711pref_skip_coa:
712
713 /* check CGA/NONCGA conflicts */
714 switch (val & (IPV6_PREFER_SRC_CGA|IPV6_PREFER_SRC_NONCGA)) {
715 case IPV6_PREFER_SRC_CGA:
716 case IPV6_PREFER_SRC_NONCGA:
717 case 0:
718 break;
719 default:
720 goto e_inval;
721 }
722
723 np->srcprefs = (np->srcprefs & prefmask) | pref;
724 retv = 0;
725
726 break;
727 }
731 } 728 }
729
732 release_sock(sk); 730 release_sock(sk);
733 731
734 return retv; 732 return retv;
@@ -839,6 +837,9 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
839 int len; 837 int len;
840 int val; 838 int val;
841 839
840 if (ip6_mroute_opt(optname))
841 return ip6_mroute_getsockopt(sk, optname, optval, optlen);
842
842 if (get_user(len, optlen)) 843 if (get_user(len, optlen))
843 return -EFAULT; 844 return -EFAULT;
844 switch (optname) { 845 switch (optname) {
@@ -1015,9 +1016,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
1015 dst = sk_dst_get(sk); 1016 dst = sk_dst_get(sk);
1016 if (dst) { 1017 if (dst) {
1017 if (val < 0) 1018 if (val < 0)
1018 val = dst_metric(dst, RTAX_HOPLIMIT); 1019 val = ip6_dst_hoplimit(dst);
1019 if (val < 0)
1020 val = ipv6_get_hoplimit(dst->dev);
1021 dst_release(dst); 1020 dst_release(dst);
1022 } 1021 }
1023 if (val < 0) 1022 if (val < 0)
@@ -1045,6 +1044,24 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
1045 val = np->sndflow; 1044 val = np->sndflow;
1046 break; 1045 break;
1047 1046
1047 case IPV6_ADDR_PREFERENCES:
1048 val = 0;
1049
1050 if (np->srcprefs & IPV6_PREFER_SRC_TMP)
1051 val |= IPV6_PREFER_SRC_TMP;
1052 else if (np->srcprefs & IPV6_PREFER_SRC_PUBLIC)
1053 val |= IPV6_PREFER_SRC_PUBLIC;
1054 else {
1055 /* XXX: should we return system default? */
1056 val |= IPV6_PREFER_SRC_PUBTMP_DEFAULT;
1057 }
1058
1059 if (np->srcprefs & IPV6_PREFER_SRC_COA)
1060 val |= IPV6_PREFER_SRC_COA;
1061 else
1062 val |= IPV6_PREFER_SRC_HOME;
1063 break;
1064
1048 default: 1065 default:
1049 return -ENOPROTOOPT; 1066 return -ENOPROTOOPT;
1050 } 1067 }
@@ -1128,13 +1145,3 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
1128EXPORT_SYMBOL(compat_ipv6_getsockopt); 1145EXPORT_SYMBOL(compat_ipv6_getsockopt);
1129#endif 1146#endif
1130 1147
1131int __init ipv6_packet_init(void)
1132{
1133 dev_add_pack(&ipv6_packet_type);
1134 return 0;
1135}
1136
1137void ipv6_packet_cleanup(void)
1138{
1139 dev_remove_pack(&ipv6_packet_type);
1140}