aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/net.h4
-rw-r--r--include/linux/netfilter.h9
-rw-r--r--include/net/inet_connection_sock.h6
-rw-r--r--include/net/ip.h4
-rw-r--r--include/net/ipv6.h10
-rw-r--r--include/net/sctp/structs.h10
-rw-r--r--include/net/sock.h12
-rw-r--r--include/net/tcp.h6
-rw-r--r--net/compat.c95
-rw-r--r--net/core/sock.c28
-rw-r--r--net/dccp/dccp.h8
-rw-r--r--net/dccp/ipv4.c12
-rw-r--r--net/dccp/ipv6.c16
-rw-r--r--net/dccp/proto.c67
-rw-r--r--net/ipv4/af_inet.c12
-rw-r--r--net/ipv4/ip_sockglue.c142
-rw-r--r--net/ipv4/raw.c50
-rw-r--r--net/ipv4/tcp.c77
-rw-r--r--net/ipv4/tcp_ipv4.c8
-rw-r--r--net/ipv4/udp.c51
-rw-r--r--net/ipv6/af_inet6.c12
-rw-r--r--net/ipv6/ipv6_sockglue.c163
-rw-r--r--net/ipv6/ipv6_syms.c4
-rw-r--r--net/ipv6/raw.c112
-rw-r--r--net/ipv6/tcp_ipv6.c12
-rw-r--r--net/ipv6/udp.c52
-rw-r--r--net/netfilter/nf_sockopt.c69
-rw-r--r--net/sctp/ipv6.c8
-rw-r--r--net/sctp/protocol.c8
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,
246int nf_getsockopt(struct sock *sk, int pf, int optval, char __user *opt, 250int nf_getsockopt(struct sock *sk, int pf, int optval, char __user *opt,
247 int *len); 251 int *len);
248 252
253int compat_nf_setsockopt(struct sock *sk, int pf, int optval,
254 char __user *opt, int len);
255int compat_nf_getsockopt(struct sock *sk, int pf, int optval,
256 char __user *opt, int *len);
257
249/* Packet queuing */ 258/* Packet queuing */
250struct nf_queue_handler { 259struct 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);
356extern int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc); 356extern int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc);
357extern int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen); 357extern int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen);
358extern int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); 358extern int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen);
359extern int compat_ip_setsockopt(struct sock *sk, int level,
360 int optname, char __user *optval, int optlen);
361extern int compat_ip_getsockopt(struct sock *sk, int level,
362 int optname, char __user *optval, int __user *optlen);
359extern int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *)); 363extern int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *));
360 364
361extern int ip_recv_error(struct sock *sk, struct msghdr *msg, int len); 365extern 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);
523extern int compat_ipv6_setsockopt(struct sock *sk,
524 int level,
525 int optname,
526 char __user *optval,
527 int optlen);
528extern int compat_ipv6_getsockopt(struct sock *sk,
529 int level,
530 int optname,
531 char __user *optval,
532 int __user *optlen);
523 533
524extern void ipv6_packet_init(void); 534extern 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);
817extern int sock_common_setsockopt(struct socket *sock, int level, int optname, 825extern int sock_common_setsockopt(struct socket *sock, int level, int optname,
818 char __user *optval, int optlen); 826 char __user *optval, int optlen);
827extern int compat_sock_common_getsockopt(struct socket *sock, int level,
828 int optname, char __user *optval, int __user *optlen);
829extern int compat_sock_common_setsockopt(struct socket *sock, int level,
830 int optname, char __user *optval, int optlen);
819 831
820extern void sk_common_release(struct sock *sk); 832extern 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,
353extern int tcp_setsockopt(struct sock *sk, int level, 353extern 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);
356extern int compat_tcp_getsockopt(struct sock *sk,
357 int level, int optname,
358 char __user *optval, int __user *optlen);
359extern int compat_tcp_setsockopt(struct sock *sk,
360 int level, int optname,
361 char __user *optval, int optlen);
356extern void tcp_set_keepalive(struct sock *sk, int val); 362extern void tcp_set_keepalive(struct sock *sk, int val);
357extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, 363extern 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
419static int do_set_attach_filter(int fd, int level, int optname, 419static 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
439static int do_set_sock_timeout(int fd, int level, int optname, char __user *optval, int optlen) 439static 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
461static 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
460asmlinkage long compat_sys_setsockopt(int fd, int level, int optname, 473asmlinkage 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
477static int do_get_sock_timeout(int fd, int level, int optname, 509static 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
506asmlinkage long compat_sys_getsockopt(int fd, int level, int optname, 538static 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
546asmlinkage 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))
517static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), 576static 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
1386EXPORT_SYMBOL(sock_common_getsockopt); 1386EXPORT_SYMBOL(sock_common_getsockopt);
1387 1387
1388#ifdef CONFIG_COMPAT
1389int 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}
1399EXPORT_SYMBOL(compat_sock_common_getsockopt);
1400#endif
1401
1388int sock_common_recvmsg(struct kiocb *iocb, struct socket *sock, 1402int 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
1415EXPORT_SYMBOL(sock_common_setsockopt); 1429EXPORT_SYMBOL(sock_common_setsockopt);
1416 1430
1431#ifdef CONFIG_COMPAT
1432int 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}
1442EXPORT_SYMBOL(compat_sock_common_setsockopt);
1443#endif
1444
1417void sk_common_release(struct sock *sk) 1445void 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);
193extern int dccp_setsockopt(struct sock *sk, int level, int optname, 193extern 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
196extern int compat_dccp_getsockopt(struct sock *sk,
197 int level, int optname,
198 char __user *optval, int __user *optlen);
199extern int compat_dccp_setsockopt(struct sock *sk,
200 int level, int optname,
201 char __user *optval, int optlen);
202#endif
195extern int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg); 203extern int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg);
196extern int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, 204extern 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
458int dccp_setsockopt(struct sock *sk, int level, int optname, 458static 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
510int 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}
515EXPORT_SYMBOL_GPL(dccp_setsockopt); 519EXPORT_SYMBOL_GPL(dccp_setsockopt);
516 520
521#ifdef CONFIG_COMPAT
522int 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}
535EXPORT_SYMBOL_GPL(compat_dccp_setsockopt);
536#endif
537
517static int dccp_getsockopt_service(struct sock *sk, int len, 538static 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
548int dccp_getsockopt(struct sock *sk, int level, int optname, 569static 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
607int 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}
590EXPORT_SYMBOL_GPL(dccp_getsockopt); 616EXPORT_SYMBOL_GPL(dccp_getsockopt);
591 617
618#ifdef CONFIG_COMPAT
619int 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}
632EXPORT_SYMBOL_GPL(compat_dccp_getsockopt);
633#endif
634
592int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, 635int 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
402int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) 402static 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
887int 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
913int 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
899int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) 945static 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
1152int 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
1183int 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
1114EXPORT_SYMBOL(ip_cmsg_recv); 1214EXPORT_SYMBOL(ip_cmsg_recv);
1115 1215
1116EXPORT_SYMBOL(ip_getsockopt); 1216EXPORT_SYMBOL(ip_getsockopt);
1117EXPORT_SYMBOL(ip_setsockopt); 1217EXPORT_SYMBOL(ip_setsockopt);
1218#ifdef CONFIG_COMPAT
1219EXPORT_SYMBOL(compat_ip_getsockopt);
1220EXPORT_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
660out: return ret; 660out: return ret;
661} 661}
662 662
663static int raw_setsockopt(struct sock *sk, int level, int optname, 663static 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
678static int raw_getsockopt(struct sock *sk, int level, int optname, 675static 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
684static 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
694static 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
706static 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
715static 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
693static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg) 725static 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 */
1690int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, 1690static 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
1870int 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
1882int 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. */
1875void tcp_get_info(struct sock *sk, struct tcp_info *info) 1900void 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
1932EXPORT_SYMBOL_GPL(tcp_get_info); 1957EXPORT_SYMBOL_GPL(tcp_get_info);
1933 1958
1934int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, 1959static 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
2049int 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
2061int 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
2029extern void __skb_cb_too_small_for_tcp(int, int); 2078extern void __skb_cb_too_small_for_tcp(int, int);
2030extern struct tcp_congestion_ops tcp_reno; 2079extern struct tcp_congestion_ops tcp_reno;
@@ -2142,3 +2191,7 @@ EXPORT_SYMBOL(tcp_sendpage);
2142EXPORT_SYMBOL(tcp_setsockopt); 2191EXPORT_SYMBOL(tcp_setsockopt);
2143EXPORT_SYMBOL(tcp_shutdown); 2192EXPORT_SYMBOL(tcp_shutdown);
2144EXPORT_SYMBOL(tcp_statistics); 2193EXPORT_SYMBOL(tcp_statistics);
2194#ifdef CONFIG_COMPAT
2195EXPORT_SYMBOL(compat_tcp_setsockopt);
2196EXPORT_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 */
1210static int udp_setsockopt(struct sock *sk, int level, int optname, 1210static 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
1259static int udp_getsockopt(struct sock *sk, int level, int optname, 1256static 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
1265static 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
1275static 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
1309static 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
1318static 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
112int ipv6_setsockopt(struct sock *sk, int level, int optname, 112static 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
626out:
627 return retv; 613 return retv;
628 614
629e_inval: 615e_inval:
@@ -631,6 +617,65 @@ e_inval:
631 return -EINVAL; 617 return -EINVAL;
632} 618}
633 619
620int 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
647int 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
634static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr, 679static 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
645int ipv6_getsockopt(struct sock *sk, int level, int optname, 690static 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
896int 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
929int 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
865void __init ipv6_packet_init(void) 968void __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);
18EXPORT_SYMBOL(addrconf_lock); 18EXPORT_SYMBOL(addrconf_lock);
19EXPORT_SYMBOL(ipv6_setsockopt); 19EXPORT_SYMBOL(ipv6_setsockopt);
20EXPORT_SYMBOL(ipv6_getsockopt); 20EXPORT_SYMBOL(ipv6_getsockopt);
21#ifdef CONFIG_COMPAT
22EXPORT_SYMBOL(compat_ipv6_setsockopt);
23EXPORT_SYMBOL(compat_ipv6_getsockopt);
24#endif
21EXPORT_SYMBOL(inet6_register_protosw); 25EXPORT_SYMBOL(inet6_register_protosw);
22EXPORT_SYMBOL(inet6_unregister_protosw); 26EXPORT_SYMBOL(inet6_unregister_protosw);
23EXPORT_SYMBOL(inet6_add_protocol); 27EXPORT_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
862static int rawv6_setsockopt(struct sock *sk, int level, int optname, 862static 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
909static int rawv6_getsockopt(struct sock *sk, int level, int optname, 892static 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
915static 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
938static 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
968static 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
991static 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
956static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) 1014static 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 */
883static int udpv6_setsockopt(struct sock *sk, int level, int optname, 883static 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
930static int udpv6_getsockopt(struct sock *sk, int level, int optname, 927static 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
936static 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
946static 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
980static 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
989static 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
967static struct inet6_protocol udpv6_protocol = { 999static 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}
132EXPORT_SYMBOL(nf_getsockopt); 132EXPORT_SYMBOL(nf_getsockopt);
133 133
134#ifdef CONFIG_COMPAT
135static 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
189int 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}
194EXPORT_SYMBOL(compat_nf_setsockopt);
195
196int 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}
201EXPORT_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,