Blame view
net/ipv6/ipv6_sockglue.c
30 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 |
/* * IPv6 BSD socket options interface |
1ab1457c4 [NET] IPV6: Fix w... |
3 |
* Linux INET6 implementation |
1da177e4c Linux-2.6.12-rc2 |
4 5 |
* * Authors: |
1ab1457c4 [NET] IPV6: Fix w... |
6 |
* Pedro Roque <roque@di.fc.ul.pt> |
1da177e4c Linux-2.6.12-rc2 |
7 8 9 |
* * Based on linux/net/ipv4/ip_sockglue.c * |
1da177e4c Linux-2.6.12-rc2 |
10 11 12 13 14 15 16 |
* This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * FIXME: Make the setsockopt code POSIX compliant: That is * |
1da177e4c Linux-2.6.12-rc2 |
17 18 19 20 21 22 23 24 25 |
* o Truncate getsockopt returns * o Return an optlen of the truncated length if need be * * Changes: * David L Stevens <dlstevens@us.ibm.com>: * - added multicast source filtering API for MLDv2 */ #include <linux/module.h> |
4fc268d24 [PATCH] capable/c... |
26 |
#include <linux/capability.h> |
1da177e4c Linux-2.6.12-rc2 |
27 28 29 30 |
#include <linux/errno.h> #include <linux/types.h> #include <linux/socket.h> #include <linux/sockios.h> |
1da177e4c Linux-2.6.12-rc2 |
31 32 |
#include <linux/net.h> #include <linux/in6.h> |
7bc570c8b [IPV6] MROUTE: Su... |
33 |
#include <linux/mroute6.h> |
1da177e4c Linux-2.6.12-rc2 |
34 35 36 37 38 |
#include <linux/netdevice.h> #include <linux/if_arp.h> #include <linux/init.h> #include <linux/sysctl.h> #include <linux/netfilter.h> |
5a0e3ad6a include cleanup: ... |
39 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
40 41 42 43 44 45 46 47 48 49 50 51 |
#include <net/sock.h> #include <net/snmp.h> #include <net/ipv6.h> #include <net/ndisc.h> #include <net/protocol.h> #include <net/transp_v6.h> #include <net/ip6_route.h> #include <net/addrconf.h> #include <net/inet_common.h> #include <net/tcp.h> #include <net/udp.h> |
ba4e58eca [NET]: Supporting... |
52 |
#include <net/udplite.h> |
1da177e4c Linux-2.6.12-rc2 |
53 |
#include <net/xfrm.h> |
dae502954 ipv4/ipv6 compat:... |
54 |
#include <net/compat.h> |
a149e7c7c ipv6: sr: add sup... |
55 |
#include <net/seg6.h> |
1da177e4c Linux-2.6.12-rc2 |
56 |
|
7c0f6ba68 Replace <asm/uacc... |
57 |
#include <linux/uaccess.h> |
1da177e4c Linux-2.6.12-rc2 |
58 |
|
1da177e4c Linux-2.6.12-rc2 |
59 60 |
struct ip6_ra_chain *ip6_ra_chain; DEFINE_RWLOCK(ip6_ra_lock); |
725a8ff04 ipv6: remove unus... |
61 |
int ip6_ra_control(struct sock *sk, int sel) |
1da177e4c Linux-2.6.12-rc2 |
62 63 64 65 |
{ struct ip6_ra_chain *ra, *new_ra, **rap; /* RA packet may be delivered ONLY to IPPROTO_RAW socket */ |
c720c7e83 inet: rename some... |
66 |
if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num != IPPROTO_RAW) |
1717699cd ipv6: Fail with a... |
67 |
return -ENOPROTOOPT; |
1da177e4c Linux-2.6.12-rc2 |
68 |
|
67ba4152e ipv6: White-space... |
69 |
new_ra = (sel >= 0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; |
1da177e4c Linux-2.6.12-rc2 |
70 71 |
write_lock_bh(&ip6_ra_lock); |
67ba4152e ipv6: White-space... |
72 |
for (rap = &ip6_ra_chain; (ra = *rap) != NULL; rap = &ra->next) { |
1da177e4c Linux-2.6.12-rc2 |
73 |
if (ra->sk == sk) { |
67ba4152e ipv6: White-space... |
74 |
if (sel >= 0) { |
1da177e4c Linux-2.6.12-rc2 |
75 |
write_unlock_bh(&ip6_ra_lock); |
a51482bde [NET]: kfree cleanup |
76 |
kfree(new_ra); |
1da177e4c Linux-2.6.12-rc2 |
77 78 79 80 81 |
return -EADDRINUSE; } *rap = ra->next; write_unlock_bh(&ip6_ra_lock); |
1da177e4c Linux-2.6.12-rc2 |
82 83 84 85 86 |
sock_put(sk); kfree(ra); return 0; } } |
63159f29b ipv6: coding styl... |
87 |
if (!new_ra) { |
1da177e4c Linux-2.6.12-rc2 |
88 89 90 91 92 |
write_unlock_bh(&ip6_ra_lock); return -ENOBUFS; } new_ra->sk = sk; new_ra->sel = sel; |
1da177e4c Linux-2.6.12-rc2 |
93 94 95 96 97 98 |
new_ra->next = ra; *rap = new_ra; sock_hold(sk); write_unlock_bh(&ip6_ra_lock); return 0; } |
e7712f1a7 [IPV6]: Share com... |
99 100 101 102 103 104 |
struct ipv6_txoptions *ipv6_update_options(struct sock *sk, struct ipv6_txoptions *opt) { if (inet_sk(sk)->is_icsk) { if (opt && !((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) && |
c720c7e83 inet: rename some... |
105 |
inet_sk(sk)->inet_daddr != LOOPBACK4_IPV6) { |
e7712f1a7 [IPV6]: Share com... |
106 107 108 109 |
struct inet_connection_sock *icsk = inet_csk(sk); icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen; icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie); } |
e7712f1a7 [IPV6]: Share com... |
110 |
} |
45f6fad84 ipv6: add complet... |
111 112 |
opt = xchg((__force struct ipv6_txoptions **)&inet6_sk(sk)->opt, opt); |
e7712f1a7 [IPV6]: Share com... |
113 114 115 116 |
sk_dst_reset(sk); return opt; } |
baf606d9c ipv4,ipv6: grab r... |
117 118 119 |
static bool setsockopt_needs_rtnl(int optname) { switch (optname) { |
8651be8f1 ipv6: fix a poten... |
120 |
case IPV6_ADDRFORM: |
baf606d9c ipv4,ipv6: grab r... |
121 122 |
case IPV6_ADD_MEMBERSHIP: case IPV6_DROP_MEMBERSHIP: |
c4a6853d8 ipv6: invert join... |
123 124 |
case IPV6_JOIN_ANYCAST: case IPV6_LEAVE_ANYCAST: |
baf606d9c ipv4,ipv6: grab r... |
125 126 |
case MCAST_JOIN_GROUP: case MCAST_LEAVE_GROUP: |
54ff9ef36 ipv4, ipv6: kill ... |
127 128 129 130 131 |
case MCAST_JOIN_SOURCE_GROUP: case MCAST_LEAVE_SOURCE_GROUP: case MCAST_BLOCK_SOURCE: case MCAST_UNBLOCK_SOURCE: case MCAST_MSFILTER: |
baf606d9c ipv4,ipv6: grab r... |
132 133 134 135 |
return true; } return false; } |
3fdadf7d2 [NET]: {get|set}s... |
136 |
static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, |
b7058842c net: Make setsock... |
137 |
char __user *optval, unsigned int optlen) |
1da177e4c Linux-2.6.12-rc2 |
138 139 |
{ struct ipv6_pinfo *np = inet6_sk(sk); |
3b1e0a655 [NET] NETNS: Omit... |
140 |
struct net *net = sock_net(sk); |
1da177e4c Linux-2.6.12-rc2 |
141 142 |
int val, valbool; int retv = -ENOPROTOOPT; |
baf606d9c ipv4,ipv6: grab r... |
143 |
bool needs_rtnl = setsockopt_needs_rtnl(optname); |
1da177e4c Linux-2.6.12-rc2 |
144 |
|
63159f29b ipv6: coding styl... |
145 |
if (!optval) |
67ba4152e ipv6: White-space... |
146 |
val = 0; |
b2a9d7c2f [IPV6]: Check len... |
147 148 149 150 151 152 153 |
else { if (optlen >= sizeof(int)) { if (get_user(val, (int __user *) optval)) return -EFAULT; } else val = 0; } |
1da177e4c Linux-2.6.12-rc2 |
154 |
|
67ba4152e ipv6: White-space... |
155 |
valbool = (val != 0); |
1da177e4c Linux-2.6.12-rc2 |
156 |
|
7bc570c8b [IPV6] MROUTE: Su... |
157 158 |
if (ip6_mroute_opt(optname)) return ip6_mroute_setsockopt(sk, optname, optval, optlen); |
baf606d9c ipv4,ipv6: grab r... |
159 160 |
if (needs_rtnl) rtnl_lock(); |
1da177e4c Linux-2.6.12-rc2 |
161 162 163 164 165 |
lock_sock(sk); switch (optname) { case IPV6_ADDRFORM: |
b2a9d7c2f [IPV6]: Check len... |
166 167 |
if (optlen < sizeof(int)) goto e_inval; |
1da177e4c Linux-2.6.12-rc2 |
168 169 170 |
if (val == PF_INET) { struct ipv6_txoptions *opt; struct sk_buff *pktopt; |
49d074f40 [IPV6]: Do not ch... |
171 172 |
if (sk->sk_type == SOCK_RAW) break; |
9596cc826 [IPV6]: Do not ch... |
173 174 175 176 177 178 179 180 |
if (sk->sk_protocol == IPPROTO_UDP || sk->sk_protocol == IPPROTO_UDPLITE) { struct udp_sock *up = udp_sk(sk); if (up->pending == AF_INET6) { retv = -EBUSY; break; } } else if (sk->sk_protocol != IPPROTO_TCP) |
1da177e4c Linux-2.6.12-rc2 |
181 182 183 184 185 186 187 188 |
break; if (sk->sk_state != TCP_ESTABLISHED) { retv = -ENOTCONN; break; } if (ipv6_only_sock(sk) || |
efe4208f4 ipv6: make lookup... |
189 |
!ipv6_addr_v4mapped(&sk->sk_v6_daddr)) { |
1da177e4c Linux-2.6.12-rc2 |
190 191 192 193 194 |
retv = -EADDRNOTAVAIL; break; } fl6_free_socklist(sk); |
8651be8f1 ipv6: fix a poten... |
195 |
__ipv6_sock_mc_close(sk); |
1da177e4c Linux-2.6.12-rc2 |
196 |
|
e6848976b [NET]: Cleanup IN... |
197 198 199 200 201 202 |
/* * Sock is moving from IPv6 to IPv4 (sk_prot), so * remove it from the refcnt debug socks count in the * original family... */ sk_refcnt_debug_dec(sk); |
1da177e4c Linux-2.6.12-rc2 |
203 |
if (sk->sk_protocol == IPPROTO_TCP) { |
d83d8461f [IP_SOCKGLUE]: Re... |
204 |
struct inet_connection_sock *icsk = inet_csk(sk); |
1da177e4c Linux-2.6.12-rc2 |
205 |
local_bh_disable(); |
c29a0bc4d [SOCK][NETNS]: Ad... |
206 207 |
sock_prot_inuse_add(net, sk->sk_prot, -1); sock_prot_inuse_add(net, &tcp_prot, 1); |
1da177e4c Linux-2.6.12-rc2 |
208 209 |
local_bh_enable(); sk->sk_prot = &tcp_prot; |
d83d8461f [IP_SOCKGLUE]: Re... |
210 |
icsk->icsk_af_ops = &ipv4_specific; |
1da177e4c Linux-2.6.12-rc2 |
211 212 |
sk->sk_socket->ops = &inet_stream_ops; sk->sk_family = PF_INET; |
d83d8461f [IP_SOCKGLUE]: Re... |
213 |
tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); |
1da177e4c Linux-2.6.12-rc2 |
214 |
} else { |
ba4e58eca [NET]: Supporting... |
215 |
struct proto *prot = &udp_prot; |
db8dac20d [UDP]: Revert udp... |
216 |
if (sk->sk_protocol == IPPROTO_UDPLITE) |
ba4e58eca [NET]: Supporting... |
217 |
prot = &udplite_prot; |
1da177e4c Linux-2.6.12-rc2 |
218 |
local_bh_disable(); |
c29a0bc4d [SOCK][NETNS]: Ad... |
219 220 |
sock_prot_inuse_add(net, sk->sk_prot, -1); sock_prot_inuse_add(net, prot, 1); |
1da177e4c Linux-2.6.12-rc2 |
221 |
local_bh_enable(); |
ba4e58eca [NET]: Supporting... |
222 |
sk->sk_prot = prot; |
1da177e4c Linux-2.6.12-rc2 |
223 224 225 |
sk->sk_socket->ops = &inet_dgram_ops; sk->sk_family = PF_INET; } |
45f6fad84 ipv6: add complet... |
226 227 228 229 230 231 |
opt = xchg((__force struct ipv6_txoptions **)&np->opt, NULL); if (opt) { atomic_sub(opt->tot_len, &sk->sk_omem_alloc); txopt_put(opt); } |
1da177e4c Linux-2.6.12-rc2 |
232 |
pktopt = xchg(&np->pktoptions, NULL); |
800d55f14 ipv6: Remove some... |
233 |
kfree_skb(pktopt); |
1da177e4c Linux-2.6.12-rc2 |
234 |
|
e6848976b [NET]: Cleanup IN... |
235 236 237 238 239 |
/* * ... and add it to the refcnt debug socks count * in the new family. -acme */ sk_refcnt_debug_inc(sk); |
1da177e4c Linux-2.6.12-rc2 |
240 241 242 243 244 245 246 |
module_put(THIS_MODULE); retv = 0; break; } goto e_inval; case IPV6_V6ONLY: |
b2a9d7c2f [IPV6]: Check len... |
247 |
if (optlen < sizeof(int) || |
c720c7e83 inet: rename some... |
248 |
inet_sk(sk)->inet_num) |
1da177e4c Linux-2.6.12-rc2 |
249 |
goto e_inval; |
9fe516ba3 inet: move ipv6on... |
250 |
sk->sk_ipv6only = valbool; |
1da177e4c Linux-2.6.12-rc2 |
251 252 |
retv = 0; break; |
333fad536 [IPV6]: Support s... |
253 |
case IPV6_RECVPKTINFO: |
b2a9d7c2f [IPV6]: Check len... |
254 255 |
if (optlen < sizeof(int)) goto e_inval; |
1da177e4c Linux-2.6.12-rc2 |
256 257 258 |
np->rxopt.bits.rxinfo = valbool; retv = 0; break; |
1ab1457c4 [NET] IPV6: Fix w... |
259 |
|
333fad536 [IPV6]: Support s... |
260 |
case IPV6_2292PKTINFO: |
b2a9d7c2f [IPV6]: Check len... |
261 262 |
if (optlen < sizeof(int)) goto e_inval; |
333fad536 [IPV6]: Support s... |
263 264 265 |
np->rxopt.bits.rxoinfo = valbool; retv = 0; break; |
1da177e4c Linux-2.6.12-rc2 |
266 |
|
333fad536 [IPV6]: Support s... |
267 |
case IPV6_RECVHOPLIMIT: |
b2a9d7c2f [IPV6]: Check len... |
268 269 |
if (optlen < sizeof(int)) goto e_inval; |
1da177e4c Linux-2.6.12-rc2 |
270 271 272 |
np->rxopt.bits.rxhlim = valbool; retv = 0; break; |
333fad536 [IPV6]: Support s... |
273 |
case IPV6_2292HOPLIMIT: |
b2a9d7c2f [IPV6]: Check len... |
274 275 |
if (optlen < sizeof(int)) goto e_inval; |
333fad536 [IPV6]: Support s... |
276 277 278 279 280 |
np->rxopt.bits.rxohlim = valbool; retv = 0; break; case IPV6_RECVRTHDR: |
b2a9d7c2f [IPV6]: Check len... |
281 282 |
if (optlen < sizeof(int)) goto e_inval; |
4c752098f [IPV6]: Make IPV6... |
283 |
np->rxopt.bits.srcrt = valbool; |
1da177e4c Linux-2.6.12-rc2 |
284 285 |
retv = 0; break; |
333fad536 [IPV6]: Support s... |
286 |
case IPV6_2292RTHDR: |
b2a9d7c2f [IPV6]: Check len... |
287 288 |
if (optlen < sizeof(int)) goto e_inval; |
4c752098f [IPV6]: Make IPV6... |
289 |
np->rxopt.bits.osrcrt = valbool; |
333fad536 [IPV6]: Support s... |
290 291 292 293 |
retv = 0; break; case IPV6_RECVHOPOPTS: |
b2a9d7c2f [IPV6]: Check len... |
294 295 |
if (optlen < sizeof(int)) goto e_inval; |
1da177e4c Linux-2.6.12-rc2 |
296 297 298 |
np->rxopt.bits.hopopts = valbool; retv = 0; break; |
333fad536 [IPV6]: Support s... |
299 |
case IPV6_2292HOPOPTS: |
b2a9d7c2f [IPV6]: Check len... |
300 301 |
if (optlen < sizeof(int)) goto e_inval; |
333fad536 [IPV6]: Support s... |
302 303 304 305 306 |
np->rxopt.bits.ohopopts = valbool; retv = 0; break; case IPV6_RECVDSTOPTS: |
b2a9d7c2f [IPV6]: Check len... |
307 308 |
if (optlen < sizeof(int)) goto e_inval; |
1da177e4c Linux-2.6.12-rc2 |
309 310 311 |
np->rxopt.bits.dstopts = valbool; retv = 0; break; |
333fad536 [IPV6]: Support s... |
312 |
case IPV6_2292DSTOPTS: |
b2a9d7c2f [IPV6]: Check len... |
313 314 |
if (optlen < sizeof(int)) goto e_inval; |
333fad536 [IPV6]: Support s... |
315 316 317 |
np->rxopt.bits.odstopts = valbool; retv = 0; break; |
41a1f8ea4 [IPV6]: Support I... |
318 |
case IPV6_TCLASS: |
b2a9d7c2f [IPV6]: Check len... |
319 320 |
if (optlen < sizeof(int)) goto e_inval; |
d0ee011f7 [IPV6]: Accept -1... |
321 |
if (val < -1 || val > 0xff) |
41a1f8ea4 [IPV6]: Support I... |
322 |
goto e_inval; |
26ced1e4a inet6: Set defaul... |
323 324 325 |
/* RFC 3542, 6.5: default traffic class of 0x0 */ if (val == -1) val = 0; |
41a1f8ea4 [IPV6]: Support I... |
326 327 328 |
np->tclass = val; retv = 0; break; |
1ab1457c4 [NET] IPV6: Fix w... |
329 |
|
41a1f8ea4 [IPV6]: Support I... |
330 |
case IPV6_RECVTCLASS: |
b2a9d7c2f [IPV6]: Check len... |
331 332 |
if (optlen < sizeof(int)) goto e_inval; |
41a1f8ea4 [IPV6]: Support I... |
333 334 335 |
np->rxopt.bits.rxtclass = valbool; retv = 0; break; |
1da177e4c Linux-2.6.12-rc2 |
336 |
case IPV6_FLOWINFO: |
b2a9d7c2f [IPV6]: Check len... |
337 338 |
if (optlen < sizeof(int)) goto e_inval; |
1da177e4c Linux-2.6.12-rc2 |
339 340 341 |
np->rxopt.bits.rxflow = valbool; retv = 0; break; |
793b14731 IPv6: data struct... |
342 343 344 345 346 347 |
case IPV6_RECVPATHMTU: if (optlen < sizeof(int)) goto e_inval; np->rxopt.bits.rxpmtu = valbool; retv = 0; break; |
6c4686228 tproxy: added tpr... |
348 |
case IPV6_TRANSPARENT: |
af31f412c net: Allow userns... |
349 350 |
if (valbool && !ns_capable(net->user_ns, CAP_NET_ADMIN) && !ns_capable(net->user_ns, CAP_NET_RAW)) { |
b889416b5 tproxy: Add missi... |
351 352 353 |
retv = -EPERM; break; } |
6c4686228 tproxy: added tpr... |
354 355 356 357 358 359 360 361 362 363 364 365 366 |
if (optlen < sizeof(int)) goto e_inval; /* we don't have a separate transparent bit for IPV6 we use the one in the IPv4 socket */ inet_sk(sk)->transparent = valbool; retv = 0; break; case IPV6_RECVORIGDSTADDR: if (optlen < sizeof(int)) goto e_inval; np->rxopt.bits.rxorigdstaddr = valbool; retv = 0; break; |
333fad536 [IPV6]: Support s... |
367 368 369 370 371 372 |
case IPV6_HOPOPTS: case IPV6_RTHDRDSTOPTS: case IPV6_RTHDR: case IPV6_DSTOPTS: { struct ipv6_txoptions *opt; |
8e39e96f2 ipv6: make ipv6_r... |
373 374 375 376 377 378 |
struct ipv6_opt_hdr *new = NULL; /* hop-by-hop / destination options are privileged option */ retv = -EPERM; if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW)) break; |
aea7427f7 ipv6: Remove opti... |
379 380 381 382 |
/* remove any sticky options header with a zero option * length, per RFC3542. */ |
333fad536 [IPV6]: Support s... |
383 |
if (optlen == 0) |
cb422c464 [IPV6]: Fixes spa... |
384 |
optval = NULL; |
63159f29b ipv6: coding styl... |
385 |
else if (!optval) |
cfb266c0e ipv6: Fix the ret... |
386 |
goto e_inval; |
aea7427f7 ipv6: Remove opti... |
387 388 389 |
else if (optlen < sizeof(struct ipv6_opt_hdr) || optlen & 0x7 || optlen > 8 * 255) goto e_inval; |
8e39e96f2 ipv6: make ipv6_r... |
390 391 392 393 394 395 396 397 398 399 400 |
else { new = memdup_user(optval, optlen); if (IS_ERR(new)) { retv = PTR_ERR(new); break; } if (unlikely(ipv6_optlen(new) > optlen)) { kfree(new); goto e_inval; } } |
333fad536 [IPV6]: Support s... |
401 |
|
1e1d04e67 net: introduce lo... |
402 403 |
opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk)); |
8e39e96f2 ipv6: make ipv6_r... |
404 405 |
opt = ipv6_renew_options(sk, opt, optname, new); kfree(new); |
333fad536 [IPV6]: Support s... |
406 407 408 409 410 411 |
if (IS_ERR(opt)) { retv = PTR_ERR(opt); break; } /* routing header option needs extra check */ |
6e093d9df ipv6: routing hea... |
412 |
retv = -EINVAL; |
dfee0a725 [IPV6]: Fix for i... |
413 |
if (optname == IPV6_RTHDR && opt && opt->srcrt) { |
333fad536 [IPV6]: Support s... |
414 |
struct ipv6_rt_hdr *rthdr = opt->srcrt; |
280a9d340 [IPV6] MIP6: Add ... |
415 |
switch (rthdr->type) { |
07a936260 ipv6: use IS_ENAB... |
416 |
#if IS_ENABLED(CONFIG_IPV6_MIP6) |
280a9d340 [IPV6] MIP6: Add ... |
417 |
case IPV6_SRCRT_TYPE_2: |
6e093d9df ipv6: routing hea... |
418 419 420 |
if (rthdr->hdrlen != 2 || rthdr->segments_left != 1) goto sticky_done; |
280a9d340 [IPV6] MIP6: Add ... |
421 |
break; |
bb4dbf9e6 [IPV6]: Do not se... |
422 |
#endif |
a149e7c7c ipv6: sr: add sup... |
423 424 425 426 427 428 429 430 431 |
case IPV6_SRCRT_TYPE_4: { struct ipv6_sr_hdr *srh = (struct ipv6_sr_hdr *) opt->srcrt; if (!seg6_validate_srh(srh, optlen)) goto sticky_done; break; } |
280a9d340 [IPV6] MIP6: Add ... |
432 |
default: |
333fad536 [IPV6]: Support s... |
433 |
goto sticky_done; |
280a9d340 [IPV6] MIP6: Add ... |
434 |
} |
333fad536 [IPV6]: Support s... |
435 436 437 |
} retv = 0; |
e7712f1a7 [IPV6]: Share com... |
438 |
opt = ipv6_update_options(sk, opt); |
333fad536 [IPV6]: Support s... |
439 |
sticky_done: |
45f6fad84 ipv6: add complet... |
440 441 442 443 |
if (opt) { atomic_sub(opt->tot_len, &sk->sk_omem_alloc); txopt_put(opt); } |
333fad536 [IPV6]: Support s... |
444 445 |
break; } |
b24a2516d ipv6: Add IPV6_PK... |
446 447 448 449 450 451 |
case IPV6_PKTINFO: { struct in6_pktinfo pkt; if (optlen == 0) goto e_inval; |
63159f29b ipv6: coding styl... |
452 |
else if (optlen < sizeof(struct in6_pktinfo) || !optval) |
b24a2516d ipv6: Add IPV6_PK... |
453 |
goto e_inval; |
914d11647 ipv6: IPV6_PKTINF... |
454 |
if (copy_from_user(&pkt, optval, sizeof(struct in6_pktinfo))) { |
b24a2516d ipv6: Add IPV6_PK... |
455 456 457 458 459 460 461 |
retv = -EFAULT; break; } if (sk->sk_bound_dev_if && pkt.ipi6_ifindex != sk->sk_bound_dev_if) goto e_inval; np->sticky_pktinfo.ipi6_ifindex = pkt.ipi6_ifindex; |
4e3fd7a06 net: remove ipv6_... |
462 |
np->sticky_pktinfo.ipi6_addr = pkt.ipi6_addr; |
b24a2516d ipv6: Add IPV6_PK... |
463 464 465 |
retv = 0; break; } |
333fad536 [IPV6]: Support s... |
466 |
case IPV6_2292PKTOPTIONS: |
1da177e4c Linux-2.6.12-rc2 |
467 468 469 |
{ struct ipv6_txoptions *opt = NULL; struct msghdr msg; |
4c9483b2f ipv6: Convert to ... |
470 |
struct flowi6 fl6; |
ad1e46a83 ipv6: process soc... |
471 |
struct sockcm_cookie sockc_junk; |
26879da58 ipv6: add new str... |
472 |
struct ipcm6_cookie ipc6; |
1da177e4c Linux-2.6.12-rc2 |
473 |
|
4c9483b2f ipv6: Convert to ... |
474 475 476 |
memset(&fl6, 0, sizeof(fl6)); fl6.flowi6_oif = sk->sk_bound_dev_if; fl6.flowi6_mark = sk->sk_mark; |
1da177e4c Linux-2.6.12-rc2 |
477 478 479 480 481 482 483 484 485 486 487 488 489 |
if (optlen == 0) goto update; /* 1K is probably excessive * 1K is surely not enough, 2K per standard header is 16K. */ retv = -EINVAL; if (optlen > 64*1024) break; opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL); retv = -ENOBUFS; |
63159f29b ipv6: coding styl... |
490 |
if (!opt) |
1da177e4c Linux-2.6.12-rc2 |
491 492 493 |
break; memset(opt, 0, sizeof(*opt)); |
0aeea21ad net, ipv6: conver... |
494 |
refcount_set(&opt->refcnt, 1); |
1da177e4c Linux-2.6.12-rc2 |
495 496 497 498 499 500 |
opt->tot_len = sizeof(*opt) + optlen; retv = -EFAULT; if (copy_from_user(opt+1, optval, optlen)) goto done; msg.msg_controllen = optlen; |
67ba4152e ipv6: White-space... |
501 |
msg.msg_control = (void *)(opt+1); |
26879da58 ipv6: add new str... |
502 |
ipc6.opt = opt; |
1da177e4c Linux-2.6.12-rc2 |
503 |
|
26879da58 ipv6: add new str... |
504 |
retv = ip6_datagram_send_ctl(net, sk, &msg, &fl6, &ipc6, &sockc_junk); |
1da177e4c Linux-2.6.12-rc2 |
505 506 507 508 |
if (retv) goto done; update: retv = 0; |
e7712f1a7 [IPV6]: Share com... |
509 |
opt = ipv6_update_options(sk, opt); |
1da177e4c Linux-2.6.12-rc2 |
510 |
done: |
45f6fad84 ipv6: add complet... |
511 512 513 514 |
if (opt) { atomic_sub(opt->tot_len, &sk->sk_omem_alloc); txopt_put(opt); } |
1da177e4c Linux-2.6.12-rc2 |
515 516 517 |
break; } case IPV6_UNICAST_HOPS: |
b2a9d7c2f [IPV6]: Check len... |
518 519 |
if (optlen < sizeof(int)) goto e_inval; |
1da177e4c Linux-2.6.12-rc2 |
520 521 522 523 524 525 526 527 |
if (val > 255 || val < -1) goto e_inval; np->hop_limit = val; retv = 0; break; case IPV6_MULTICAST_HOPS: if (sk->sk_type == SOCK_STREAM) |
1717699cd ipv6: Fail with a... |
528 |
break; |
b2a9d7c2f [IPV6]: Check len... |
529 530 |
if (optlen < sizeof(int)) goto e_inval; |
1da177e4c Linux-2.6.12-rc2 |
531 532 |
if (val > 255 || val < -1) goto e_inval; |
2a38e6d5a ipv6: Set mcast_h... |
533 |
np->mcast_hops = (val == -1 ? IPV6_DEFAULT_MCASTHOPS : val); |
1da177e4c Linux-2.6.12-rc2 |
534 535 536 537 |
retv = 0; break; case IPV6_MULTICAST_LOOP: |
b2a9d7c2f [IPV6]: Check len... |
538 539 |
if (optlen < sizeof(int)) goto e_inval; |
28d448821 ipv6: Check IPV6_... |
540 541 |
if (val != valbool) goto e_inval; |
1da177e4c Linux-2.6.12-rc2 |
542 543 544 |
np->mc_loop = valbool; retv = 0; break; |
c4062dfc4 ipv6: Implement I... |
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 |
case IPV6_UNICAST_IF: { struct net_device *dev = NULL; int ifindex; if (optlen != sizeof(int)) goto e_inval; ifindex = (__force int)ntohl((__force __be32)val); if (ifindex == 0) { np->ucast_oif = 0; retv = 0; break; } dev = dev_get_by_index(net, ifindex); retv = -EADDRNOTAVAIL; if (!dev) break; dev_put(dev); retv = -EINVAL; if (sk->sk_bound_dev_if) break; np->ucast_oif = ifindex; retv = 0; break; } |
1da177e4c Linux-2.6.12-rc2 |
574 575 |
case IPV6_MULTICAST_IF: if (sk->sk_type == SOCK_STREAM) |
1717699cd ipv6: Fail with a... |
576 |
break; |
b2a9d7c2f [IPV6]: Check len... |
577 578 |
if (optlen < sizeof(int)) goto e_inval; |
1da177e4c Linux-2.6.12-rc2 |
579 |
|
4953f0fcc [IPv6]: Update se... |
580 |
if (val) { |
55b805035 net: Fix IP_MULTI... |
581 |
struct net_device *dev; |
7bb387c5a net: Allow IP_MUL... |
582 |
int midx; |
55b805035 net: Fix IP_MULTI... |
583 |
|
7bb387c5a net: Allow IP_MUL... |
584 |
rcu_read_lock(); |
4953f0fcc [IPv6]: Update se... |
585 |
|
7bb387c5a net: Allow IP_MUL... |
586 |
dev = dev_get_by_index_rcu(net, val); |
55b805035 net: Fix IP_MULTI... |
587 |
if (!dev) { |
7bb387c5a net: Allow IP_MUL... |
588 |
rcu_read_unlock(); |
4953f0fcc [IPv6]: Update se... |
589 590 591 |
retv = -ENODEV; break; } |
7bb387c5a net: Allow IP_MUL... |
592 593 594 595 596 597 598 599 |
midx = l3mdev_master_ifindex_rcu(dev); rcu_read_unlock(); if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val && (!midx || midx != sk->sk_bound_dev_if)) goto e_inval; |
1da177e4c Linux-2.6.12-rc2 |
600 601 602 603 604 605 606 607 |
} np->mcast_oif = val; retv = 0; break; case IPV6_ADD_MEMBERSHIP: case IPV6_DROP_MEMBERSHIP: { struct ipv6_mreq mreq; |
a28398ba6 [IPV6]: Check len... |
608 609 |
if (optlen < sizeof(struct ipv6_mreq)) goto e_inval; |
a96fb49be [NET]: Fix IP_ADD... |
610 611 612 |
retv = -EPROTO; if (inet_sk(sk)->is_icsk) break; |
1da177e4c Linux-2.6.12-rc2 |
613 614 615 616 617 |
retv = -EFAULT; if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq))) break; if (optname == IPV6_ADD_MEMBERSHIP) |
54ff9ef36 ipv4, ipv6: kill ... |
618 |
retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr); |
1da177e4c Linux-2.6.12-rc2 |
619 |
else |
54ff9ef36 ipv4, ipv6: kill ... |
620 |
retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr); |
1da177e4c Linux-2.6.12-rc2 |
621 622 623 624 625 626 |
break; } case IPV6_JOIN_ANYCAST: case IPV6_LEAVE_ANYCAST: { struct ipv6_mreq mreq; |
a28398ba6 [IPV6]: Check len... |
627 |
if (optlen < sizeof(struct ipv6_mreq)) |
1da177e4c Linux-2.6.12-rc2 |
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 |
goto e_inval; retv = -EFAULT; if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq))) break; if (optname == IPV6_JOIN_ANYCAST) retv = ipv6_sock_ac_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr); else retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr); break; } case MCAST_JOIN_GROUP: case MCAST_LEAVE_GROUP: { struct group_req greq; struct sockaddr_in6 *psin6; |
a28398ba6 [IPV6]: Check len... |
645 646 |
if (optlen < sizeof(struct group_req)) goto e_inval; |
1da177e4c Linux-2.6.12-rc2 |
647 648 649 650 651 652 653 654 655 |
retv = -EFAULT; if (copy_from_user(&greq, optval, sizeof(struct group_req))) break; if (greq.gr_group.ss_family != AF_INET6) { retv = -EADDRNOTAVAIL; break; } psin6 = (struct sockaddr_in6 *)&greq.gr_group; if (optname == MCAST_JOIN_GROUP) |
54ff9ef36 ipv4, ipv6: kill ... |
656 657 |
retv = ipv6_sock_mc_join(sk, greq.gr_interface, &psin6->sin6_addr); |
1da177e4c Linux-2.6.12-rc2 |
658 |
else |
54ff9ef36 ipv4, ipv6: kill ... |
659 660 |
retv = ipv6_sock_mc_drop(sk, greq.gr_interface, &psin6->sin6_addr); |
1da177e4c Linux-2.6.12-rc2 |
661 662 663 664 665 666 667 668 669 |
break; } case MCAST_JOIN_SOURCE_GROUP: case MCAST_LEAVE_SOURCE_GROUP: case MCAST_BLOCK_SOURCE: case MCAST_UNBLOCK_SOURCE: { struct group_source_req greqs; int omode, add; |
a28398ba6 [IPV6]: Check len... |
670 |
if (optlen < sizeof(struct group_source_req)) |
1da177e4c Linux-2.6.12-rc2 |
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 |
goto e_inval; if (copy_from_user(&greqs, optval, sizeof(greqs))) { retv = -EFAULT; break; } if (greqs.gsr_group.ss_family != AF_INET6 || greqs.gsr_source.ss_family != AF_INET6) { retv = -EADDRNOTAVAIL; break; } if (optname == MCAST_BLOCK_SOURCE) { omode = MCAST_EXCLUDE; add = 1; } else if (optname == MCAST_UNBLOCK_SOURCE) { omode = MCAST_EXCLUDE; add = 0; } else if (optname == MCAST_JOIN_SOURCE_GROUP) { struct sockaddr_in6 *psin6; psin6 = (struct sockaddr_in6 *)&greqs.gsr_group; |
54ff9ef36 ipv4, ipv6: kill ... |
691 692 |
retv = ipv6_sock_mc_join(sk, greqs.gsr_interface, &psin6->sin6_addr); |
c9e3e8b69 [IPV6]: multicast... |
693 694 |
/* prior join w/ different source is ok */ if (retv && retv != -EADDRINUSE) |
1da177e4c Linux-2.6.12-rc2 |
695 696 697 |
break; omode = MCAST_INCLUDE; add = 1; |
c9e3e8b69 [IPV6]: multicast... |
698 |
} else /* MCAST_LEAVE_SOURCE_GROUP */ { |
1da177e4c Linux-2.6.12-rc2 |
699 700 701 702 703 704 705 706 |
omode = MCAST_INCLUDE; add = 0; } retv = ip6_mc_source(add, omode, sk, &greqs); break; } case MCAST_MSFILTER: { |
1da177e4c Linux-2.6.12-rc2 |
707 708 709 710 711 712 713 714 |
struct group_filter *gsf; if (optlen < GROUP_FILTER_SIZE(0)) goto e_inval; if (optlen > sysctl_optmem_max) { retv = -ENOBUFS; break; } |
43727da90 do_ipv6_setsockop... |
715 716 717 |
gsf = memdup_user(optval, optlen); if (IS_ERR(gsf)) { retv = PTR_ERR(gsf); |
1da177e4c Linux-2.6.12-rc2 |
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 |
break; } /* numsrc >= (4G-140)/128 overflow in 32 bits */ if (gsf->gf_numsrc >= 0x1ffffffU || gsf->gf_numsrc > sysctl_mld_max_msf) { kfree(gsf); retv = -ENOBUFS; break; } if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) { kfree(gsf); retv = -EINVAL; break; } retv = ip6_mc_msfilter(sk, gsf); kfree(gsf); break; } case IPV6_ROUTER_ALERT: |
b2a9d7c2f [IPV6]: Check len... |
738 739 |
if (optlen < sizeof(int)) goto e_inval; |
725a8ff04 ipv6: remove unus... |
740 |
retv = ip6_ra_control(sk, val); |
1da177e4c Linux-2.6.12-rc2 |
741 742 |
break; case IPV6_MTU_DISCOVER: |
b2a9d7c2f [IPV6]: Check len... |
743 744 |
if (optlen < sizeof(int)) goto e_inval; |
0b95227a7 ipv6: yet another... |
745 |
if (val < IPV6_PMTUDISC_DONT || val > IPV6_PMTUDISC_OMIT) |
1da177e4c Linux-2.6.12-rc2 |
746 747 748 749 750 |
goto e_inval; np->pmtudisc = val; retv = 0; break; case IPV6_MTU: |
b2a9d7c2f [IPV6]: Check len... |
751 752 |
if (optlen < sizeof(int)) goto e_inval; |
1da177e4c Linux-2.6.12-rc2 |
753 754 755 756 757 758 |
if (val && val < IPV6_MIN_MTU) goto e_inval; np->frag_size = val; retv = 0; break; case IPV6_RECVERR: |
b2a9d7c2f [IPV6]: Check len... |
759 760 |
if (optlen < sizeof(int)) goto e_inval; |
1da177e4c Linux-2.6.12-rc2 |
761 762 763 764 765 766 |
np->recverr = valbool; if (!val) skb_queue_purge(&sk->sk_error_queue); retv = 0; break; case IPV6_FLOWINFO_SEND: |
b2a9d7c2f [IPV6]: Check len... |
767 768 |
if (optlen < sizeof(int)) goto e_inval; |
1da177e4c Linux-2.6.12-rc2 |
769 770 771 772 773 774 775 776 |
np->sndflow = valbool; retv = 0; break; case IPV6_FLOWLABEL_MGR: retv = ipv6_flowlabel_opt(sk, optval, optlen); break; case IPV6_IPSEC_POLICY: case IPV6_XFRM_POLICY: |
6fc0b4a7a [IPSEC]: Restrict... |
777 |
retv = -EPERM; |
af31f412c net: Allow userns... |
778 |
if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
6fc0b4a7a [IPSEC]: Restrict... |
779 |
break; |
1da177e4c Linux-2.6.12-rc2 |
780 781 |
retv = xfrm_user_policy(sk, optname, optval, optlen); break; |
7cbca67c0 [IPV6]: Support S... |
782 783 784 785 |
case IPV6_ADDR_PREFERENCES: { unsigned int pref = 0; unsigned int prefmask = ~0; |
b2a9d7c2f [IPV6]: Check len... |
786 787 |
if (optlen < sizeof(int)) goto e_inval; |
7cbca67c0 [IPV6]: Support S... |
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 |
retv = -EINVAL; /* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */ switch (val & (IPV6_PREFER_SRC_PUBLIC| IPV6_PREFER_SRC_TMP| IPV6_PREFER_SRC_PUBTMP_DEFAULT)) { case IPV6_PREFER_SRC_PUBLIC: pref |= IPV6_PREFER_SRC_PUBLIC; break; case IPV6_PREFER_SRC_TMP: pref |= IPV6_PREFER_SRC_TMP; break; case IPV6_PREFER_SRC_PUBTMP_DEFAULT: break; case 0: goto pref_skip_pubtmp; default: goto e_inval; } prefmask &= ~(IPV6_PREFER_SRC_PUBLIC| IPV6_PREFER_SRC_TMP); pref_skip_pubtmp: /* check HOME/COA conflicts */ switch (val & (IPV6_PREFER_SRC_HOME|IPV6_PREFER_SRC_COA)) { case IPV6_PREFER_SRC_HOME: break; case IPV6_PREFER_SRC_COA: pref |= IPV6_PREFER_SRC_COA; case 0: goto pref_skip_coa; default: goto e_inval; } prefmask &= ~IPV6_PREFER_SRC_COA; pref_skip_coa: /* check CGA/NONCGA conflicts */ switch (val & (IPV6_PREFER_SRC_CGA|IPV6_PREFER_SRC_NONCGA)) { case IPV6_PREFER_SRC_CGA: case IPV6_PREFER_SRC_NONCGA: case 0: break; default: goto e_inval; } np->srcprefs = (np->srcprefs & prefmask) | pref; retv = 0; break; } |
e802af9ca IPv6: Generic TTL... |
842 843 844 845 846 847 |
case IPV6_MINHOPCOUNT: if (optlen < sizeof(int)) goto e_inval; if (val < 0 || val > 255) goto e_inval; np->min_hopcount = val; |
d4596bad2 ipv6: setsockopt(... |
848 |
retv = 0; |
793b14731 IPv6: data struct... |
849 850 851 |
break; case IPV6_DONTFRAG: np->dontfrag = valbool; |
e802af9ca IPv6: Generic TTL... |
852 853 |
retv = 0; break; |
cb1ce2ef3 ipv6: Implement a... |
854 855 |
case IPV6_AUTOFLOWLABEL: np->autoflowlabel = valbool; |
6d0317869 net: reevalulate ... |
856 |
np->autoflowlabel_set = 1; |
cb1ce2ef3 ipv6: Implement a... |
857 858 |
retv = 0; break; |
0cc0aa614 ipv6: add IPV6_RE... |
859 860 861 862 |
case IPV6_RECVFRAGSIZE: np->rxopt.bits.recvfragsize = valbool; retv = 0; break; |
1da177e4c Linux-2.6.12-rc2 |
863 |
} |
7cbca67c0 [IPV6]: Support S... |
864 |
|
1da177e4c Linux-2.6.12-rc2 |
865 |
release_sock(sk); |
baf606d9c ipv4,ipv6: grab r... |
866 867 |
if (needs_rtnl) rtnl_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
868 |
|
1da177e4c Linux-2.6.12-rc2 |
869 870 871 872 |
return retv; e_inval: release_sock(sk); |
baf606d9c ipv4,ipv6: grab r... |
873 874 |
if (needs_rtnl) rtnl_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
875 876 |
return -EINVAL; } |
3fdadf7d2 [NET]: {get|set}s... |
877 |
int ipv6_setsockopt(struct sock *sk, int level, int optname, |
b7058842c net: Make setsock... |
878 |
char __user *optval, unsigned int optlen) |
3fdadf7d2 [NET]: {get|set}s... |
879 880 881 882 883 884 885 886 887 888 889 890 891 |
{ int err; if (level == SOL_IP && sk->sk_type != SOCK_RAW) return udp_prot.setsockopt(sk, level, optname, optval, optlen); if (level != SOL_IPV6) return -ENOPROTOOPT; err = do_ipv6_setsockopt(sk, level, optname, optval, optlen); #ifdef CONFIG_NETFILTER /* we need to exclude all possible ENOPROTOOPTs except default case */ if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY && |
516c855cf netfilter: on soc... |
892 893 |
optname != IPV6_XFRM_POLICY) err = nf_setsockopt(sk, PF_INET6, optname, optval, optlen); |
3fdadf7d2 [NET]: {get|set}s... |
894 895 896 |
#endif return err; } |
7159039a1 [IPV6]: Decentral... |
897 |
EXPORT_SYMBOL(ipv6_setsockopt); |
3fdadf7d2 [NET]: {get|set}s... |
898 899 900 |
#ifdef CONFIG_COMPAT int compat_ipv6_setsockopt(struct sock *sk, int level, int optname, |
b7058842c net: Make setsock... |
901 |
char __user *optval, unsigned int optlen) |
3fdadf7d2 [NET]: {get|set}s... |
902 903 904 905 |
{ int err; if (level == SOL_IP && sk->sk_type != SOCK_RAW) { |
543d9cfee [NET]: Identation... |
906 907 908 909 |
if (udp_prot.compat_setsockopt != NULL) return udp_prot.compat_setsockopt(sk, level, optname, optval, optlen); return udp_prot.setsockopt(sk, level, optname, optval, optlen); |
3fdadf7d2 [NET]: {get|set}s... |
910 911 912 913 |
} if (level != SOL_IPV6) return -ENOPROTOOPT; |
dae502954 ipv4/ipv6 compat:... |
914 915 916 |
if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER) return compat_mc_setsockopt(sk, level, optname, optval, optlen, ipv6_setsockopt); |
3fdadf7d2 [NET]: {get|set}s... |
917 918 919 920 |
err = do_ipv6_setsockopt(sk, level, optname, optval, optlen); #ifdef CONFIG_NETFILTER /* we need to exclude all possible ENOPROTOOPTs except default case */ if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY && |
516c855cf netfilter: on soc... |
921 922 923 |
optname != IPV6_XFRM_POLICY) err = compat_nf_setsockopt(sk, PF_INET6, optname, optval, optlen); |
3fdadf7d2 [NET]: {get|set}s... |
924 925 926 |
#endif return err; } |
543d9cfee [NET]: Identation... |
927 |
EXPORT_SYMBOL(compat_ipv6_setsockopt); |
3fdadf7d2 [NET]: {get|set}s... |
928 |
#endif |
286930797 [IPV6]: Handle np... |
929 |
static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt, |
4c6510a73 [IPV6]: Return co... |
930 |
int optname, char __user *optval, int len) |
333fad536 [IPV6]: Support s... |
931 |
{ |
286930797 [IPV6]: Handle np... |
932 |
struct ipv6_opt_hdr *hdr; |
4c6510a73 [IPV6]: Return co... |
933 934 |
if (!opt) return 0; |
67ba4152e ipv6: White-space... |
935 |
switch (optname) { |
4c6510a73 [IPV6]: Return co... |
936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 |
case IPV6_HOPOPTS: hdr = opt->hopopt; break; case IPV6_RTHDRDSTOPTS: hdr = opt->dst0opt; break; case IPV6_RTHDR: hdr = (struct ipv6_opt_hdr *)opt->srcrt; break; case IPV6_DSTOPTS: hdr = opt->dst1opt; break; default: return -EINVAL; /* should not happen */ } if (!hdr) |
333fad536 [IPV6]: Support s... |
953 |
return 0; |
286930797 [IPV6]: Handle np... |
954 |
|
d2b02ed94 [IPV6] fix ipv6_g... |
955 |
len = min_t(unsigned int, len, ipv6_optlen(hdr)); |
660adc6e6 [IPv6]: Invalid s... |
956 |
if (copy_to_user(optval, hdr, len)) |
333fad536 [IPV6]: Support s... |
957 |
return -EFAULT; |
95b496b66 [IPV6]: Fix the d... |
958 |
return len; |
333fad536 [IPV6]: Support s... |
959 |
} |
3fdadf7d2 [NET]: {get|set}s... |
960 |
static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, |
95c961747 net: cleanup unsi... |
961 |
char __user *optval, int __user *optlen, unsigned int flags) |
1da177e4c Linux-2.6.12-rc2 |
962 963 964 965 |
{ struct ipv6_pinfo *np = inet6_sk(sk); int len; int val; |
7bc570c8b [IPV6] MROUTE: Su... |
966 967 |
if (ip6_mroute_opt(optname)) return ip6_mroute_getsockopt(sk, optname, optval, optlen); |
1da177e4c Linux-2.6.12-rc2 |
968 969 970 971 972 |
if (get_user(len, optlen)) return -EFAULT; switch (optname) { case IPV6_ADDRFORM: if (sk->sk_protocol != IPPROTO_UDP && |
ba4e58eca [NET]: Supporting... |
973 |
sk->sk_protocol != IPPROTO_UDPLITE && |
1da177e4c Linux-2.6.12-rc2 |
974 |
sk->sk_protocol != IPPROTO_TCP) |
1717699cd ipv6: Fail with a... |
975 |
return -ENOPROTOOPT; |
1da177e4c Linux-2.6.12-rc2 |
976 977 978 979 980 981 982 983 984 985 986 987 988 |
if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; val = sk->sk_family; break; case MCAST_MSFILTER: { struct group_filter gsf; int err; if (len < GROUP_FILTER_SIZE(0)) return -EINVAL; if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0))) return -EFAULT; |
20c61fbd8 ipv6 mcast: Check... |
989 990 |
if (gsf.gf_group.ss_family != AF_INET6) return -EADDRNOTAVAIL; |
1da177e4c Linux-2.6.12-rc2 |
991 992 993 994 995 996 |
lock_sock(sk); err = ip6_mc_msfget(sk, &gsf, (struct group_filter __user *)optval, optlen); release_sock(sk); return err; } |
333fad536 [IPV6]: Support s... |
997 |
case IPV6_2292PKTOPTIONS: |
1da177e4c Linux-2.6.12-rc2 |
998 999 1000 1001 1002 1003 1004 1005 1006 |
{ struct msghdr msg; struct sk_buff *skb; if (sk->sk_type != SOCK_STREAM) return -ENOPROTOOPT; msg.msg_control = optval; msg.msg_controllen = len; |
98e77438a ipv6: Fix ipv6_ge... |
1007 |
msg.msg_flags = flags; |
1da177e4c Linux-2.6.12-rc2 |
1008 1009 1010 1011 |
lock_sock(sk); skb = np->pktoptions; if (skb) |
4b261c75a ipv6: make IPV6_R... |
1012 |
ip6_datagram_recv_ctl(sk, &msg, skb); |
1dc7b90f7 ipv6: tcp: fix ra... |
1013 1014 |
release_sock(sk); if (!skb) { |
1da177e4c Linux-2.6.12-rc2 |
1015 1016 |
if (np->rxopt.bits.rxinfo) { struct in6_pktinfo src_info; |
f250dcdac ipv6: fix the ret... |
1017 1018 |
src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : np->sticky_pktinfo.ipi6_ifindex; |
efe4208f4 ipv6: make lookup... |
1019 |
src_info.ipi6_addr = np->mcast_oif ? sk->sk_v6_daddr : np->sticky_pktinfo.ipi6_addr; |
1da177e4c Linux-2.6.12-rc2 |
1020 1021 1022 1023 1024 1025 |
put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info); } if (np->rxopt.bits.rxhlim) { int hlim = np->mcast_hops; put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); } |
4c507d289 net: implement IP... |
1026 |
if (np->rxopt.bits.rxtclass) { |
d76ed22b2 ipv6: move IPV6_T... |
1027 |
int tclass = (int)ip6_tclass(np->rcv_flowinfo); |
4c507d289 net: implement IP... |
1028 1029 |
put_cmsg(&msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); } |
333fad536 [IPV6]: Support s... |
1030 1031 |
if (np->rxopt.bits.rxoinfo) { struct in6_pktinfo src_info; |
f250dcdac ipv6: fix the ret... |
1032 1033 |
src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : np->sticky_pktinfo.ipi6_ifindex; |
efe4208f4 ipv6: make lookup... |
1034 1035 |
src_info.ipi6_addr = np->mcast_oif ? sk->sk_v6_daddr : np->sticky_pktinfo.ipi6_addr; |
333fad536 [IPV6]: Support s... |
1036 1037 1038 1039 1040 1041 |
put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info); } if (np->rxopt.bits.rxohlim) { int hlim = np->mcast_hops; put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim); } |
1397ed35f ipv6: add flowinf... |
1042 |
if (np->rxopt.bits.rxflow) { |
685360536 ipv6: fix incorre... |
1043 |
__be32 flowinfo = np->rcv_flowinfo; |
1397ed35f ipv6: add flowinf... |
1044 1045 |
put_cmsg(&msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo); } |
1da177e4c Linux-2.6.12-rc2 |
1046 1047 1048 1049 1050 1051 1052 |
} len -= msg.msg_controllen; return put_user(len, optlen); } case IPV6_MTU: { struct dst_entry *dst; |
b6c6712a4 net: sk_dst_cache... |
1053 |
|
1ab1457c4 [NET] IPV6: Fix w... |
1054 |
val = 0; |
b6c6712a4 net: sk_dst_cache... |
1055 1056 1057 |
rcu_read_lock(); dst = __sk_dst_get(sk); if (dst) |
1da177e4c Linux-2.6.12-rc2 |
1058 |
val = dst_mtu(dst); |
b6c6712a4 net: sk_dst_cache... |
1059 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
1060 1061 1062 1063 1064 1065 |
if (!val) return -ENOTCONN; break; } case IPV6_V6ONLY: |
9fe516ba3 inet: move ipv6on... |
1066 |
val = sk->sk_ipv6only; |
1da177e4c Linux-2.6.12-rc2 |
1067 |
break; |
333fad536 [IPV6]: Support s... |
1068 |
case IPV6_RECVPKTINFO: |
1da177e4c Linux-2.6.12-rc2 |
1069 1070 |
val = np->rxopt.bits.rxinfo; break; |
333fad536 [IPV6]: Support s... |
1071 1072 1073 1074 1075 |
case IPV6_2292PKTINFO: val = np->rxopt.bits.rxoinfo; break; case IPV6_RECVHOPLIMIT: |
1da177e4c Linux-2.6.12-rc2 |
1076 1077 |
val = np->rxopt.bits.rxhlim; break; |
333fad536 [IPV6]: Support s... |
1078 1079 1080 1081 1082 |
case IPV6_2292HOPLIMIT: val = np->rxopt.bits.rxohlim; break; case IPV6_RECVRTHDR: |
1da177e4c Linux-2.6.12-rc2 |
1083 1084 |
val = np->rxopt.bits.srcrt; break; |
333fad536 [IPV6]: Support s... |
1085 1086 1087 |
case IPV6_2292RTHDR: val = np->rxopt.bits.osrcrt; break; |
1da177e4c Linux-2.6.12-rc2 |
1088 |
case IPV6_HOPOPTS: |
333fad536 [IPV6]: Support s... |
1089 1090 1091 1092 |
case IPV6_RTHDRDSTOPTS: case IPV6_RTHDR: case IPV6_DSTOPTS: { |
45f6fad84 ipv6: add complet... |
1093 |
struct ipv6_txoptions *opt; |
333fad536 [IPV6]: Support s... |
1094 1095 |
lock_sock(sk); |
1e1d04e67 net: introduce lo... |
1096 1097 |
opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk)); |
45f6fad84 ipv6: add complet... |
1098 |
len = ipv6_getsockopt_sticky(sk, opt, optname, optval, len); |
333fad536 [IPV6]: Support s... |
1099 |
release_sock(sk); |
05335c222 [IPV6]: Fix the r... |
1100 1101 1102 |
/* check if ipv6_getsockopt_sticky() returns err code */ if (len < 0) return len; |
333fad536 [IPV6]: Support s... |
1103 1104 1105 1106 |
return put_user(len, optlen); } case IPV6_RECVHOPOPTS: |
1da177e4c Linux-2.6.12-rc2 |
1107 1108 |
val = np->rxopt.bits.hopopts; break; |
333fad536 [IPV6]: Support s... |
1109 1110 1111 1112 1113 |
case IPV6_2292HOPOPTS: val = np->rxopt.bits.ohopopts; break; case IPV6_RECVDSTOPTS: |
1da177e4c Linux-2.6.12-rc2 |
1114 1115 |
val = np->rxopt.bits.dstopts; break; |
333fad536 [IPV6]: Support s... |
1116 1117 1118 |
case IPV6_2292DSTOPTS: val = np->rxopt.bits.odstopts; break; |
41a1f8ea4 [IPV6]: Support I... |
1119 1120 1121 1122 1123 1124 1125 |
case IPV6_TCLASS: val = np->tclass; break; case IPV6_RECVTCLASS: val = np->rxopt.bits.rxtclass; break; |
1da177e4c Linux-2.6.12-rc2 |
1126 1127 1128 |
case IPV6_FLOWINFO: val = np->rxopt.bits.rxflow; break; |
793b14731 IPv6: data struct... |
1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 |
case IPV6_RECVPATHMTU: val = np->rxopt.bits.rxpmtu; break; case IPV6_PATHMTU: { struct dst_entry *dst; struct ip6_mtuinfo mtuinfo; if (len < sizeof(mtuinfo)) return -EINVAL; len = sizeof(mtuinfo); memset(&mtuinfo, 0, sizeof(mtuinfo)); rcu_read_lock(); dst = __sk_dst_get(sk); if (dst) mtuinfo.ip6m_mtu = dst_mtu(dst); rcu_read_unlock(); if (!mtuinfo.ip6m_mtu) return -ENOTCONN; if (put_user(len, optlen)) return -EFAULT; if (copy_to_user(optval, &mtuinfo, len)) return -EFAULT; return 0; |
793b14731 IPv6: data struct... |
1158 |
} |
6c4686228 tproxy: added tpr... |
1159 1160 1161 1162 1163 1164 1165 |
case IPV6_TRANSPARENT: val = inet_sk(sk)->transparent; break; case IPV6_RECVORIGDSTADDR: val = np->rxopt.bits.rxorigdstaddr; break; |
1da177e4c Linux-2.6.12-rc2 |
1166 |
case IPV6_UNICAST_HOPS: |
1da177e4c Linux-2.6.12-rc2 |
1167 |
case IPV6_MULTICAST_HOPS: |
befffe901 [IPV6]: Fix IPV6_... |
1168 1169 1170 1171 1172 1173 1174 |
{ struct dst_entry *dst; if (optname == IPV6_UNICAST_HOPS) val = np->hop_limit; else val = np->mcast_hops; |
b6c6712a4 net: sk_dst_cache... |
1175 1176 1177 1178 |
if (val < 0) { rcu_read_lock(); dst = __sk_dst_get(sk); if (dst) |
6b75d0908 [IPV6]: Optimize ... |
1179 |
val = ip6_dst_hoplimit(dst); |
b6c6712a4 net: sk_dst_cache... |
1180 |
rcu_read_unlock(); |
befffe901 [IPV6]: Fix IPV6_... |
1181 |
} |
b6c6712a4 net: sk_dst_cache... |
1182 |
|
befffe901 [IPV6]: Fix IPV6_... |
1183 |
if (val < 0) |
53b7997fd ipv6 netns: Make ... |
1184 |
val = sock_net(sk)->ipv6.devconf_all->hop_limit; |
1da177e4c Linux-2.6.12-rc2 |
1185 |
break; |
befffe901 [IPV6]: Fix IPV6_... |
1186 |
} |
1da177e4c Linux-2.6.12-rc2 |
1187 1188 1189 1190 1191 1192 1193 1194 |
case IPV6_MULTICAST_LOOP: val = np->mc_loop; break; case IPV6_MULTICAST_IF: val = np->mcast_oif; break; |
c4062dfc4 ipv6: Implement I... |
1195 1196 1197 |
case IPV6_UNICAST_IF: val = (__force int)htonl((__u32) np->ucast_oif); break; |
1da177e4c Linux-2.6.12-rc2 |
1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 |
case IPV6_MTU_DISCOVER: val = np->pmtudisc; break; case IPV6_RECVERR: val = np->recverr; break; case IPV6_FLOWINFO_SEND: val = np->sndflow; break; |
3fdfa5ff5 ipv6: enable IPV6... |
1209 1210 1211 |
case IPV6_FLOWLABEL_MGR: { struct in6_flowlabel_req freq; |
46e5f4017 ipv6: add a flag ... |
1212 |
int flags; |
3fdfa5ff5 ipv6: enable IPV6... |
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 |
if (len < sizeof(freq)) return -EINVAL; if (copy_from_user(&freq, optval, sizeof(freq))) return -EFAULT; if (freq.flr_action != IPV6_FL_A_GET) return -EINVAL; len = sizeof(freq); |
46e5f4017 ipv6: add a flag ... |
1224 |
flags = freq.flr_flags; |
3fdfa5ff5 ipv6: enable IPV6... |
1225 |
memset(&freq, 0, sizeof(freq)); |
46e5f4017 ipv6: add a flag ... |
1226 |
val = ipv6_flowlabel_opt_get(sk, &freq, flags); |
3fdfa5ff5 ipv6: enable IPV6... |
1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 |
if (val < 0) return val; if (put_user(len, optlen)) return -EFAULT; if (copy_to_user(optval, &freq, len)) return -EFAULT; return 0; } |
7cbca67c0 [IPV6]: Support S... |
1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 |
case IPV6_ADDR_PREFERENCES: val = 0; if (np->srcprefs & IPV6_PREFER_SRC_TMP) val |= IPV6_PREFER_SRC_TMP; else if (np->srcprefs & IPV6_PREFER_SRC_PUBLIC) val |= IPV6_PREFER_SRC_PUBLIC; else { /* XXX: should we return system default? */ val |= IPV6_PREFER_SRC_PUBTMP_DEFAULT; } if (np->srcprefs & IPV6_PREFER_SRC_COA) val |= IPV6_PREFER_SRC_COA; else val |= IPV6_PREFER_SRC_HOME; break; |
e802af9ca IPv6: Generic TTL... |
1254 1255 1256 1257 |
case IPV6_MINHOPCOUNT: val = np->min_hopcount; break; |
793b14731 IPv6: data struct... |
1258 1259 1260 1261 |
case IPV6_DONTFRAG: val = np->dontfrag; break; |
7cbca67c0 [IPV6]: Support S... |
1262 |
|
cb1ce2ef3 ipv6: Implement a... |
1263 |
case IPV6_AUTOFLOWLABEL: |
2295b3dd5 ipv6: Fix getsock... |
1264 |
val = ip6_autoflowlabel(sock_net(sk), np); |
cb1ce2ef3 ipv6: Implement a... |
1265 |
break; |
0cc0aa614 ipv6: add IPV6_RE... |
1266 1267 1268 |
case IPV6_RECVFRAGSIZE: val = np->rxopt.bits.recvfragsize; break; |
1da177e4c Linux-2.6.12-rc2 |
1269 |
default: |
cf6fc4a92 [IPV6]: Fix the r... |
1270 |
return -ENOPROTOOPT; |
1da177e4c Linux-2.6.12-rc2 |
1271 1272 |
} len = min_t(unsigned int, sizeof(int), len); |
67ba4152e ipv6: White-space... |
1273 |
if (put_user(len, optlen)) |
1da177e4c Linux-2.6.12-rc2 |
1274 |
return -EFAULT; |
67ba4152e ipv6: White-space... |
1275 |
if (copy_to_user(optval, &val, len)) |
1da177e4c Linux-2.6.12-rc2 |
1276 1277 1278 |
return -EFAULT; return 0; } |
3fdadf7d2 [NET]: {get|set}s... |
1279 1280 1281 1282 1283 1284 1285 |
int ipv6_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { int err; if (level == SOL_IP && sk->sk_type != SOCK_RAW) return udp_prot.getsockopt(sk, level, optname, optval, optlen); |
67ba4152e ipv6: White-space... |
1286 |
if (level != SOL_IPV6) |
3fdadf7d2 [NET]: {get|set}s... |
1287 |
return -ENOPROTOOPT; |
98e77438a ipv6: Fix ipv6_ge... |
1288 |
err = do_ipv6_getsockopt(sk, level, optname, optval, optlen, 0); |
3fdadf7d2 [NET]: {get|set}s... |
1289 |
#ifdef CONFIG_NETFILTER |
cf6fc4a92 [IPV6]: Fix the r... |
1290 1291 |
/* we need to exclude all possible ENOPROTOOPTs except default case */ if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) { |
3fdadf7d2 [NET]: {get|set}s... |
1292 1293 1294 1295 |
int len; if (get_user(len, optlen)) return -EFAULT; |
485595768 netfilter: drop o... |
1296 |
err = nf_getsockopt(sk, PF_INET6, optname, optval, &len); |
3fdadf7d2 [NET]: {get|set}s... |
1297 1298 1299 1300 1301 1302 |
if (err >= 0) err = put_user(len, optlen); } #endif return err; } |
7159039a1 [IPV6]: Decentral... |
1303 |
EXPORT_SYMBOL(ipv6_getsockopt); |
3fdadf7d2 [NET]: {get|set}s... |
1304 1305 |
#ifdef CONFIG_COMPAT int compat_ipv6_getsockopt(struct sock *sk, int level, int optname, |
543d9cfee [NET]: Identation... |
1306 |
char __user *optval, int __user *optlen) |
3fdadf7d2 [NET]: {get|set}s... |
1307 1308 1309 1310 |
{ int err; if (level == SOL_IP && sk->sk_type != SOCK_RAW) { |
543d9cfee [NET]: Identation... |
1311 1312 1313 1314 |
if (udp_prot.compat_getsockopt != NULL) return udp_prot.compat_getsockopt(sk, level, optname, optval, optlen); return udp_prot.getsockopt(sk, level, optname, optval, optlen); |
3fdadf7d2 [NET]: {get|set}s... |
1315 |
} |
543d9cfee [NET]: Identation... |
1316 |
if (level != SOL_IPV6) |
3fdadf7d2 [NET]: {get|set}s... |
1317 |
return -ENOPROTOOPT; |
809917903 ipv6: Compilation... |
1318 1319 1320 |
if (optname == MCAST_MSFILTER) return compat_mc_getsockopt(sk, level, optname, optval, optlen, ipv6_getsockopt); |
98e77438a ipv6: Fix ipv6_ge... |
1321 1322 |
err = do_ipv6_getsockopt(sk, level, optname, optval, optlen, MSG_CMSG_COMPAT); |
3fdadf7d2 [NET]: {get|set}s... |
1323 |
#ifdef CONFIG_NETFILTER |
cf6fc4a92 [IPV6]: Fix the r... |
1324 1325 |
/* we need to exclude all possible ENOPROTOOPTs except default case */ if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) { |
3fdadf7d2 [NET]: {get|set}s... |
1326 1327 1328 1329 |
int len; if (get_user(len, optlen)) return -EFAULT; |
485595768 netfilter: drop o... |
1330 |
err = compat_nf_getsockopt(sk, PF_INET6, optname, optval, &len); |
3fdadf7d2 [NET]: {get|set}s... |
1331 1332 1333 1334 1335 1336 |
if (err >= 0) err = put_user(len, optlen); } #endif return err; } |
543d9cfee [NET]: Identation... |
1337 |
EXPORT_SYMBOL(compat_ipv6_getsockopt); |
3fdadf7d2 [NET]: {get|set}s... |
1338 |
#endif |