diff options
author | Dmitry Mishin <dim@openvz.org> | 2006-03-21 01:45:21 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-03-21 01:45:21 -0500 |
commit | 3fdadf7d27e3fbcf72930941884387d1f4936f04 (patch) | |
tree | 167072cf1e60b6b307610563614b435ff0caa52d | |
parent | c750360938b403e6cc193d293cfbcb099dd6c60e (diff) |
[NET]: {get|set}sockopt compatibility layer
This patch extends {get|set}sockopt compatibility layer in order to
move protocol specific parts to their place and avoid huge universal
net/compat.c file in the future.
Signed-off-by: Dmitry Mishin <dim@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/net.h | 4 | ||||
-rw-r--r-- | include/linux/netfilter.h | 9 | ||||
-rw-r--r-- | include/net/inet_connection_sock.h | 6 | ||||
-rw-r--r-- | include/net/ip.h | 4 | ||||
-rw-r--r-- | include/net/ipv6.h | 10 | ||||
-rw-r--r-- | include/net/sctp/structs.h | 10 | ||||
-rw-r--r-- | include/net/sock.h | 12 | ||||
-rw-r--r-- | include/net/tcp.h | 6 | ||||
-rw-r--r-- | net/compat.c | 95 | ||||
-rw-r--r-- | net/core/sock.c | 28 | ||||
-rw-r--r-- | net/dccp/dccp.h | 8 | ||||
-rw-r--r-- | net/dccp/ipv4.c | 12 | ||||
-rw-r--r-- | net/dccp/ipv6.c | 16 | ||||
-rw-r--r-- | net/dccp/proto.c | 67 | ||||
-rw-r--r-- | net/ipv4/af_inet.c | 12 | ||||
-rw-r--r-- | net/ipv4/ip_sockglue.c | 142 | ||||
-rw-r--r-- | net/ipv4/raw.c | 50 | ||||
-rw-r--r-- | net/ipv4/tcp.c | 77 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 8 | ||||
-rw-r--r-- | net/ipv4/udp.c | 51 | ||||
-rw-r--r-- | net/ipv6/af_inet6.c | 12 | ||||
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 163 | ||||
-rw-r--r-- | net/ipv6/ipv6_syms.c | 4 | ||||
-rw-r--r-- | net/ipv6/raw.c | 112 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 12 | ||||
-rw-r--r-- | net/ipv6/udp.c | 52 | ||||
-rw-r--r-- | net/netfilter/nf_sockopt.c | 69 | ||||
-rw-r--r-- | net/sctp/ipv6.c | 8 | ||||
-rw-r--r-- | net/sctp/protocol.c | 8 |
29 files changed, 928 insertions, 139 deletions
diff --git a/include/linux/net.h b/include/linux/net.h index 28195a2d8ff0..152fa6551fd8 100644 --- a/include/linux/net.h +++ b/include/linux/net.h | |||
@@ -149,6 +149,10 @@ struct proto_ops { | |||
149 | int optname, char __user *optval, int optlen); | 149 | int optname, char __user *optval, int optlen); |
150 | int (*getsockopt)(struct socket *sock, int level, | 150 | int (*getsockopt)(struct socket *sock, int level, |
151 | int optname, char __user *optval, int __user *optlen); | 151 | int optname, char __user *optval, int __user *optlen); |
152 | int (*compat_setsockopt)(struct socket *sock, int level, | ||
153 | int optname, char __user *optval, int optlen); | ||
154 | int (*compat_getsockopt)(struct socket *sock, int level, | ||
155 | int optname, char __user *optval, int __user *optlen); | ||
152 | int (*sendmsg) (struct kiocb *iocb, struct socket *sock, | 156 | int (*sendmsg) (struct kiocb *iocb, struct socket *sock, |
153 | struct msghdr *m, size_t total_len); | 157 | struct msghdr *m, size_t total_len); |
154 | int (*recvmsg) (struct kiocb *iocb, struct socket *sock, | 158 | int (*recvmsg) (struct kiocb *iocb, struct socket *sock, |
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 468896939843..412e52ca9720 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h | |||
@@ -80,10 +80,14 @@ struct nf_sockopt_ops | |||
80 | int set_optmin; | 80 | int set_optmin; |
81 | int set_optmax; | 81 | int set_optmax; |
82 | int (*set)(struct sock *sk, int optval, void __user *user, unsigned int len); | 82 | int (*set)(struct sock *sk, int optval, void __user *user, unsigned int len); |
83 | int (*compat_set)(struct sock *sk, int optval, | ||
84 | void __user *user, unsigned int len); | ||
83 | 85 | ||
84 | int get_optmin; | 86 | int get_optmin; |
85 | int get_optmax; | 87 | int get_optmax; |
86 | int (*get)(struct sock *sk, int optval, void __user *user, int *len); | 88 | int (*get)(struct sock *sk, int optval, void __user *user, int *len); |
89 | int (*compat_get)(struct sock *sk, int optval, | ||
90 | void __user *user, int *len); | ||
87 | 91 | ||
88 | /* Number of users inside set() or get(). */ | 92 | /* Number of users inside set() or get(). */ |
89 | unsigned int use; | 93 | unsigned int use; |
@@ -246,6 +250,11 @@ int nf_setsockopt(struct sock *sk, int pf, int optval, char __user *opt, | |||
246 | int nf_getsockopt(struct sock *sk, int pf, int optval, char __user *opt, | 250 | int nf_getsockopt(struct sock *sk, int pf, int optval, char __user *opt, |
247 | int *len); | 251 | int *len); |
248 | 252 | ||
253 | int compat_nf_setsockopt(struct sock *sk, int pf, int optval, | ||
254 | char __user *opt, int len); | ||
255 | int compat_nf_getsockopt(struct sock *sk, int pf, int optval, | ||
256 | char __user *opt, int *len); | ||
257 | |||
249 | /* Packet queuing */ | 258 | /* Packet queuing */ |
250 | struct nf_queue_handler { | 259 | struct nf_queue_handler { |
251 | int (*outfn)(struct sk_buff *skb, struct nf_info *info, | 260 | int (*outfn)(struct sk_buff *skb, struct nf_info *info, |
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index 363a067403ee..ae61331366f0 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h | |||
@@ -50,6 +50,12 @@ struct inet_connection_sock_af_ops { | |||
50 | char __user *optval, int optlen); | 50 | char __user *optval, int optlen); |
51 | int (*getsockopt)(struct sock *sk, int level, int optname, | 51 | int (*getsockopt)(struct sock *sk, int level, int optname, |
52 | char __user *optval, int __user *optlen); | 52 | char __user *optval, int __user *optlen); |
53 | int (*compat_setsockopt)(struct sock *sk, | ||
54 | int level, int optname, | ||
55 | char __user *optval, int optlen); | ||
56 | int (*compat_getsockopt)(struct sock *sk, | ||
57 | int level, int optname, | ||
58 | char __user *optval, int __user *optlen); | ||
53 | void (*addr2sockaddr)(struct sock *sk, struct sockaddr *); | 59 | void (*addr2sockaddr)(struct sock *sk, struct sockaddr *); |
54 | int sockaddr_len; | 60 | int sockaddr_len; |
55 | }; | 61 | }; |
diff --git a/include/net/ip.h b/include/net/ip.h index fab3d5b3ab1c..8fe6156ca9b0 100644 --- a/include/net/ip.h +++ b/include/net/ip.h | |||
@@ -356,6 +356,10 @@ extern void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb); | |||
356 | extern int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc); | 356 | extern int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc); |
357 | extern int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen); | 357 | extern int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen); |
358 | extern int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); | 358 | extern int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); |
359 | extern int compat_ip_setsockopt(struct sock *sk, int level, | ||
360 | int optname, char __user *optval, int optlen); | ||
361 | extern int compat_ip_getsockopt(struct sock *sk, int level, | ||
362 | int optname, char __user *optval, int __user *optlen); | ||
359 | extern int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *)); | 363 | extern int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *)); |
360 | 364 | ||
361 | extern int ip_recv_error(struct sock *sk, struct msghdr *msg, int len); | 365 | extern int ip_recv_error(struct sock *sk, struct msghdr *msg, int len); |
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index c893a1ce4b39..6d6f0634ae41 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h | |||
@@ -520,6 +520,16 @@ extern int ipv6_getsockopt(struct sock *sk, int level, | |||
520 | int optname, | 520 | int optname, |
521 | char __user *optval, | 521 | char __user *optval, |
522 | int __user *optlen); | 522 | int __user *optlen); |
523 | extern int compat_ipv6_setsockopt(struct sock *sk, | ||
524 | int level, | ||
525 | int optname, | ||
526 | char __user *optval, | ||
527 | int optlen); | ||
528 | extern int compat_ipv6_getsockopt(struct sock *sk, | ||
529 | int level, | ||
530 | int optname, | ||
531 | char __user *optval, | ||
532 | int __user *optlen); | ||
523 | 533 | ||
524 | extern void ipv6_packet_init(void); | 534 | extern void ipv6_packet_init(void); |
525 | 535 | ||
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 072f407848a6..eba99f375517 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h | |||
@@ -514,6 +514,16 @@ struct sctp_af { | |||
514 | int optname, | 514 | int optname, |
515 | char __user *optval, | 515 | char __user *optval, |
516 | int __user *optlen); | 516 | int __user *optlen); |
517 | int (*compat_setsockopt) (struct sock *sk, | ||
518 | int level, | ||
519 | int optname, | ||
520 | char __user *optval, | ||
521 | int optlen); | ||
522 | int (*compat_getsockopt) (struct sock *sk, | ||
523 | int level, | ||
524 | int optname, | ||
525 | char __user *optval, | ||
526 | int __user *optlen); | ||
517 | struct dst_entry *(*get_dst) (struct sctp_association *asoc, | 527 | struct dst_entry *(*get_dst) (struct sctp_association *asoc, |
518 | union sctp_addr *daddr, | 528 | union sctp_addr *daddr, |
519 | union sctp_addr *saddr); | 529 | union sctp_addr *saddr); |
diff --git a/include/net/sock.h b/include/net/sock.h index f63d0d56712c..ec226f31dc2a 100644 --- a/include/net/sock.h +++ b/include/net/sock.h | |||
@@ -520,6 +520,14 @@ struct proto { | |||
520 | int (*getsockopt)(struct sock *sk, int level, | 520 | int (*getsockopt)(struct sock *sk, int level, |
521 | int optname, char __user *optval, | 521 | int optname, char __user *optval, |
522 | int __user *option); | 522 | int __user *option); |
523 | int (*compat_setsockopt)(struct sock *sk, | ||
524 | int level, | ||
525 | int optname, char __user *optval, | ||
526 | int optlen); | ||
527 | int (*compat_getsockopt)(struct sock *sk, | ||
528 | int level, | ||
529 | int optname, char __user *optval, | ||
530 | int __user *option); | ||
523 | int (*sendmsg)(struct kiocb *iocb, struct sock *sk, | 531 | int (*sendmsg)(struct kiocb *iocb, struct sock *sk, |
524 | struct msghdr *msg, size_t len); | 532 | struct msghdr *msg, size_t len); |
525 | int (*recvmsg)(struct kiocb *iocb, struct sock *sk, | 533 | int (*recvmsg)(struct kiocb *iocb, struct sock *sk, |
@@ -816,6 +824,10 @@ extern int sock_common_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
816 | struct msghdr *msg, size_t size, int flags); | 824 | struct msghdr *msg, size_t size, int flags); |
817 | extern int sock_common_setsockopt(struct socket *sock, int level, int optname, | 825 | extern int sock_common_setsockopt(struct socket *sock, int level, int optname, |
818 | char __user *optval, int optlen); | 826 | char __user *optval, int optlen); |
827 | extern int compat_sock_common_getsockopt(struct socket *sock, int level, | ||
828 | int optname, char __user *optval, int __user *optlen); | ||
829 | extern int compat_sock_common_setsockopt(struct socket *sock, int level, | ||
830 | int optname, char __user *optval, int optlen); | ||
819 | 831 | ||
820 | extern void sk_common_release(struct sock *sk); | 832 | extern void sk_common_release(struct sock *sk); |
821 | 833 | ||
diff --git a/include/net/tcp.h b/include/net/tcp.h index 457e224de468..9418f4d1afbb 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -353,6 +353,12 @@ extern int tcp_getsockopt(struct sock *sk, int level, | |||
353 | extern int tcp_setsockopt(struct sock *sk, int level, | 353 | extern int tcp_setsockopt(struct sock *sk, int level, |
354 | int optname, char __user *optval, | 354 | int optname, char __user *optval, |
355 | int optlen); | 355 | int optlen); |
356 | extern int compat_tcp_getsockopt(struct sock *sk, | ||
357 | int level, int optname, | ||
358 | char __user *optval, int __user *optlen); | ||
359 | extern int compat_tcp_setsockopt(struct sock *sk, | ||
360 | int level, int optname, | ||
361 | char __user *optval, int optlen); | ||
356 | extern void tcp_set_keepalive(struct sock *sk, int val); | 362 | extern void tcp_set_keepalive(struct sock *sk, int val); |
357 | extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, | 363 | extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, |
358 | struct msghdr *msg, | 364 | struct msghdr *msg, |
diff --git a/net/compat.c b/net/compat.c index e593dace2fdb..13177a1a4b39 100644 --- a/net/compat.c +++ b/net/compat.c | |||
@@ -416,7 +416,7 @@ struct compat_sock_fprog { | |||
416 | compat_uptr_t filter; /* struct sock_filter * */ | 416 | compat_uptr_t filter; /* struct sock_filter * */ |
417 | }; | 417 | }; |
418 | 418 | ||
419 | static int do_set_attach_filter(int fd, int level, int optname, | 419 | static int do_set_attach_filter(struct socket *sock, int level, int optname, |
420 | char __user *optval, int optlen) | 420 | char __user *optval, int optlen) |
421 | { | 421 | { |
422 | struct compat_sock_fprog __user *fprog32 = (struct compat_sock_fprog __user *)optval; | 422 | struct compat_sock_fprog __user *fprog32 = (struct compat_sock_fprog __user *)optval; |
@@ -432,11 +432,12 @@ static int do_set_attach_filter(int fd, int level, int optname, | |||
432 | __put_user(compat_ptr(ptr), &kfprog->filter)) | 432 | __put_user(compat_ptr(ptr), &kfprog->filter)) |
433 | return -EFAULT; | 433 | return -EFAULT; |
434 | 434 | ||
435 | return sys_setsockopt(fd, level, optname, (char __user *)kfprog, | 435 | return sock_setsockopt(sock, level, optname, (char __user *)kfprog, |
436 | sizeof(struct sock_fprog)); | 436 | sizeof(struct sock_fprog)); |
437 | } | 437 | } |
438 | 438 | ||
439 | static int do_set_sock_timeout(int fd, int level, int optname, char __user *optval, int optlen) | 439 | static int do_set_sock_timeout(struct socket *sock, int level, |
440 | int optname, char __user *optval, int optlen) | ||
440 | { | 441 | { |
441 | struct compat_timeval __user *up = (struct compat_timeval __user *) optval; | 442 | struct compat_timeval __user *up = (struct compat_timeval __user *) optval; |
442 | struct timeval ktime; | 443 | struct timeval ktime; |
@@ -451,30 +452,61 @@ static int do_set_sock_timeout(int fd, int level, int optname, char __user *optv | |||
451 | return -EFAULT; | 452 | return -EFAULT; |
452 | old_fs = get_fs(); | 453 | old_fs = get_fs(); |
453 | set_fs(KERNEL_DS); | 454 | set_fs(KERNEL_DS); |
454 | err = sys_setsockopt(fd, level, optname, (char *) &ktime, sizeof(ktime)); | 455 | err = sock_setsockopt(sock, level, optname, (char *) &ktime, sizeof(ktime)); |
455 | set_fs(old_fs); | 456 | set_fs(old_fs); |
456 | 457 | ||
457 | return err; | 458 | return err; |
458 | } | 459 | } |
459 | 460 | ||
461 | static int compat_sock_setsockopt(struct socket *sock, int level, int optname, | ||
462 | char __user *optval, int optlen) | ||
463 | { | ||
464 | if (optname == SO_ATTACH_FILTER) | ||
465 | return do_set_attach_filter(sock, level, optname, | ||
466 | optval, optlen); | ||
467 | if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) | ||
468 | return do_set_sock_timeout(sock, level, optname, optval, optlen); | ||
469 | |||
470 | return sock_setsockopt(sock, level, optname, optval, optlen); | ||
471 | } | ||
472 | |||
460 | asmlinkage long compat_sys_setsockopt(int fd, int level, int optname, | 473 | asmlinkage long compat_sys_setsockopt(int fd, int level, int optname, |
461 | char __user *optval, int optlen) | 474 | char __user *optval, int optlen) |
462 | { | 475 | { |
476 | int err; | ||
477 | struct socket *sock; | ||
478 | |||
463 | /* SO_SET_REPLACE seems to be the same in all levels */ | 479 | /* SO_SET_REPLACE seems to be the same in all levels */ |
464 | if (optname == IPT_SO_SET_REPLACE) | 480 | if (optname == IPT_SO_SET_REPLACE) |
465 | return do_netfilter_replace(fd, level, optname, | 481 | return do_netfilter_replace(fd, level, optname, |
466 | optval, optlen); | 482 | optval, optlen); |
467 | if (level == SOL_SOCKET && optname == SO_ATTACH_FILTER) | ||
468 | return do_set_attach_filter(fd, level, optname, | ||
469 | optval, optlen); | ||
470 | if (level == SOL_SOCKET && | ||
471 | (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) | ||
472 | return do_set_sock_timeout(fd, level, optname, optval, optlen); | ||
473 | 483 | ||
474 | return sys_setsockopt(fd, level, optname, optval, optlen); | 484 | if (optlen < 0) |
485 | return -EINVAL; | ||
486 | |||
487 | if ((sock = sockfd_lookup(fd, &err))!=NULL) | ||
488 | { | ||
489 | err = security_socket_setsockopt(sock,level,optname); | ||
490 | if (err) { | ||
491 | sockfd_put(sock); | ||
492 | return err; | ||
493 | } | ||
494 | |||
495 | if (level == SOL_SOCKET) | ||
496 | err = compat_sock_setsockopt(sock, level, | ||
497 | optname, optval, optlen); | ||
498 | else if (sock->ops->compat_setsockopt) | ||
499 | err = sock->ops->compat_setsockopt(sock, level, | ||
500 | optname, optval, optlen); | ||
501 | else | ||
502 | err = sock->ops->setsockopt(sock, level, | ||
503 | optname, optval, optlen); | ||
504 | sockfd_put(sock); | ||
505 | } | ||
506 | return err; | ||
475 | } | 507 | } |
476 | 508 | ||
477 | static int do_get_sock_timeout(int fd, int level, int optname, | 509 | static int do_get_sock_timeout(struct socket *sock, int level, int optname, |
478 | char __user *optval, int __user *optlen) | 510 | char __user *optval, int __user *optlen) |
479 | { | 511 | { |
480 | struct compat_timeval __user *up; | 512 | struct compat_timeval __user *up; |
@@ -490,7 +522,7 @@ static int do_get_sock_timeout(int fd, int level, int optname, | |||
490 | len = sizeof(ktime); | 522 | len = sizeof(ktime); |
491 | old_fs = get_fs(); | 523 | old_fs = get_fs(); |
492 | set_fs(KERNEL_DS); | 524 | set_fs(KERNEL_DS); |
493 | err = sys_getsockopt(fd, level, optname, (char *) &ktime, &len); | 525 | err = sock_getsockopt(sock, level, optname, (char *) &ktime, &len); |
494 | set_fs(old_fs); | 526 | set_fs(old_fs); |
495 | 527 | ||
496 | if (!err) { | 528 | if (!err) { |
@@ -503,15 +535,42 @@ static int do_get_sock_timeout(int fd, int level, int optname, | |||
503 | return err; | 535 | return err; |
504 | } | 536 | } |
505 | 537 | ||
506 | asmlinkage long compat_sys_getsockopt(int fd, int level, int optname, | 538 | static int compat_sock_getsockopt(struct socket *sock, int level, int optname, |
507 | char __user *optval, int __user *optlen) | 539 | char __user *optval, int __user *optlen) |
508 | { | 540 | { |
509 | if (level == SOL_SOCKET && | 541 | if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) |
510 | (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) | 542 | return do_get_sock_timeout(sock, level, optname, optval, optlen); |
511 | return do_get_sock_timeout(fd, level, optname, optval, optlen); | 543 | return sock_getsockopt(sock, level, optname, optval, optlen); |
512 | return sys_getsockopt(fd, level, optname, optval, optlen); | ||
513 | } | 544 | } |
514 | 545 | ||
546 | asmlinkage long compat_sys_getsockopt(int fd, int level, int optname, | ||
547 | char __user *optval, int __user *optlen) | ||
548 | { | ||
549 | int err; | ||
550 | struct socket *sock; | ||
551 | |||
552 | if ((sock = sockfd_lookup(fd, &err))!=NULL) | ||
553 | { | ||
554 | err = security_socket_getsockopt(sock, level, | ||
555 | optname); | ||
556 | if (err) { | ||
557 | sockfd_put(sock); | ||
558 | return err; | ||
559 | } | ||
560 | |||
561 | if (level == SOL_SOCKET) | ||
562 | err = compat_sock_getsockopt(sock, level, | ||
563 | optname, optval, optlen); | ||
564 | else if (sock->ops->compat_getsockopt) | ||
565 | err = sock->ops->compat_getsockopt(sock, level, | ||
566 | optname, optval, optlen); | ||
567 | else | ||
568 | err = sock->ops->getsockopt(sock, level, | ||
569 | optname, optval, optlen); | ||
570 | sockfd_put(sock); | ||
571 | } | ||
572 | return err; | ||
573 | } | ||
515 | /* Argument list sizes for compat_sys_socketcall */ | 574 | /* Argument list sizes for compat_sys_socketcall */ |
516 | #define AL(x) ((x) * sizeof(u32)) | 575 | #define AL(x) ((x) * sizeof(u32)) |
517 | static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), | 576 | static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), |
diff --git a/net/core/sock.c b/net/core/sock.c index 5038a5a7bd84..dd63cdea3fe7 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -1385,6 +1385,20 @@ int sock_common_getsockopt(struct socket *sock, int level, int optname, | |||
1385 | 1385 | ||
1386 | EXPORT_SYMBOL(sock_common_getsockopt); | 1386 | EXPORT_SYMBOL(sock_common_getsockopt); |
1387 | 1387 | ||
1388 | #ifdef CONFIG_COMPAT | ||
1389 | int compat_sock_common_getsockopt(struct socket *sock, int level, | ||
1390 | int optname, char __user *optval, int __user *optlen) | ||
1391 | { | ||
1392 | struct sock *sk = sock->sk; | ||
1393 | |||
1394 | if (sk->sk_prot->compat_setsockopt) | ||
1395 | return sk->sk_prot->compat_getsockopt(sk, level, | ||
1396 | optname, optval, optlen); | ||
1397 | return sk->sk_prot->getsockopt(sk, level, optname, optval, optlen); | ||
1398 | } | ||
1399 | EXPORT_SYMBOL(compat_sock_common_getsockopt); | ||
1400 | #endif | ||
1401 | |||
1388 | int sock_common_recvmsg(struct kiocb *iocb, struct socket *sock, | 1402 | int sock_common_recvmsg(struct kiocb *iocb, struct socket *sock, |
1389 | struct msghdr *msg, size_t size, int flags) | 1403 | struct msghdr *msg, size_t size, int flags) |
1390 | { | 1404 | { |
@@ -1414,6 +1428,20 @@ int sock_common_setsockopt(struct socket *sock, int level, int optname, | |||
1414 | 1428 | ||
1415 | EXPORT_SYMBOL(sock_common_setsockopt); | 1429 | EXPORT_SYMBOL(sock_common_setsockopt); |
1416 | 1430 | ||
1431 | #ifdef CONFIG_COMPAT | ||
1432 | int compat_sock_common_setsockopt(struct socket *sock, | ||
1433 | int level, int optname, char __user *optval, int optlen) | ||
1434 | { | ||
1435 | struct sock *sk = sock->sk; | ||
1436 | |||
1437 | if (sk->sk_prot->compat_setsockopt) | ||
1438 | return sk->sk_prot->compat_setsockopt(sk, level, | ||
1439 | optname, optval, optlen); | ||
1440 | return sk->sk_prot->setsockopt(sk, level, optname, optval, optlen); | ||
1441 | } | ||
1442 | EXPORT_SYMBOL(compat_sock_common_setsockopt); | ||
1443 | #endif | ||
1444 | |||
1417 | void sk_common_release(struct sock *sk) | 1445 | void sk_common_release(struct sock *sk) |
1418 | { | 1446 | { |
1419 | if (sk->sk_prot->destroy) | 1447 | if (sk->sk_prot->destroy) |
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 34e70fb89d4a..47de17208d7a 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h | |||
@@ -192,6 +192,14 @@ extern int dccp_getsockopt(struct sock *sk, int level, int optname, | |||
192 | char __user *optval, int __user *optlen); | 192 | char __user *optval, int __user *optlen); |
193 | extern int dccp_setsockopt(struct sock *sk, int level, int optname, | 193 | extern int dccp_setsockopt(struct sock *sk, int level, int optname, |
194 | char __user *optval, int optlen); | 194 | char __user *optval, int optlen); |
195 | #ifdef CONFIG_COMPAT | ||
196 | extern int compat_dccp_getsockopt(struct sock *sk, | ||
197 | int level, int optname, | ||
198 | char __user *optval, int __user *optlen); | ||
199 | extern int compat_dccp_setsockopt(struct sock *sk, | ||
200 | int level, int optname, | ||
201 | char __user *optval, int optlen); | ||
202 | #endif | ||
195 | extern int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg); | 203 | extern int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg); |
196 | extern int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, | 204 | extern int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, |
197 | struct msghdr *msg, size_t size); | 205 | struct msghdr *msg, size_t size); |
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 80d450ba6219..8a33c8498d9c 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -994,6 +994,10 @@ static struct inet_connection_sock_af_ops dccp_ipv4_af_ops = { | |||
994 | .net_header_len = sizeof(struct iphdr), | 994 | .net_header_len = sizeof(struct iphdr), |
995 | .setsockopt = ip_setsockopt, | 995 | .setsockopt = ip_setsockopt, |
996 | .getsockopt = ip_getsockopt, | 996 | .getsockopt = ip_getsockopt, |
997 | #ifdef CONFIG_COMPAT | ||
998 | .compat_setsockopt = compat_ip_setsockopt, | ||
999 | .compat_getsockopt = compat_ip_getsockopt, | ||
1000 | #endif | ||
997 | .addr2sockaddr = inet_csk_addr2sockaddr, | 1001 | .addr2sockaddr = inet_csk_addr2sockaddr, |
998 | .sockaddr_len = sizeof(struct sockaddr_in), | 1002 | .sockaddr_len = sizeof(struct sockaddr_in), |
999 | }; | 1003 | }; |
@@ -1040,6 +1044,10 @@ static struct proto dccp_v4_prot = { | |||
1040 | .init = dccp_v4_init_sock, | 1044 | .init = dccp_v4_init_sock, |
1041 | .setsockopt = dccp_setsockopt, | 1045 | .setsockopt = dccp_setsockopt, |
1042 | .getsockopt = dccp_getsockopt, | 1046 | .getsockopt = dccp_getsockopt, |
1047 | #ifdef CONFIG_COMPAT | ||
1048 | .compat_setsockopt = compat_dccp_setsockopt, | ||
1049 | .compat_getsockopt = compat_dccp_getsockopt, | ||
1050 | #endif | ||
1043 | .sendmsg = dccp_sendmsg, | 1051 | .sendmsg = dccp_sendmsg, |
1044 | .recvmsg = dccp_recvmsg, | 1052 | .recvmsg = dccp_recvmsg, |
1045 | .backlog_rcv = dccp_v4_do_rcv, | 1053 | .backlog_rcv = dccp_v4_do_rcv, |
@@ -1079,6 +1087,10 @@ static const struct proto_ops inet_dccp_ops = { | |||
1079 | .shutdown = inet_shutdown, | 1087 | .shutdown = inet_shutdown, |
1080 | .setsockopt = sock_common_setsockopt, | 1088 | .setsockopt = sock_common_setsockopt, |
1081 | .getsockopt = sock_common_getsockopt, | 1089 | .getsockopt = sock_common_getsockopt, |
1090 | #ifdef CONFIG_COMPAT | ||
1091 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
1092 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
1093 | #endif | ||
1082 | .sendmsg = inet_sendmsg, | 1094 | .sendmsg = inet_sendmsg, |
1083 | .recvmsg = sock_common_recvmsg, | 1095 | .recvmsg = sock_common_recvmsg, |
1084 | .mmap = sock_no_mmap, | 1096 | .mmap = sock_no_mmap, |
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 7c8233f6d3c2..89106c7d3247 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c | |||
@@ -1114,6 +1114,10 @@ static struct inet_connection_sock_af_ops dccp_ipv6_af_ops = { | |||
1114 | .net_header_len = sizeof(struct ipv6hdr), | 1114 | .net_header_len = sizeof(struct ipv6hdr), |
1115 | .setsockopt = ipv6_setsockopt, | 1115 | .setsockopt = ipv6_setsockopt, |
1116 | .getsockopt = ipv6_getsockopt, | 1116 | .getsockopt = ipv6_getsockopt, |
1117 | #ifdef CONFIG_COMPAT | ||
1118 | .compat_setsockopt = compat_ipv6_setsockopt, | ||
1119 | .compat_getsockopt = compat_ipv6_getsockopt, | ||
1120 | #endif | ||
1117 | .addr2sockaddr = inet6_csk_addr2sockaddr, | 1121 | .addr2sockaddr = inet6_csk_addr2sockaddr, |
1118 | .sockaddr_len = sizeof(struct sockaddr_in6) | 1122 | .sockaddr_len = sizeof(struct sockaddr_in6) |
1119 | }; | 1123 | }; |
@@ -1130,6 +1134,10 @@ static struct inet_connection_sock_af_ops dccp_ipv6_mapped = { | |||
1130 | .net_header_len = sizeof(struct iphdr), | 1134 | .net_header_len = sizeof(struct iphdr), |
1131 | .setsockopt = ipv6_setsockopt, | 1135 | .setsockopt = ipv6_setsockopt, |
1132 | .getsockopt = ipv6_getsockopt, | 1136 | .getsockopt = ipv6_getsockopt, |
1137 | #ifdef CONFIG_COMPAT | ||
1138 | .compat_setsockopt = compat_ipv6_setsockopt, | ||
1139 | .compat_getsockopt = compat_ipv6_getsockopt, | ||
1140 | #endif | ||
1133 | .addr2sockaddr = inet6_csk_addr2sockaddr, | 1141 | .addr2sockaddr = inet6_csk_addr2sockaddr, |
1134 | .sockaddr_len = sizeof(struct sockaddr_in6) | 1142 | .sockaddr_len = sizeof(struct sockaddr_in6) |
1135 | }; | 1143 | }; |
@@ -1167,6 +1175,10 @@ static struct proto dccp_v6_prot = { | |||
1167 | .init = dccp_v6_init_sock, | 1175 | .init = dccp_v6_init_sock, |
1168 | .setsockopt = dccp_setsockopt, | 1176 | .setsockopt = dccp_setsockopt, |
1169 | .getsockopt = dccp_getsockopt, | 1177 | .getsockopt = dccp_getsockopt, |
1178 | #ifdef CONFIG_COMPAT | ||
1179 | .compat_setsockopt = compat_dccp_setsockopt, | ||
1180 | .compat_getsockopt = compat_dccp_getsockopt, | ||
1181 | #endif | ||
1170 | .sendmsg = dccp_sendmsg, | 1182 | .sendmsg = dccp_sendmsg, |
1171 | .recvmsg = dccp_recvmsg, | 1183 | .recvmsg = dccp_recvmsg, |
1172 | .backlog_rcv = dccp_v6_do_rcv, | 1184 | .backlog_rcv = dccp_v6_do_rcv, |
@@ -1204,6 +1216,10 @@ static struct proto_ops inet6_dccp_ops = { | |||
1204 | .shutdown = inet_shutdown, | 1216 | .shutdown = inet_shutdown, |
1205 | .setsockopt = sock_common_setsockopt, | 1217 | .setsockopt = sock_common_setsockopt, |
1206 | .getsockopt = sock_common_getsockopt, | 1218 | .getsockopt = sock_common_getsockopt, |
1219 | #ifdef CONFIG_COMPAT | ||
1220 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
1221 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
1222 | #endif | ||
1207 | .sendmsg = inet_sendmsg, | 1223 | .sendmsg = inet_sendmsg, |
1208 | .recvmsg = sock_common_recvmsg, | 1224 | .recvmsg = sock_common_recvmsg, |
1209 | .mmap = sock_no_mmap, | 1225 | .mmap = sock_no_mmap, |
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index baccaf35ffbd..59b214995f28 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c | |||
@@ -455,18 +455,13 @@ out_free_val: | |||
455 | goto out; | 455 | goto out; |
456 | } | 456 | } |
457 | 457 | ||
458 | int dccp_setsockopt(struct sock *sk, int level, int optname, | 458 | static int do_dccp_setsockopt(struct sock *sk, int level, int optname, |
459 | char __user *optval, int optlen) | 459 | char __user *optval, int optlen) |
460 | { | 460 | { |
461 | struct dccp_sock *dp; | 461 | struct dccp_sock *dp; |
462 | int err; | 462 | int err; |
463 | int val; | 463 | int val; |
464 | 464 | ||
465 | if (level != SOL_DCCP) | ||
466 | return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level, | ||
467 | optname, optval, | ||
468 | optlen); | ||
469 | |||
470 | if (optlen < sizeof(int)) | 465 | if (optlen < sizeof(int)) |
471 | return -EINVAL; | 466 | return -EINVAL; |
472 | 467 | ||
@@ -512,8 +507,34 @@ int dccp_setsockopt(struct sock *sk, int level, int optname, | |||
512 | return err; | 507 | return err; |
513 | } | 508 | } |
514 | 509 | ||
510 | int dccp_setsockopt(struct sock *sk, int level, int optname, | ||
511 | char __user *optval, int optlen) | ||
512 | { | ||
513 | if (level != SOL_DCCP) | ||
514 | return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level, | ||
515 | optname, optval, | ||
516 | optlen); | ||
517 | return do_dccp_setsockopt(sk, level, optname, optval, optlen); | ||
518 | } | ||
515 | EXPORT_SYMBOL_GPL(dccp_setsockopt); | 519 | EXPORT_SYMBOL_GPL(dccp_setsockopt); |
516 | 520 | ||
521 | #ifdef CONFIG_COMPAT | ||
522 | int compat_dccp_setsockopt(struct sock *sk, int level, int optname, | ||
523 | char __user *optval, int optlen) | ||
524 | { | ||
525 | if (level != SOL_DCCP) { | ||
526 | if (inet_csk(sk)->icsk_af_ops->compat_setsockopt) | ||
527 | return inet_csk(sk)->icsk_af_ops->compat_setsockopt(sk, | ||
528 | level, optname, optval, optlen); | ||
529 | else | ||
530 | return inet_csk(sk)->icsk_af_ops->setsockopt(sk, | ||
531 | level, optname, optval, optlen); | ||
532 | } | ||
533 | return do_dccp_setsockopt(sk, level, optname, optval, optlen); | ||
534 | } | ||
535 | EXPORT_SYMBOL_GPL(compat_dccp_setsockopt); | ||
536 | #endif | ||
537 | |||
517 | static int dccp_getsockopt_service(struct sock *sk, int len, | 538 | static int dccp_getsockopt_service(struct sock *sk, int len, |
518 | __be32 __user *optval, | 539 | __be32 __user *optval, |
519 | int __user *optlen) | 540 | int __user *optlen) |
@@ -545,16 +566,12 @@ out: | |||
545 | return err; | 566 | return err; |
546 | } | 567 | } |
547 | 568 | ||
548 | int dccp_getsockopt(struct sock *sk, int level, int optname, | 569 | static int do_dccp_getsockopt(struct sock *sk, int level, int optname, |
549 | char __user *optval, int __user *optlen) | 570 | char __user *optval, int __user *optlen) |
550 | { | 571 | { |
551 | struct dccp_sock *dp; | 572 | struct dccp_sock *dp; |
552 | int val, len; | 573 | int val, len; |
553 | 574 | ||
554 | if (level != SOL_DCCP) | ||
555 | return inet_csk(sk)->icsk_af_ops->getsockopt(sk, level, | ||
556 | optname, optval, | ||
557 | optlen); | ||
558 | if (get_user(len, optlen)) | 575 | if (get_user(len, optlen)) |
559 | return -EFAULT; | 576 | return -EFAULT; |
560 | 577 | ||
@@ -587,8 +604,34 @@ int dccp_getsockopt(struct sock *sk, int level, int optname, | |||
587 | return 0; | 604 | return 0; |
588 | } | 605 | } |
589 | 606 | ||
607 | int dccp_getsockopt(struct sock *sk, int level, int optname, | ||
608 | char __user *optval, int __user *optlen) | ||
609 | { | ||
610 | if (level != SOL_DCCP) | ||
611 | return inet_csk(sk)->icsk_af_ops->getsockopt(sk, level, | ||
612 | optname, optval, | ||
613 | optlen); | ||
614 | return do_dccp_getsockopt(sk, level, optname, optval, optlen); | ||
615 | } | ||
590 | EXPORT_SYMBOL_GPL(dccp_getsockopt); | 616 | EXPORT_SYMBOL_GPL(dccp_getsockopt); |
591 | 617 | ||
618 | #ifdef CONFIG_COMPAT | ||
619 | int compat_dccp_getsockopt(struct sock *sk, int level, int optname, | ||
620 | char __user *optval, int __user *optlen) | ||
621 | { | ||
622 | if (level != SOL_DCCP) { | ||
623 | if (inet_csk(sk)->icsk_af_ops->compat_setsockopt) | ||
624 | return inet_csk(sk)->icsk_af_ops->compat_getsockopt(sk, | ||
625 | level, optname, optval, optlen); | ||
626 | else | ||
627 | return inet_csk(sk)->icsk_af_ops->getsockopt(sk, | ||
628 | level, optname, optval, optlen); | ||
629 | } | ||
630 | return do_dccp_getsockopt(sk, level, optname, optval, optlen); | ||
631 | } | ||
632 | EXPORT_SYMBOL_GPL(compat_dccp_getsockopt); | ||
633 | #endif | ||
634 | |||
592 | int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | 635 | int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
593 | size_t len) | 636 | size_t len) |
594 | { | 637 | { |
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 97c276f95b35..454e523b506a 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -802,6 +802,10 @@ const struct proto_ops inet_stream_ops = { | |||
802 | .shutdown = inet_shutdown, | 802 | .shutdown = inet_shutdown, |
803 | .setsockopt = sock_common_setsockopt, | 803 | .setsockopt = sock_common_setsockopt, |
804 | .getsockopt = sock_common_getsockopt, | 804 | .getsockopt = sock_common_getsockopt, |
805 | #ifdef CONFIG_COMPAT | ||
806 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
807 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
808 | #endif | ||
805 | .sendmsg = inet_sendmsg, | 809 | .sendmsg = inet_sendmsg, |
806 | .recvmsg = sock_common_recvmsg, | 810 | .recvmsg = sock_common_recvmsg, |
807 | .mmap = sock_no_mmap, | 811 | .mmap = sock_no_mmap, |
@@ -823,6 +827,10 @@ const struct proto_ops inet_dgram_ops = { | |||
823 | .shutdown = inet_shutdown, | 827 | .shutdown = inet_shutdown, |
824 | .setsockopt = sock_common_setsockopt, | 828 | .setsockopt = sock_common_setsockopt, |
825 | .getsockopt = sock_common_getsockopt, | 829 | .getsockopt = sock_common_getsockopt, |
830 | #ifdef CONFIG_COMPAT | ||
831 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
832 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
833 | #endif | ||
826 | .sendmsg = inet_sendmsg, | 834 | .sendmsg = inet_sendmsg, |
827 | .recvmsg = sock_common_recvmsg, | 835 | .recvmsg = sock_common_recvmsg, |
828 | .mmap = sock_no_mmap, | 836 | .mmap = sock_no_mmap, |
@@ -848,6 +856,10 @@ static const struct proto_ops inet_sockraw_ops = { | |||
848 | .shutdown = inet_shutdown, | 856 | .shutdown = inet_shutdown, |
849 | .setsockopt = sock_common_setsockopt, | 857 | .setsockopt = sock_common_setsockopt, |
850 | .getsockopt = sock_common_getsockopt, | 858 | .getsockopt = sock_common_getsockopt, |
859 | #ifdef CONFIG_COMPAT | ||
860 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
861 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
862 | #endif | ||
851 | .sendmsg = inet_sendmsg, | 863 | .sendmsg = inet_sendmsg, |
852 | .recvmsg = sock_common_recvmsg, | 864 | .recvmsg = sock_common_recvmsg, |
853 | .mmap = sock_no_mmap, | 865 | .mmap = sock_no_mmap, |
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index b5c4f61518e8..49ff1cd4e1c9 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
@@ -399,14 +399,12 @@ out: | |||
399 | * an IP socket. | 399 | * an IP socket. |
400 | */ | 400 | */ |
401 | 401 | ||
402 | int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) | 402 | static int do_ip_setsockopt(struct sock *sk, int level, |
403 | int optname, char __user *optval, int optlen) | ||
403 | { | 404 | { |
404 | struct inet_sock *inet = inet_sk(sk); | 405 | struct inet_sock *inet = inet_sk(sk); |
405 | int val=0,err; | 406 | int val=0,err; |
406 | 407 | ||
407 | if (level != SOL_IP) | ||
408 | return -ENOPROTOOPT; | ||
409 | |||
410 | if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) | | 408 | if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) | |
411 | (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) | | 409 | (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) | |
412 | (1<<IP_RETOPTS) | (1<<IP_TOS) | | 410 | (1<<IP_RETOPTS) | (1<<IP_TOS) | |
@@ -875,12 +873,7 @@ mc_msf_out: | |||
875 | break; | 873 | break; |
876 | 874 | ||
877 | default: | 875 | default: |
878 | #ifdef CONFIG_NETFILTER | ||
879 | err = nf_setsockopt(sk, PF_INET, optname, optval, | ||
880 | optlen); | ||
881 | #else | ||
882 | err = -ENOPROTOOPT; | 876 | err = -ENOPROTOOPT; |
883 | #endif | ||
884 | break; | 877 | break; |
885 | } | 878 | } |
886 | release_sock(sk); | 879 | release_sock(sk); |
@@ -891,12 +884,66 @@ e_inval: | |||
891 | return -EINVAL; | 884 | return -EINVAL; |
892 | } | 885 | } |
893 | 886 | ||
887 | int ip_setsockopt(struct sock *sk, int level, | ||
888 | int optname, char __user *optval, int optlen) | ||
889 | { | ||
890 | int err; | ||
891 | |||
892 | if (level != SOL_IP) | ||
893 | return -ENOPROTOOPT; | ||
894 | |||
895 | err = do_ip_setsockopt(sk, level, optname, optval, optlen); | ||
896 | #ifdef CONFIG_NETFILTER | ||
897 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
898 | if (err == -ENOPROTOOPT && optname != IP_HDRINCL && | ||
899 | optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY | ||
900 | #ifdef CONFIG_IP_MROUTE | ||
901 | && (optname < MRT_BASE || optname > (MRT_BASE + 10)) | ||
902 | #endif | ||
903 | ) { | ||
904 | lock_sock(sk); | ||
905 | err = nf_setsockopt(sk, PF_INET, optname, optval, optlen); | ||
906 | release_sock(sk); | ||
907 | } | ||
908 | #endif | ||
909 | return err; | ||
910 | } | ||
911 | |||
912 | #ifdef CONFIG_COMPAT | ||
913 | int compat_ip_setsockopt(struct sock *sk, int level, | ||
914 | int optname, char __user *optval, int optlen) | ||
915 | { | ||
916 | int err; | ||
917 | |||
918 | if (level != SOL_IP) | ||
919 | return -ENOPROTOOPT; | ||
920 | |||
921 | err = do_ip_setsockopt(sk, level, optname, optval, optlen); | ||
922 | #ifdef CONFIG_NETFILTER | ||
923 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
924 | if (err == -ENOPROTOOPT && optname != IP_HDRINCL && | ||
925 | optname != IP_IPSEC_POLICY && optname != IP_XFRM_POLICY | ||
926 | #ifdef CONFIG_IP_MROUTE | ||
927 | && (optname < MRT_BASE || optname > (MRT_BASE + 10)) | ||
928 | #endif | ||
929 | ) { | ||
930 | lock_sock(sk); | ||
931 | err = compat_nf_setsockopt(sk, PF_INET, | ||
932 | optname, optval, optlen); | ||
933 | release_sock(sk); | ||
934 | } | ||
935 | #endif | ||
936 | return err; | ||
937 | } | ||
938 | #endif | ||
939 | |||
894 | /* | 940 | /* |
895 | * Get the options. Note for future reference. The GET of IP options gets the | 941 | * Get the options. Note for future reference. The GET of IP options gets the |
896 | * _received_ ones. The set sets the _sent_ ones. | 942 | * _received_ ones. The set sets the _sent_ ones. |
897 | */ | 943 | */ |
898 | 944 | ||
899 | int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) | 945 | static int do_ip_getsockopt(struct sock *sk, int level, int optname, |
946 | char __user *optval, int __user *optlen) | ||
900 | { | 947 | { |
901 | struct inet_sock *inet = inet_sk(sk); | 948 | struct inet_sock *inet = inet_sk(sk); |
902 | int val; | 949 | int val; |
@@ -1080,17 +1127,8 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, | |||
1080 | val = inet->freebind; | 1127 | val = inet->freebind; |
1081 | break; | 1128 | break; |
1082 | default: | 1129 | default: |
1083 | #ifdef CONFIG_NETFILTER | ||
1084 | val = nf_getsockopt(sk, PF_INET, optname, optval, | ||
1085 | &len); | ||
1086 | release_sock(sk); | ||
1087 | if (val >= 0) | ||
1088 | val = put_user(len, optlen); | ||
1089 | return val; | ||
1090 | #else | ||
1091 | release_sock(sk); | 1130 | release_sock(sk); |
1092 | return -ENOPROTOOPT; | 1131 | return -ENOPROTOOPT; |
1093 | #endif | ||
1094 | } | 1132 | } |
1095 | release_sock(sk); | 1133 | release_sock(sk); |
1096 | 1134 | ||
@@ -1111,7 +1149,73 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, | |||
1111 | return 0; | 1149 | return 0; |
1112 | } | 1150 | } |
1113 | 1151 | ||
1152 | int ip_getsockopt(struct sock *sk, int level, | ||
1153 | int optname, char __user *optval, int __user *optlen) | ||
1154 | { | ||
1155 | int err; | ||
1156 | |||
1157 | err = do_ip_getsockopt(sk, level, optname, optval, optlen); | ||
1158 | #ifdef CONFIG_NETFILTER | ||
1159 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
1160 | if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS | ||
1161 | #ifdef CONFIG_IP_MROUTE | ||
1162 | && (optname < MRT_BASE || optname > MRT_BASE+10) | ||
1163 | #endif | ||
1164 | ) { | ||
1165 | int len; | ||
1166 | |||
1167 | if(get_user(len,optlen)) | ||
1168 | return -EFAULT; | ||
1169 | |||
1170 | lock_sock(sk); | ||
1171 | err = nf_getsockopt(sk, PF_INET, optname, optval, | ||
1172 | &len); | ||
1173 | release_sock(sk); | ||
1174 | if (err >= 0) | ||
1175 | err = put_user(len, optlen); | ||
1176 | return err; | ||
1177 | } | ||
1178 | #endif | ||
1179 | return err; | ||
1180 | } | ||
1181 | |||
1182 | #ifdef CONFIG_COMPAT | ||
1183 | int compat_ip_getsockopt(struct sock *sk, int level, | ||
1184 | int optname, char __user *optval, int __user *optlen) | ||
1185 | { | ||
1186 | int err; | ||
1187 | |||
1188 | err = do_ip_getsockopt(sk, level, optname, optval, optlen); | ||
1189 | #ifdef CONFIG_NETFILTER | ||
1190 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
1191 | if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS | ||
1192 | #ifdef CONFIG_IP_MROUTE | ||
1193 | && (optname < MRT_BASE || optname > MRT_BASE+10) | ||
1194 | #endif | ||
1195 | ) { | ||
1196 | int len; | ||
1197 | |||
1198 | if(get_user(len,optlen)) | ||
1199 | return -EFAULT; | ||
1200 | |||
1201 | lock_sock(sk); | ||
1202 | err = compat_nf_getsockopt(sk, PF_INET, | ||
1203 | optname, optval, &len); | ||
1204 | release_sock(sk); | ||
1205 | if (err >= 0) | ||
1206 | err = put_user(len, optlen); | ||
1207 | return err; | ||
1208 | } | ||
1209 | #endif | ||
1210 | return err; | ||
1211 | } | ||
1212 | #endif | ||
1213 | |||
1114 | EXPORT_SYMBOL(ip_cmsg_recv); | 1214 | EXPORT_SYMBOL(ip_cmsg_recv); |
1115 | 1215 | ||
1116 | EXPORT_SYMBOL(ip_getsockopt); | 1216 | EXPORT_SYMBOL(ip_getsockopt); |
1117 | EXPORT_SYMBOL(ip_setsockopt); | 1217 | EXPORT_SYMBOL(ip_setsockopt); |
1218 | #ifdef CONFIG_COMPAT | ||
1219 | EXPORT_SYMBOL(compat_ip_getsockopt); | ||
1220 | EXPORT_SYMBOL(compat_ip_setsockopt); | ||
1221 | #endif | ||
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index f29a12da5109..f1b02b34fc0a 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c | |||
@@ -660,12 +660,9 @@ static int raw_geticmpfilter(struct sock *sk, char __user *optval, int __user *o | |||
660 | out: return ret; | 660 | out: return ret; |
661 | } | 661 | } |
662 | 662 | ||
663 | static int raw_setsockopt(struct sock *sk, int level, int optname, | 663 | static int do_raw_setsockopt(struct sock *sk, int level, int optname, |
664 | char __user *optval, int optlen) | 664 | char __user *optval, int optlen) |
665 | { | 665 | { |
666 | if (level != SOL_RAW) | ||
667 | return ip_setsockopt(sk, level, optname, optval, optlen); | ||
668 | |||
669 | if (optname == ICMP_FILTER) { | 666 | if (optname == ICMP_FILTER) { |
670 | if (inet_sk(sk)->num != IPPROTO_ICMP) | 667 | if (inet_sk(sk)->num != IPPROTO_ICMP) |
671 | return -EOPNOTSUPP; | 668 | return -EOPNOTSUPP; |
@@ -675,12 +672,28 @@ static int raw_setsockopt(struct sock *sk, int level, int optname, | |||
675 | return -ENOPROTOOPT; | 672 | return -ENOPROTOOPT; |
676 | } | 673 | } |
677 | 674 | ||
678 | static int raw_getsockopt(struct sock *sk, int level, int optname, | 675 | static int raw_setsockopt(struct sock *sk, int level, int optname, |
679 | char __user *optval, int __user *optlen) | 676 | char __user *optval, int optlen) |
680 | { | 677 | { |
681 | if (level != SOL_RAW) | 678 | if (level != SOL_RAW) |
682 | return ip_getsockopt(sk, level, optname, optval, optlen); | 679 | return ip_setsockopt(sk, level, optname, optval, optlen); |
680 | return do_raw_setsockopt(sk, level, optname, optval, optlen); | ||
681 | } | ||
683 | 682 | ||
683 | #ifdef CONFIG_COMPAT | ||
684 | static int compat_raw_setsockopt(struct sock *sk, int level, int optname, | ||
685 | char __user *optval, int optlen) | ||
686 | { | ||
687 | if (level != SOL_RAW) | ||
688 | return compat_ip_setsockopt(sk, level, | ||
689 | optname, optval, optlen); | ||
690 | return do_raw_setsockopt(sk, level, optname, optval, optlen); | ||
691 | } | ||
692 | #endif | ||
693 | |||
694 | static int do_raw_getsockopt(struct sock *sk, int level, int optname, | ||
695 | char __user *optval, int __user *optlen) | ||
696 | { | ||
684 | if (optname == ICMP_FILTER) { | 697 | if (optname == ICMP_FILTER) { |
685 | if (inet_sk(sk)->num != IPPROTO_ICMP) | 698 | if (inet_sk(sk)->num != IPPROTO_ICMP) |
686 | return -EOPNOTSUPP; | 699 | return -EOPNOTSUPP; |
@@ -690,6 +703,25 @@ static int raw_getsockopt(struct sock *sk, int level, int optname, | |||
690 | return -ENOPROTOOPT; | 703 | return -ENOPROTOOPT; |
691 | } | 704 | } |
692 | 705 | ||
706 | static int raw_getsockopt(struct sock *sk, int level, int optname, | ||
707 | char __user *optval, int __user *optlen) | ||
708 | { | ||
709 | if (level != SOL_RAW) | ||
710 | return ip_getsockopt(sk, level, optname, optval, optlen); | ||
711 | return do_raw_getsockopt(sk, level, optname, optval, optlen); | ||
712 | } | ||
713 | |||
714 | #ifdef CONFIG_COMPAT | ||
715 | static int compat_raw_getsockopt(struct sock *sk, int level, int optname, | ||
716 | char __user *optval, int __user *optlen) | ||
717 | { | ||
718 | if (level != SOL_RAW) | ||
719 | return compat_ip_getsockopt(sk, level, | ||
720 | optname, optval, optlen); | ||
721 | return do_raw_getsockopt(sk, level, optname, optval, optlen); | ||
722 | } | ||
723 | #endif | ||
724 | |||
693 | static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg) | 725 | static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg) |
694 | { | 726 | { |
695 | switch (cmd) { | 727 | switch (cmd) { |
@@ -728,6 +760,10 @@ struct proto raw_prot = { | |||
728 | .init = raw_init, | 760 | .init = raw_init, |
729 | .setsockopt = raw_setsockopt, | 761 | .setsockopt = raw_setsockopt, |
730 | .getsockopt = raw_getsockopt, | 762 | .getsockopt = raw_getsockopt, |
763 | #ifdef CONFIG_COMPAT | ||
764 | .compat_setsockopt = compat_raw_setsockopt, | ||
765 | .compat_getsockopt = compat_raw_getsockopt, | ||
766 | #endif | ||
731 | .sendmsg = raw_sendmsg, | 767 | .sendmsg = raw_sendmsg, |
732 | .recvmsg = raw_recvmsg, | 768 | .recvmsg = raw_recvmsg, |
733 | .bind = raw_bind, | 769 | .bind = raw_bind, |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 00aa80e93243..31b0123a9699 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -1687,18 +1687,14 @@ int tcp_disconnect(struct sock *sk, int flags) | |||
1687 | /* | 1687 | /* |
1688 | * Socket option code for TCP. | 1688 | * Socket option code for TCP. |
1689 | */ | 1689 | */ |
1690 | int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, | 1690 | static int do_tcp_setsockopt(struct sock *sk, int level, |
1691 | int optlen) | 1691 | int optname, char __user *optval, int optlen) |
1692 | { | 1692 | { |
1693 | struct tcp_sock *tp = tcp_sk(sk); | 1693 | struct tcp_sock *tp = tcp_sk(sk); |
1694 | struct inet_connection_sock *icsk = inet_csk(sk); | 1694 | struct inet_connection_sock *icsk = inet_csk(sk); |
1695 | int val; | 1695 | int val; |
1696 | int err = 0; | 1696 | int err = 0; |
1697 | 1697 | ||
1698 | if (level != SOL_TCP) | ||
1699 | return icsk->icsk_af_ops->setsockopt(sk, level, optname, | ||
1700 | optval, optlen); | ||
1701 | |||
1702 | /* This is a string value all the others are int's */ | 1698 | /* This is a string value all the others are int's */ |
1703 | if (optname == TCP_CONGESTION) { | 1699 | if (optname == TCP_CONGESTION) { |
1704 | char name[TCP_CA_NAME_MAX]; | 1700 | char name[TCP_CA_NAME_MAX]; |
@@ -1871,6 +1867,35 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, | |||
1871 | return err; | 1867 | return err; |
1872 | } | 1868 | } |
1873 | 1869 | ||
1870 | int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, | ||
1871 | int optlen) | ||
1872 | { | ||
1873 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
1874 | |||
1875 | if (level != SOL_TCP) | ||
1876 | return icsk->icsk_af_ops->setsockopt(sk, level, optname, | ||
1877 | optval, optlen); | ||
1878 | return do_tcp_setsockopt(sk, level, optname, optval, optlen); | ||
1879 | } | ||
1880 | |||
1881 | #ifdef CONFIG_COMPAT | ||
1882 | int compat_tcp_setsockopt(struct sock *sk, int level, | ||
1883 | int optname, char __user *optval, int optlen) | ||
1884 | { | ||
1885 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
1886 | |||
1887 | if (level != SOL_TCP) { | ||
1888 | if (icsk->icsk_af_ops->compat_setsockopt) | ||
1889 | return icsk->icsk_af_ops->compat_setsockopt(sk, | ||
1890 | level, optname, optval, optlen); | ||
1891 | else | ||
1892 | return icsk->icsk_af_ops->setsockopt(sk, | ||
1893 | level, optname, optval, optlen); | ||
1894 | } | ||
1895 | return do_tcp_setsockopt(sk, level, optname, optval, optlen); | ||
1896 | } | ||
1897 | #endif | ||
1898 | |||
1874 | /* Return information about state of tcp endpoint in API format. */ | 1899 | /* Return information about state of tcp endpoint in API format. */ |
1875 | void tcp_get_info(struct sock *sk, struct tcp_info *info) | 1900 | void tcp_get_info(struct sock *sk, struct tcp_info *info) |
1876 | { | 1901 | { |
@@ -1931,17 +1956,13 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) | |||
1931 | 1956 | ||
1932 | EXPORT_SYMBOL_GPL(tcp_get_info); | 1957 | EXPORT_SYMBOL_GPL(tcp_get_info); |
1933 | 1958 | ||
1934 | int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, | 1959 | static int do_tcp_getsockopt(struct sock *sk, int level, |
1935 | int __user *optlen) | 1960 | int optname, char __user *optval, int __user *optlen) |
1936 | { | 1961 | { |
1937 | struct inet_connection_sock *icsk = inet_csk(sk); | 1962 | struct inet_connection_sock *icsk = inet_csk(sk); |
1938 | struct tcp_sock *tp = tcp_sk(sk); | 1963 | struct tcp_sock *tp = tcp_sk(sk); |
1939 | int val, len; | 1964 | int val, len; |
1940 | 1965 | ||
1941 | if (level != SOL_TCP) | ||
1942 | return icsk->icsk_af_ops->getsockopt(sk, level, optname, | ||
1943 | optval, optlen); | ||
1944 | |||
1945 | if (get_user(len, optlen)) | 1966 | if (get_user(len, optlen)) |
1946 | return -EFAULT; | 1967 | return -EFAULT; |
1947 | 1968 | ||
@@ -2025,6 +2046,34 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, | |||
2025 | return 0; | 2046 | return 0; |
2026 | } | 2047 | } |
2027 | 2048 | ||
2049 | int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, | ||
2050 | int __user *optlen) | ||
2051 | { | ||
2052 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
2053 | |||
2054 | if (level != SOL_TCP) | ||
2055 | return icsk->icsk_af_ops->getsockopt(sk, level, optname, | ||
2056 | optval, optlen); | ||
2057 | return do_tcp_getsockopt(sk, level, optname, optval, optlen); | ||
2058 | } | ||
2059 | |||
2060 | #ifdef CONFIG_COMPAT | ||
2061 | int compat_tcp_getsockopt(struct sock *sk, int level, | ||
2062 | int optname, char __user *optval, int __user *optlen) | ||
2063 | { | ||
2064 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
2065 | |||
2066 | if (level != SOL_TCP) { | ||
2067 | if (icsk->icsk_af_ops->compat_getsockopt) | ||
2068 | return icsk->icsk_af_ops->compat_getsockopt(sk, | ||
2069 | level, optname, optval, optlen); | ||
2070 | else | ||
2071 | return icsk->icsk_af_ops->getsockopt(sk, | ||
2072 | level, optname, optval, optlen); | ||
2073 | } | ||
2074 | return do_tcp_getsockopt(sk, level, optname, optval, optlen); | ||
2075 | } | ||
2076 | #endif | ||
2028 | 2077 | ||
2029 | extern void __skb_cb_too_small_for_tcp(int, int); | 2078 | extern void __skb_cb_too_small_for_tcp(int, int); |
2030 | extern struct tcp_congestion_ops tcp_reno; | 2079 | extern struct tcp_congestion_ops tcp_reno; |
@@ -2142,3 +2191,7 @@ EXPORT_SYMBOL(tcp_sendpage); | |||
2142 | EXPORT_SYMBOL(tcp_setsockopt); | 2191 | EXPORT_SYMBOL(tcp_setsockopt); |
2143 | EXPORT_SYMBOL(tcp_shutdown); | 2192 | EXPORT_SYMBOL(tcp_shutdown); |
2144 | EXPORT_SYMBOL(tcp_statistics); | 2193 | EXPORT_SYMBOL(tcp_statistics); |
2194 | #ifdef CONFIG_COMPAT | ||
2195 | EXPORT_SYMBOL(compat_tcp_setsockopt); | ||
2196 | EXPORT_SYMBOL(compat_tcp_getsockopt); | ||
2197 | #endif | ||
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 4eb903db1b12..249ef6c88959 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -1226,6 +1226,10 @@ struct inet_connection_sock_af_ops ipv4_specific = { | |||
1226 | .net_header_len = sizeof(struct iphdr), | 1226 | .net_header_len = sizeof(struct iphdr), |
1227 | .setsockopt = ip_setsockopt, | 1227 | .setsockopt = ip_setsockopt, |
1228 | .getsockopt = ip_getsockopt, | 1228 | .getsockopt = ip_getsockopt, |
1229 | #ifdef CONFIG_COMPAT | ||
1230 | .compat_setsockopt = compat_ip_setsockopt, | ||
1231 | .compat_getsockopt = compat_ip_getsockopt, | ||
1232 | #endif | ||
1229 | .addr2sockaddr = inet_csk_addr2sockaddr, | 1233 | .addr2sockaddr = inet_csk_addr2sockaddr, |
1230 | .sockaddr_len = sizeof(struct sockaddr_in), | 1234 | .sockaddr_len = sizeof(struct sockaddr_in), |
1231 | }; | 1235 | }; |
@@ -1808,6 +1812,10 @@ struct proto tcp_prot = { | |||
1808 | .shutdown = tcp_shutdown, | 1812 | .shutdown = tcp_shutdown, |
1809 | .setsockopt = tcp_setsockopt, | 1813 | .setsockopt = tcp_setsockopt, |
1810 | .getsockopt = tcp_getsockopt, | 1814 | .getsockopt = tcp_getsockopt, |
1815 | #ifdef CONFIG_COMPAT | ||
1816 | .compat_setsockopt = compat_tcp_setsockopt, | ||
1817 | .compat_getsockopt = compat_tcp_getsockopt, | ||
1818 | #endif | ||
1811 | .sendmsg = tcp_sendmsg, | 1819 | .sendmsg = tcp_sendmsg, |
1812 | .recvmsg = tcp_recvmsg, | 1820 | .recvmsg = tcp_recvmsg, |
1813 | .backlog_rcv = tcp_v4_do_rcv, | 1821 | .backlog_rcv = tcp_v4_do_rcv, |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 00840474a449..0b0721bd45c6 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -1207,16 +1207,13 @@ static int udp_destroy_sock(struct sock *sk) | |||
1207 | /* | 1207 | /* |
1208 | * Socket option code for UDP | 1208 | * Socket option code for UDP |
1209 | */ | 1209 | */ |
1210 | static int udp_setsockopt(struct sock *sk, int level, int optname, | 1210 | static int do_udp_setsockopt(struct sock *sk, int level, int optname, |
1211 | char __user *optval, int optlen) | 1211 | char __user *optval, int optlen) |
1212 | { | 1212 | { |
1213 | struct udp_sock *up = udp_sk(sk); | 1213 | struct udp_sock *up = udp_sk(sk); |
1214 | int val; | 1214 | int val; |
1215 | int err = 0; | 1215 | int err = 0; |
1216 | 1216 | ||
1217 | if (level != SOL_UDP) | ||
1218 | return ip_setsockopt(sk, level, optname, optval, optlen); | ||
1219 | |||
1220 | if(optlen<sizeof(int)) | 1217 | if(optlen<sizeof(int)) |
1221 | return -EINVAL; | 1218 | return -EINVAL; |
1222 | 1219 | ||
@@ -1256,15 +1253,31 @@ static int udp_setsockopt(struct sock *sk, int level, int optname, | |||
1256 | return err; | 1253 | return err; |
1257 | } | 1254 | } |
1258 | 1255 | ||
1259 | static int udp_getsockopt(struct sock *sk, int level, int optname, | 1256 | static int udp_setsockopt(struct sock *sk, int level, int optname, |
1257 | char __user *optval, int optlen) | ||
1258 | { | ||
1259 | if (level != SOL_UDP) | ||
1260 | return ip_setsockopt(sk, level, optname, optval, optlen); | ||
1261 | return do_udp_setsockopt(sk, level, optname, optval, optlen); | ||
1262 | } | ||
1263 | |||
1264 | #ifdef CONFIG_COMPAT | ||
1265 | static int compat_udp_setsockopt(struct sock *sk, int level, int optname, | ||
1266 | char __user *optval, int optlen) | ||
1267 | { | ||
1268 | if (level != SOL_UDP) | ||
1269 | return compat_ip_setsockopt(sk, level, | ||
1270 | optname, optval, optlen); | ||
1271 | return do_udp_setsockopt(sk, level, optname, optval, optlen); | ||
1272 | } | ||
1273 | #endif | ||
1274 | |||
1275 | static int do_udp_getsockopt(struct sock *sk, int level, int optname, | ||
1260 | char __user *optval, int __user *optlen) | 1276 | char __user *optval, int __user *optlen) |
1261 | { | 1277 | { |
1262 | struct udp_sock *up = udp_sk(sk); | 1278 | struct udp_sock *up = udp_sk(sk); |
1263 | int val, len; | 1279 | int val, len; |
1264 | 1280 | ||
1265 | if (level != SOL_UDP) | ||
1266 | return ip_getsockopt(sk, level, optname, optval, optlen); | ||
1267 | |||
1268 | if(get_user(len,optlen)) | 1281 | if(get_user(len,optlen)) |
1269 | return -EFAULT; | 1282 | return -EFAULT; |
1270 | 1283 | ||
@@ -1293,6 +1306,24 @@ static int udp_getsockopt(struct sock *sk, int level, int optname, | |||
1293 | return 0; | 1306 | return 0; |
1294 | } | 1307 | } |
1295 | 1308 | ||
1309 | static int udp_getsockopt(struct sock *sk, int level, int optname, | ||
1310 | char __user *optval, int __user *optlen) | ||
1311 | { | ||
1312 | if (level != SOL_UDP) | ||
1313 | return ip_getsockopt(sk, level, optname, optval, optlen); | ||
1314 | return do_udp_getsockopt(sk, level, optname, optval, optlen); | ||
1315 | } | ||
1316 | |||
1317 | #ifdef CONFIG_COMPAT | ||
1318 | static int compat_udp_getsockopt(struct sock *sk, int level, int optname, | ||
1319 | char __user *optval, int __user *optlen) | ||
1320 | { | ||
1321 | if (level != SOL_UDP) | ||
1322 | return compat_ip_getsockopt(sk, level, | ||
1323 | optname, optval, optlen); | ||
1324 | return do_udp_getsockopt(sk, level, optname, optval, optlen); | ||
1325 | } | ||
1326 | #endif | ||
1296 | /** | 1327 | /** |
1297 | * udp_poll - wait for a UDP event. | 1328 | * udp_poll - wait for a UDP event. |
1298 | * @file - file struct | 1329 | * @file - file struct |
@@ -1350,6 +1381,10 @@ struct proto udp_prot = { | |||
1350 | .destroy = udp_destroy_sock, | 1381 | .destroy = udp_destroy_sock, |
1351 | .setsockopt = udp_setsockopt, | 1382 | .setsockopt = udp_setsockopt, |
1352 | .getsockopt = udp_getsockopt, | 1383 | .getsockopt = udp_getsockopt, |
1384 | #ifdef CONFIG_COMPAT | ||
1385 | .compat_setsockopt = compat_udp_setsockopt, | ||
1386 | .compat_getsockopt = compat_udp_getsockopt, | ||
1387 | #endif | ||
1353 | .sendmsg = udp_sendmsg, | 1388 | .sendmsg = udp_sendmsg, |
1354 | .recvmsg = udp_recvmsg, | 1389 | .recvmsg = udp_recvmsg, |
1355 | .sendpage = udp_sendpage, | 1390 | .sendpage = udp_sendpage, |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 6c9711ac1c03..97844c4cd9b1 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -470,6 +470,10 @@ const struct proto_ops inet6_stream_ops = { | |||
470 | .shutdown = inet_shutdown, /* ok */ | 470 | .shutdown = inet_shutdown, /* ok */ |
471 | .setsockopt = sock_common_setsockopt, /* ok */ | 471 | .setsockopt = sock_common_setsockopt, /* ok */ |
472 | .getsockopt = sock_common_getsockopt, /* ok */ | 472 | .getsockopt = sock_common_getsockopt, /* ok */ |
473 | #ifdef CONFIG_COMPAT | ||
474 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
475 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
476 | #endif | ||
473 | .sendmsg = inet_sendmsg, /* ok */ | 477 | .sendmsg = inet_sendmsg, /* ok */ |
474 | .recvmsg = sock_common_recvmsg, /* ok */ | 478 | .recvmsg = sock_common_recvmsg, /* ok */ |
475 | .mmap = sock_no_mmap, | 479 | .mmap = sock_no_mmap, |
@@ -491,6 +495,10 @@ const struct proto_ops inet6_dgram_ops = { | |||
491 | .shutdown = inet_shutdown, /* ok */ | 495 | .shutdown = inet_shutdown, /* ok */ |
492 | .setsockopt = sock_common_setsockopt, /* ok */ | 496 | .setsockopt = sock_common_setsockopt, /* ok */ |
493 | .getsockopt = sock_common_getsockopt, /* ok */ | 497 | .getsockopt = sock_common_getsockopt, /* ok */ |
498 | #ifdef CONFIG_COMPAT | ||
499 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
500 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
501 | #endif | ||
494 | .sendmsg = inet_sendmsg, /* ok */ | 502 | .sendmsg = inet_sendmsg, /* ok */ |
495 | .recvmsg = sock_common_recvmsg, /* ok */ | 503 | .recvmsg = sock_common_recvmsg, /* ok */ |
496 | .mmap = sock_no_mmap, | 504 | .mmap = sock_no_mmap, |
@@ -519,6 +527,10 @@ static const struct proto_ops inet6_sockraw_ops = { | |||
519 | .shutdown = inet_shutdown, /* ok */ | 527 | .shutdown = inet_shutdown, /* ok */ |
520 | .setsockopt = sock_common_setsockopt, /* ok */ | 528 | .setsockopt = sock_common_setsockopt, /* ok */ |
521 | .getsockopt = sock_common_getsockopt, /* ok */ | 529 | .getsockopt = sock_common_getsockopt, /* ok */ |
530 | #ifdef CONFIG_COMPAT | ||
531 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
532 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
533 | #endif | ||
522 | .sendmsg = inet_sendmsg, /* ok */ | 534 | .sendmsg = inet_sendmsg, /* ok */ |
523 | .recvmsg = sock_common_recvmsg, /* ok */ | 535 | .recvmsg = sock_common_recvmsg, /* ok */ |
524 | .mmap = sock_no_mmap, | 536 | .mmap = sock_no_mmap, |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index f7142ba519ab..988eac58e9d1 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -109,19 +109,13 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *)) | |||
109 | return 0; | 109 | return 0; |
110 | } | 110 | } |
111 | 111 | ||
112 | int ipv6_setsockopt(struct sock *sk, int level, int optname, | 112 | static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, |
113 | char __user *optval, int optlen) | 113 | char __user *optval, int optlen) |
114 | { | 114 | { |
115 | struct ipv6_pinfo *np = inet6_sk(sk); | 115 | struct ipv6_pinfo *np = inet6_sk(sk); |
116 | int val, valbool; | 116 | int val, valbool; |
117 | int retv = -ENOPROTOOPT; | 117 | int retv = -ENOPROTOOPT; |
118 | 118 | ||
119 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) | ||
120 | return udp_prot.setsockopt(sk, level, optname, optval, optlen); | ||
121 | |||
122 | if(level!=SOL_IPV6) | ||
123 | goto out; | ||
124 | |||
125 | if (optval == NULL) | 119 | if (optval == NULL) |
126 | val=0; | 120 | val=0; |
127 | else if (get_user(val, (int __user *) optval)) | 121 | else if (get_user(val, (int __user *) optval)) |
@@ -613,17 +607,9 @@ done: | |||
613 | retv = xfrm_user_policy(sk, optname, optval, optlen); | 607 | retv = xfrm_user_policy(sk, optname, optval, optlen); |
614 | break; | 608 | break; |
615 | 609 | ||
616 | #ifdef CONFIG_NETFILTER | ||
617 | default: | ||
618 | retv = nf_setsockopt(sk, PF_INET6, optname, optval, | ||
619 | optlen); | ||
620 | break; | ||
621 | #endif | ||
622 | |||
623 | } | 610 | } |
624 | release_sock(sk); | 611 | release_sock(sk); |
625 | 612 | ||
626 | out: | ||
627 | return retv; | 613 | return retv; |
628 | 614 | ||
629 | e_inval: | 615 | e_inval: |
@@ -631,6 +617,65 @@ e_inval: | |||
631 | return -EINVAL; | 617 | return -EINVAL; |
632 | } | 618 | } |
633 | 619 | ||
620 | int ipv6_setsockopt(struct sock *sk, int level, int optname, | ||
621 | char __user *optval, int optlen) | ||
622 | { | ||
623 | int err; | ||
624 | |||
625 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) | ||
626 | return udp_prot.setsockopt(sk, level, optname, optval, optlen); | ||
627 | |||
628 | if (level != SOL_IPV6) | ||
629 | return -ENOPROTOOPT; | ||
630 | |||
631 | err = do_ipv6_setsockopt(sk, level, optname, optval, optlen); | ||
632 | #ifdef CONFIG_NETFILTER | ||
633 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
634 | if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY && | ||
635 | optname != IPV6_XFRM_POLICY) { | ||
636 | lock_sock(sk); | ||
637 | err = nf_setsockopt(sk, PF_INET6, optname, optval, | ||
638 | optlen); | ||
639 | release_sock(sk); | ||
640 | } | ||
641 | #endif | ||
642 | return err; | ||
643 | } | ||
644 | |||
645 | |||
646 | #ifdef CONFIG_COMPAT | ||
647 | int compat_ipv6_setsockopt(struct sock *sk, int level, int optname, | ||
648 | char __user *optval, int optlen) | ||
649 | { | ||
650 | int err; | ||
651 | |||
652 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) { | ||
653 | if (udp_prot.compat_setsockopt) | ||
654 | return udp_prot.compat_setsockopt(sk, level, | ||
655 | optname, optval, optlen); | ||
656 | else | ||
657 | return udp_prot.setsockopt(sk, level, | ||
658 | optname, optval, optlen); | ||
659 | } | ||
660 | |||
661 | if (level != SOL_IPV6) | ||
662 | return -ENOPROTOOPT; | ||
663 | |||
664 | err = do_ipv6_setsockopt(sk, level, optname, optval, optlen); | ||
665 | #ifdef CONFIG_NETFILTER | ||
666 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | ||
667 | if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY && | ||
668 | optname != IPV6_XFRM_POLICY) { | ||
669 | lock_sock(sk); | ||
670 | err = compat_nf_setsockopt(sk, PF_INET6, optname, optval, | ||
671 | optlen); | ||
672 | release_sock(sk); | ||
673 | } | ||
674 | #endif | ||
675 | return err; | ||
676 | } | ||
677 | #endif | ||
678 | |||
634 | static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr, | 679 | static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr, |
635 | char __user *optval, int len) | 680 | char __user *optval, int len) |
636 | { | 681 | { |
@@ -642,17 +687,13 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr, | |||
642 | return len; | 687 | return len; |
643 | } | 688 | } |
644 | 689 | ||
645 | int ipv6_getsockopt(struct sock *sk, int level, int optname, | 690 | static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, |
646 | char __user *optval, int __user *optlen) | 691 | char __user *optval, int __user *optlen) |
647 | { | 692 | { |
648 | struct ipv6_pinfo *np = inet6_sk(sk); | 693 | struct ipv6_pinfo *np = inet6_sk(sk); |
649 | int len; | 694 | int len; |
650 | int val; | 695 | int val; |
651 | 696 | ||
652 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) | ||
653 | return udp_prot.getsockopt(sk, level, optname, optval, optlen); | ||
654 | if(level!=SOL_IPV6) | ||
655 | return -ENOPROTOOPT; | ||
656 | if (get_user(len, optlen)) | 697 | if (get_user(len, optlen)) |
657 | return -EFAULT; | 698 | return -EFAULT; |
658 | switch (optname) { | 699 | switch (optname) { |
@@ -842,17 +883,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
842 | break; | 883 | break; |
843 | 884 | ||
844 | default: | 885 | default: |
845 | #ifdef CONFIG_NETFILTER | ||
846 | lock_sock(sk); | ||
847 | val = nf_getsockopt(sk, PF_INET6, optname, optval, | ||
848 | &len); | ||
849 | release_sock(sk); | ||
850 | if (val >= 0) | ||
851 | val = put_user(len, optlen); | ||
852 | return val; | ||
853 | #else | ||
854 | return -EINVAL; | 886 | return -EINVAL; |
855 | #endif | ||
856 | } | 887 | } |
857 | len = min_t(unsigned int, sizeof(int), len); | 888 | len = min_t(unsigned int, sizeof(int), len); |
858 | if(put_user(len, optlen)) | 889 | if(put_user(len, optlen)) |
@@ -862,6 +893,78 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
862 | return 0; | 893 | return 0; |
863 | } | 894 | } |
864 | 895 | ||
896 | int ipv6_getsockopt(struct sock *sk, int level, int optname, | ||
897 | char __user *optval, int __user *optlen) | ||
898 | { | ||
899 | int err; | ||
900 | |||
901 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) | ||
902 | return udp_prot.getsockopt(sk, level, optname, optval, optlen); | ||
903 | |||
904 | if(level != SOL_IPV6) | ||
905 | return -ENOPROTOOPT; | ||
906 | |||
907 | err = do_ipv6_getsockopt(sk, level, optname, optval, optlen); | ||
908 | #ifdef CONFIG_NETFILTER | ||
909 | /* we need to exclude all possible EINVALs except default case */ | ||
910 | if (err == -ENOPROTOOPT && optname != IPV6_ADDRFORM && | ||
911 | optname != MCAST_MSFILTER) { | ||
912 | int len; | ||
913 | |||
914 | if (get_user(len, optlen)) | ||
915 | return -EFAULT; | ||
916 | |||
917 | lock_sock(sk); | ||
918 | err = nf_getsockopt(sk, PF_INET6, optname, optval, | ||
919 | &len); | ||
920 | release_sock(sk); | ||
921 | if (err >= 0) | ||
922 | err = put_user(len, optlen); | ||
923 | } | ||
924 | #endif | ||
925 | return err; | ||
926 | } | ||
927 | |||
928 | #ifdef CONFIG_COMPAT | ||
929 | int compat_ipv6_getsockopt(struct sock *sk, int level, int optname, | ||
930 | char __user *optval, int __user *optlen) | ||
931 | { | ||
932 | int err; | ||
933 | |||
934 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) { | ||
935 | if (udp_prot.compat_getsockopt) | ||
936 | return udp_prot.compat_getsockopt(sk, level, | ||
937 | optname, optval, optlen); | ||
938 | else | ||
939 | return udp_prot.getsockopt(sk, level, | ||
940 | optname, optval, optlen); | ||
941 | } | ||
942 | |||
943 | if(level != SOL_IPV6) | ||
944 | return -ENOPROTOOPT; | ||
945 | |||
946 | err = do_ipv6_getsockopt(sk, level, optname, optval, optlen); | ||
947 | #ifdef CONFIG_NETFILTER | ||
948 | /* we need to exclude all possible EINVALs except default case */ | ||
949 | if (err == -ENOPROTOOPT && optname != IPV6_ADDRFORM && | ||
950 | optname != MCAST_MSFILTER) { | ||
951 | int len; | ||
952 | |||
953 | if (get_user(len, optlen)) | ||
954 | return -EFAULT; | ||
955 | |||
956 | lock_sock(sk); | ||
957 | err = compat_nf_getsockopt(sk, PF_INET6, optname, optval, | ||
958 | &len); | ||
959 | release_sock(sk); | ||
960 | if (err >= 0) | ||
961 | err = put_user(len, optlen); | ||
962 | } | ||
963 | #endif | ||
964 | return err; | ||
965 | } | ||
966 | #endif | ||
967 | |||
865 | void __init ipv6_packet_init(void) | 968 | void __init ipv6_packet_init(void) |
866 | { | 969 | { |
867 | dev_add_pack(&ipv6_packet_type); | 970 | dev_add_pack(&ipv6_packet_type); |
diff --git a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c index 16482785bdfd..61419e11e35d 100644 --- a/net/ipv6/ipv6_syms.c +++ b/net/ipv6/ipv6_syms.c | |||
@@ -18,6 +18,10 @@ EXPORT_SYMBOL(ip6_route_output); | |||
18 | EXPORT_SYMBOL(addrconf_lock); | 18 | EXPORT_SYMBOL(addrconf_lock); |
19 | EXPORT_SYMBOL(ipv6_setsockopt); | 19 | EXPORT_SYMBOL(ipv6_setsockopt); |
20 | EXPORT_SYMBOL(ipv6_getsockopt); | 20 | EXPORT_SYMBOL(ipv6_getsockopt); |
21 | #ifdef CONFIG_COMPAT | ||
22 | EXPORT_SYMBOL(compat_ipv6_setsockopt); | ||
23 | EXPORT_SYMBOL(compat_ipv6_getsockopt); | ||
24 | #endif | ||
21 | EXPORT_SYMBOL(inet6_register_protosw); | 25 | EXPORT_SYMBOL(inet6_register_protosw); |
22 | EXPORT_SYMBOL(inet6_unregister_protosw); | 26 | EXPORT_SYMBOL(inet6_unregister_protosw); |
23 | EXPORT_SYMBOL(inet6_add_protocol); | 27 | EXPORT_SYMBOL(inet6_add_protocol); |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index ae20a0ec9bd8..8de5a8e59149 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -859,29 +859,12 @@ static int rawv6_geticmpfilter(struct sock *sk, int level, int optname, | |||
859 | } | 859 | } |
860 | 860 | ||
861 | 861 | ||
862 | static int rawv6_setsockopt(struct sock *sk, int level, int optname, | 862 | static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, |
863 | char __user *optval, int optlen) | 863 | char __user *optval, int optlen) |
864 | { | 864 | { |
865 | struct raw6_sock *rp = raw6_sk(sk); | 865 | struct raw6_sock *rp = raw6_sk(sk); |
866 | int val; | 866 | int val; |
867 | 867 | ||
868 | switch(level) { | ||
869 | case SOL_RAW: | ||
870 | break; | ||
871 | |||
872 | case SOL_ICMPV6: | ||
873 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | ||
874 | return -EOPNOTSUPP; | ||
875 | return rawv6_seticmpfilter(sk, level, optname, optval, | ||
876 | optlen); | ||
877 | case SOL_IPV6: | ||
878 | if (optname == IPV6_CHECKSUM) | ||
879 | break; | ||
880 | default: | ||
881 | return ipv6_setsockopt(sk, level, optname, optval, | ||
882 | optlen); | ||
883 | }; | ||
884 | |||
885 | if (get_user(val, (int __user *)optval)) | 868 | if (get_user(val, (int __user *)optval)) |
886 | return -EFAULT; | 869 | return -EFAULT; |
887 | 870 | ||
@@ -906,12 +889,9 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname, | |||
906 | } | 889 | } |
907 | } | 890 | } |
908 | 891 | ||
909 | static int rawv6_getsockopt(struct sock *sk, int level, int optname, | 892 | static int rawv6_setsockopt(struct sock *sk, int level, int optname, |
910 | char __user *optval, int __user *optlen) | 893 | char __user *optval, int optlen) |
911 | { | 894 | { |
912 | struct raw6_sock *rp = raw6_sk(sk); | ||
913 | int val, len; | ||
914 | |||
915 | switch(level) { | 895 | switch(level) { |
916 | case SOL_RAW: | 896 | case SOL_RAW: |
917 | break; | 897 | break; |
@@ -919,15 +899,47 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname, | |||
919 | case SOL_ICMPV6: | 899 | case SOL_ICMPV6: |
920 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | 900 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) |
921 | return -EOPNOTSUPP; | 901 | return -EOPNOTSUPP; |
922 | return rawv6_geticmpfilter(sk, level, optname, optval, | 902 | return rawv6_seticmpfilter(sk, level, optname, optval, |
923 | optlen); | 903 | optlen); |
924 | case SOL_IPV6: | 904 | case SOL_IPV6: |
925 | if (optname == IPV6_CHECKSUM) | 905 | if (optname == IPV6_CHECKSUM) |
926 | break; | 906 | break; |
927 | default: | 907 | default: |
928 | return ipv6_getsockopt(sk, level, optname, optval, | 908 | return ipv6_setsockopt(sk, level, optname, optval, |
929 | optlen); | 909 | optlen); |
930 | }; | 910 | }; |
911 | return do_rawv6_setsockopt(sk, level, optname, optval, optlen); | ||
912 | } | ||
913 | |||
914 | #ifdef CONFIG_COMPAT | ||
915 | static int compat_rawv6_setsockopt(struct sock *sk, int level, int optname, | ||
916 | char __user *optval, int optlen) | ||
917 | { | ||
918 | switch(level) { | ||
919 | case SOL_RAW: | ||
920 | break; | ||
921 | |||
922 | case SOL_ICMPV6: | ||
923 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | ||
924 | return -EOPNOTSUPP; | ||
925 | return rawv6_seticmpfilter(sk, level, optname, optval, | ||
926 | optlen); | ||
927 | case SOL_IPV6: | ||
928 | if (optname == IPV6_CHECKSUM) | ||
929 | break; | ||
930 | default: | ||
931 | return compat_ipv6_setsockopt(sk, level, | ||
932 | optname, optval, optlen); | ||
933 | }; | ||
934 | return do_rawv6_setsockopt(sk, level, optname, optval, optlen); | ||
935 | } | ||
936 | #endif | ||
937 | |||
938 | static int do_rawv6_getsockopt(struct sock *sk, int level, int optname, | ||
939 | char __user *optval, int __user *optlen) | ||
940 | { | ||
941 | struct raw6_sock *rp = raw6_sk(sk); | ||
942 | int val, len; | ||
931 | 943 | ||
932 | if (get_user(len,optlen)) | 944 | if (get_user(len,optlen)) |
933 | return -EFAULT; | 945 | return -EFAULT; |
@@ -953,6 +965,52 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname, | |||
953 | return 0; | 965 | return 0; |
954 | } | 966 | } |
955 | 967 | ||
968 | static int rawv6_getsockopt(struct sock *sk, int level, int optname, | ||
969 | char __user *optval, int __user *optlen) | ||
970 | { | ||
971 | switch(level) { | ||
972 | case SOL_RAW: | ||
973 | break; | ||
974 | |||
975 | case SOL_ICMPV6: | ||
976 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | ||
977 | return -EOPNOTSUPP; | ||
978 | return rawv6_geticmpfilter(sk, level, optname, optval, | ||
979 | optlen); | ||
980 | case SOL_IPV6: | ||
981 | if (optname == IPV6_CHECKSUM) | ||
982 | break; | ||
983 | default: | ||
984 | return ipv6_getsockopt(sk, level, optname, optval, | ||
985 | optlen); | ||
986 | }; | ||
987 | return do_rawv6_getsockopt(sk, level, optname, optval, optlen); | ||
988 | } | ||
989 | |||
990 | #ifdef CONFIG_COMPAT | ||
991 | static int compat_rawv6_getsockopt(struct sock *sk, int level, int optname, | ||
992 | char __user *optval, int __user *optlen) | ||
993 | { | ||
994 | switch(level) { | ||
995 | case SOL_RAW: | ||
996 | break; | ||
997 | |||
998 | case SOL_ICMPV6: | ||
999 | if (inet_sk(sk)->num != IPPROTO_ICMPV6) | ||
1000 | return -EOPNOTSUPP; | ||
1001 | return rawv6_geticmpfilter(sk, level, optname, optval, | ||
1002 | optlen); | ||
1003 | case SOL_IPV6: | ||
1004 | if (optname == IPV6_CHECKSUM) | ||
1005 | break; | ||
1006 | default: | ||
1007 | return compat_ipv6_getsockopt(sk, level, | ||
1008 | optname, optval, optlen); | ||
1009 | }; | ||
1010 | return do_rawv6_getsockopt(sk, level, optname, optval, optlen); | ||
1011 | } | ||
1012 | #endif | ||
1013 | |||
956 | static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) | 1014 | static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) |
957 | { | 1015 | { |
958 | switch(cmd) { | 1016 | switch(cmd) { |
@@ -1008,6 +1066,10 @@ struct proto rawv6_prot = { | |||
1008 | .destroy = inet6_destroy_sock, | 1066 | .destroy = inet6_destroy_sock, |
1009 | .setsockopt = rawv6_setsockopt, | 1067 | .setsockopt = rawv6_setsockopt, |
1010 | .getsockopt = rawv6_getsockopt, | 1068 | .getsockopt = rawv6_getsockopt, |
1069 | #ifdef CONFIG_COMPAT | ||
1070 | .compat_setsockopt = compat_rawv6_setsockopt, | ||
1071 | .compat_getsockopt = compat_rawv6_getsockopt, | ||
1072 | #endif | ||
1011 | .sendmsg = rawv6_sendmsg, | 1073 | .sendmsg = rawv6_sendmsg, |
1012 | .recvmsg = rawv6_recvmsg, | 1074 | .recvmsg = rawv6_recvmsg, |
1013 | .bind = rawv6_bind, | 1075 | .bind = rawv6_bind, |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index af6a0c60f903..2f8975e0150a 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -1308,6 +1308,10 @@ static struct inet_connection_sock_af_ops ipv6_specific = { | |||
1308 | 1308 | ||
1309 | .setsockopt = ipv6_setsockopt, | 1309 | .setsockopt = ipv6_setsockopt, |
1310 | .getsockopt = ipv6_getsockopt, | 1310 | .getsockopt = ipv6_getsockopt, |
1311 | #ifdef CONFIG_COMPAT | ||
1312 | .compat_setsockopt = compat_ipv6_setsockopt, | ||
1313 | .compat_getsockopt = compat_ipv6_getsockopt, | ||
1314 | #endif | ||
1311 | .addr2sockaddr = inet6_csk_addr2sockaddr, | 1315 | .addr2sockaddr = inet6_csk_addr2sockaddr, |
1312 | .sockaddr_len = sizeof(struct sockaddr_in6) | 1316 | .sockaddr_len = sizeof(struct sockaddr_in6) |
1313 | }; | 1317 | }; |
@@ -1327,6 +1331,10 @@ static struct inet_connection_sock_af_ops ipv6_mapped = { | |||
1327 | 1331 | ||
1328 | .setsockopt = ipv6_setsockopt, | 1332 | .setsockopt = ipv6_setsockopt, |
1329 | .getsockopt = ipv6_getsockopt, | 1333 | .getsockopt = ipv6_getsockopt, |
1334 | #ifdef CONFIG_COMPAT | ||
1335 | .compat_setsockopt = compat_ipv6_setsockopt, | ||
1336 | .compat_getsockopt = compat_ipv6_getsockopt, | ||
1337 | #endif | ||
1330 | .addr2sockaddr = inet6_csk_addr2sockaddr, | 1338 | .addr2sockaddr = inet6_csk_addr2sockaddr, |
1331 | .sockaddr_len = sizeof(struct sockaddr_in6) | 1339 | .sockaddr_len = sizeof(struct sockaddr_in6) |
1332 | }; | 1340 | }; |
@@ -1566,6 +1574,10 @@ struct proto tcpv6_prot = { | |||
1566 | .shutdown = tcp_shutdown, | 1574 | .shutdown = tcp_shutdown, |
1567 | .setsockopt = tcp_setsockopt, | 1575 | .setsockopt = tcp_setsockopt, |
1568 | .getsockopt = tcp_getsockopt, | 1576 | .getsockopt = tcp_getsockopt, |
1577 | #ifdef CONFIG_COMPAT | ||
1578 | .compat_setsockopt = compat_tcp_setsockopt, | ||
1579 | .compat_getsockopt = compat_tcp_getsockopt, | ||
1580 | #endif | ||
1569 | .sendmsg = tcp_sendmsg, | 1581 | .sendmsg = tcp_sendmsg, |
1570 | .recvmsg = tcp_recvmsg, | 1582 | .recvmsg = tcp_recvmsg, |
1571 | .backlog_rcv = tcp_v6_do_rcv, | 1583 | .backlog_rcv = tcp_v6_do_rcv, |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index c47648892c04..538ada00646a 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -880,16 +880,13 @@ static int udpv6_destroy_sock(struct sock *sk) | |||
880 | /* | 880 | /* |
881 | * Socket option code for UDP | 881 | * Socket option code for UDP |
882 | */ | 882 | */ |
883 | static int udpv6_setsockopt(struct sock *sk, int level, int optname, | 883 | static int do_udpv6_setsockopt(struct sock *sk, int level, int optname, |
884 | char __user *optval, int optlen) | 884 | char __user *optval, int optlen) |
885 | { | 885 | { |
886 | struct udp_sock *up = udp_sk(sk); | 886 | struct udp_sock *up = udp_sk(sk); |
887 | int val; | 887 | int val; |
888 | int err = 0; | 888 | int err = 0; |
889 | 889 | ||
890 | if (level != SOL_UDP) | ||
891 | return ipv6_setsockopt(sk, level, optname, optval, optlen); | ||
892 | |||
893 | if(optlen<sizeof(int)) | 890 | if(optlen<sizeof(int)) |
894 | return -EINVAL; | 891 | return -EINVAL; |
895 | 892 | ||
@@ -927,15 +924,31 @@ static int udpv6_setsockopt(struct sock *sk, int level, int optname, | |||
927 | return err; | 924 | return err; |
928 | } | 925 | } |
929 | 926 | ||
930 | static int udpv6_getsockopt(struct sock *sk, int level, int optname, | 927 | static int udpv6_setsockopt(struct sock *sk, int level, int optname, |
928 | char __user *optval, int optlen) | ||
929 | { | ||
930 | if (level != SOL_UDP) | ||
931 | return ipv6_setsockopt(sk, level, optname, optval, optlen); | ||
932 | return do_udpv6_setsockopt(sk, level, optname, optval, optlen); | ||
933 | } | ||
934 | |||
935 | #ifdef CONFIG_COMPAT | ||
936 | static int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, | ||
937 | char __user *optval, int optlen) | ||
938 | { | ||
939 | if (level != SOL_UDP) | ||
940 | return compat_ipv6_setsockopt(sk, level, | ||
941 | optname, optval, optlen); | ||
942 | return do_udpv6_setsockopt(sk, level, optname, optval, optlen); | ||
943 | } | ||
944 | #endif | ||
945 | |||
946 | static int do_udpv6_getsockopt(struct sock *sk, int level, int optname, | ||
931 | char __user *optval, int __user *optlen) | 947 | char __user *optval, int __user *optlen) |
932 | { | 948 | { |
933 | struct udp_sock *up = udp_sk(sk); | 949 | struct udp_sock *up = udp_sk(sk); |
934 | int val, len; | 950 | int val, len; |
935 | 951 | ||
936 | if (level != SOL_UDP) | ||
937 | return ipv6_getsockopt(sk, level, optname, optval, optlen); | ||
938 | |||
939 | if(get_user(len,optlen)) | 952 | if(get_user(len,optlen)) |
940 | return -EFAULT; | 953 | return -EFAULT; |
941 | 954 | ||
@@ -964,6 +977,25 @@ static int udpv6_getsockopt(struct sock *sk, int level, int optname, | |||
964 | return 0; | 977 | return 0; |
965 | } | 978 | } |
966 | 979 | ||
980 | static int udpv6_getsockopt(struct sock *sk, int level, int optname, | ||
981 | char __user *optval, int __user *optlen) | ||
982 | { | ||
983 | if (level != SOL_UDP) | ||
984 | return ipv6_getsockopt(sk, level, optname, optval, optlen); | ||
985 | return do_udpv6_getsockopt(sk, level, optname, optval, optlen); | ||
986 | } | ||
987 | |||
988 | #ifdef CONFIG_COMPAT | ||
989 | static int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, | ||
990 | char __user *optval, int __user *optlen) | ||
991 | { | ||
992 | if (level != SOL_UDP) | ||
993 | return compat_ipv6_getsockopt(sk, level, | ||
994 | optname, optval, optlen); | ||
995 | return do_udpv6_getsockopt(sk, level, optname, optval, optlen); | ||
996 | } | ||
997 | #endif | ||
998 | |||
967 | static struct inet6_protocol udpv6_protocol = { | 999 | static struct inet6_protocol udpv6_protocol = { |
968 | .handler = udpv6_rcv, | 1000 | .handler = udpv6_rcv, |
969 | .err_handler = udpv6_err, | 1001 | .err_handler = udpv6_err, |
@@ -1046,6 +1078,10 @@ struct proto udpv6_prot = { | |||
1046 | .destroy = udpv6_destroy_sock, | 1078 | .destroy = udpv6_destroy_sock, |
1047 | .setsockopt = udpv6_setsockopt, | 1079 | .setsockopt = udpv6_setsockopt, |
1048 | .getsockopt = udpv6_getsockopt, | 1080 | .getsockopt = udpv6_getsockopt, |
1081 | #ifdef CONFIG_COMPAT | ||
1082 | .compat_setsockopt = compat_udpv6_setsockopt, | ||
1083 | .compat_getsockopt = compat_udpv6_getsockopt, | ||
1084 | #endif | ||
1049 | .sendmsg = udpv6_sendmsg, | 1085 | .sendmsg = udpv6_sendmsg, |
1050 | .recvmsg = udpv6_recvmsg, | 1086 | .recvmsg = udpv6_recvmsg, |
1051 | .backlog_rcv = udpv6_queue_rcv_skb, | 1087 | .backlog_rcv = udpv6_queue_rcv_skb, |
diff --git a/net/netfilter/nf_sockopt.c b/net/netfilter/nf_sockopt.c index 0e5c5e204799..da1cd48de216 100644 --- a/net/netfilter/nf_sockopt.c +++ b/net/netfilter/nf_sockopt.c | |||
@@ -131,3 +131,72 @@ int nf_getsockopt(struct sock *sk, int pf, int val, char __user *opt, int *len) | |||
131 | } | 131 | } |
132 | EXPORT_SYMBOL(nf_getsockopt); | 132 | EXPORT_SYMBOL(nf_getsockopt); |
133 | 133 | ||
134 | #ifdef CONFIG_COMPAT | ||
135 | static int compat_nf_sockopt(struct sock *sk, int pf, int val, | ||
136 | char __user *opt, int *len, int get) | ||
137 | { | ||
138 | struct list_head *i; | ||
139 | struct nf_sockopt_ops *ops; | ||
140 | int ret; | ||
141 | |||
142 | if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) | ||
143 | return -EINTR; | ||
144 | |||
145 | list_for_each(i, &nf_sockopts) { | ||
146 | ops = (struct nf_sockopt_ops *)i; | ||
147 | if (ops->pf == pf) { | ||
148 | if (get) { | ||
149 | if (val >= ops->get_optmin | ||
150 | && val < ops->get_optmax) { | ||
151 | ops->use++; | ||
152 | mutex_unlock(&nf_sockopt_mutex); | ||
153 | if (ops->compat_get) | ||
154 | ret = ops->compat_get(sk, | ||
155 | val, opt, len); | ||
156 | else | ||
157 | ret = ops->get(sk, | ||
158 | val, opt, len); | ||
159 | goto out; | ||
160 | } | ||
161 | } else { | ||
162 | if (val >= ops->set_optmin | ||
163 | && val < ops->set_optmax) { | ||
164 | ops->use++; | ||
165 | mutex_unlock(&nf_sockopt_mutex); | ||
166 | if (ops->compat_set) | ||
167 | ret = ops->compat_set(sk, | ||
168 | val, opt, *len); | ||
169 | else | ||
170 | ret = ops->set(sk, | ||
171 | val, opt, *len); | ||
172 | goto out; | ||
173 | } | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | mutex_unlock(&nf_sockopt_mutex); | ||
178 | return -ENOPROTOOPT; | ||
179 | |||
180 | out: | ||
181 | mutex_lock(&nf_sockopt_mutex); | ||
182 | ops->use--; | ||
183 | if (ops->cleanup_task) | ||
184 | wake_up_process(ops->cleanup_task); | ||
185 | mutex_unlock(&nf_sockopt_mutex); | ||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | int compat_nf_setsockopt(struct sock *sk, int pf, | ||
190 | int val, char __user *opt, int len) | ||
191 | { | ||
192 | return compat_nf_sockopt(sk, pf, val, opt, &len, 0); | ||
193 | } | ||
194 | EXPORT_SYMBOL(compat_nf_setsockopt); | ||
195 | |||
196 | int compat_nf_getsockopt(struct sock *sk, int pf, | ||
197 | int val, char __user *opt, int *len) | ||
198 | { | ||
199 | return compat_nf_sockopt(sk, pf, val, opt, len, 1); | ||
200 | } | ||
201 | EXPORT_SYMBOL(compat_nf_getsockopt); | ||
202 | #endif | ||
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 2e266129a764..bbee14d01c9b 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
@@ -875,6 +875,10 @@ static const struct proto_ops inet6_seqpacket_ops = { | |||
875 | .shutdown = inet_shutdown, | 875 | .shutdown = inet_shutdown, |
876 | .setsockopt = sock_common_setsockopt, | 876 | .setsockopt = sock_common_setsockopt, |
877 | .getsockopt = sock_common_getsockopt, | 877 | .getsockopt = sock_common_getsockopt, |
878 | #ifdef CONFIG_COMPAT | ||
879 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
880 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
881 | #endif | ||
878 | .sendmsg = inet_sendmsg, | 882 | .sendmsg = inet_sendmsg, |
879 | .recvmsg = sock_common_recvmsg, | 883 | .recvmsg = sock_common_recvmsg, |
880 | .mmap = sock_no_mmap, | 884 | .mmap = sock_no_mmap, |
@@ -914,6 +918,10 @@ static struct sctp_af sctp_ipv6_specific = { | |||
914 | .sctp_xmit = sctp_v6_xmit, | 918 | .sctp_xmit = sctp_v6_xmit, |
915 | .setsockopt = ipv6_setsockopt, | 919 | .setsockopt = ipv6_setsockopt, |
916 | .getsockopt = ipv6_getsockopt, | 920 | .getsockopt = ipv6_getsockopt, |
921 | #ifdef CONFIG_COMPAT | ||
922 | .compat_setsockopt = compat_ipv6_setsockopt, | ||
923 | .compat_getsockopt = compat_ipv6_getsockopt, | ||
924 | #endif | ||
917 | .get_dst = sctp_v6_get_dst, | 925 | .get_dst = sctp_v6_get_dst, |
918 | .get_saddr = sctp_v6_get_saddr, | 926 | .get_saddr = sctp_v6_get_saddr, |
919 | .copy_addrlist = sctp_v6_copy_addrlist, | 927 | .copy_addrlist = sctp_v6_copy_addrlist, |
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index de693b43c8ea..d90f5491870f 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c | |||
@@ -845,6 +845,10 @@ static const struct proto_ops inet_seqpacket_ops = { | |||
845 | .shutdown = inet_shutdown, /* Looks harmless. */ | 845 | .shutdown = inet_shutdown, /* Looks harmless. */ |
846 | .setsockopt = sock_common_setsockopt, /* IP_SOL IP_OPTION is a problem. */ | 846 | .setsockopt = sock_common_setsockopt, /* IP_SOL IP_OPTION is a problem. */ |
847 | .getsockopt = sock_common_getsockopt, | 847 | .getsockopt = sock_common_getsockopt, |
848 | #ifdef CONFIG_COMPAT | ||
849 | .compat_setsockopt = compat_sock_common_setsockopt, | ||
850 | .compat_getsockopt = compat_sock_common_getsockopt, | ||
851 | #endif | ||
848 | .sendmsg = inet_sendmsg, | 852 | .sendmsg = inet_sendmsg, |
849 | .recvmsg = sock_common_recvmsg, | 853 | .recvmsg = sock_common_recvmsg, |
850 | .mmap = sock_no_mmap, | 854 | .mmap = sock_no_mmap, |
@@ -883,6 +887,10 @@ static struct sctp_af sctp_ipv4_specific = { | |||
883 | .sctp_xmit = sctp_v4_xmit, | 887 | .sctp_xmit = sctp_v4_xmit, |
884 | .setsockopt = ip_setsockopt, | 888 | .setsockopt = ip_setsockopt, |
885 | .getsockopt = ip_getsockopt, | 889 | .getsockopt = ip_getsockopt, |
890 | #ifdef CONFIG_COMPAT | ||
891 | .compat_setsockopt = compat_ip_setsockopt, | ||
892 | .compat_getsockopt = compat_ip_getsockopt, | ||
893 | #endif | ||
886 | .get_dst = sctp_v4_get_dst, | 894 | .get_dst = sctp_v4_get_dst, |
887 | .get_saddr = sctp_v4_get_saddr, | 895 | .get_saddr = sctp_v4_get_saddr, |
888 | .copy_addrlist = sctp_v4_copy_addrlist, | 896 | .copy_addrlist = sctp_v4_copy_addrlist, |