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 /net/compat.c | |
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>
Diffstat (limited to 'net/compat.c')
-rw-r--r-- | net/compat.c | 95 |
1 files changed, 77 insertions, 18 deletions
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), |