diff options
Diffstat (limited to 'net/netlink/af_netlink.c')
| -rw-r--r-- | net/netlink/af_netlink.c | 312 |
1 files changed, 247 insertions, 65 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index ff774a06c89d..62435ffc6184 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
| @@ -13,7 +13,12 @@ | |||
| 13 | * added netlink_proto_exit | 13 | * added netlink_proto_exit |
| 14 | * Tue Jan 22 18:32:44 BRST 2002 Arnaldo C. de Melo <acme@conectiva.com.br> | 14 | * Tue Jan 22 18:32:44 BRST 2002 Arnaldo C. de Melo <acme@conectiva.com.br> |
| 15 | * use nlk_sk, as sk->protinfo is on a diet 8) | 15 | * use nlk_sk, as sk->protinfo is on a diet 8) |
| 16 | * | 16 | * Fri Jul 22 19:51:12 MEST 2005 Harald Welte <laforge@gnumonks.org> |
| 17 | * - inc module use count of module that owns | ||
| 18 | * the kernel socket in case userspace opens | ||
| 19 | * socket of same protocol | ||
| 20 | * - remove all module support, since netlink is | ||
| 21 | * mandatory if CONFIG_NET=y these days | ||
| 17 | */ | 22 | */ |
| 18 | 23 | ||
| 19 | #include <linux/config.h> | 24 | #include <linux/config.h> |
| @@ -55,21 +60,29 @@ | |||
| 55 | #include <net/scm.h> | 60 | #include <net/scm.h> |
| 56 | 61 | ||
| 57 | #define Nprintk(a...) | 62 | #define Nprintk(a...) |
| 63 | #define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) | ||
| 58 | 64 | ||
| 59 | struct netlink_sock { | 65 | struct netlink_sock { |
| 60 | /* struct sock has to be the first member of netlink_sock */ | 66 | /* struct sock has to be the first member of netlink_sock */ |
| 61 | struct sock sk; | 67 | struct sock sk; |
| 62 | u32 pid; | 68 | u32 pid; |
| 63 | unsigned int groups; | ||
| 64 | u32 dst_pid; | 69 | u32 dst_pid; |
| 65 | unsigned int dst_groups; | 70 | u32 dst_group; |
| 71 | u32 flags; | ||
| 72 | u32 subscriptions; | ||
| 73 | u32 ngroups; | ||
| 74 | unsigned long *groups; | ||
| 66 | unsigned long state; | 75 | unsigned long state; |
| 67 | wait_queue_head_t wait; | 76 | wait_queue_head_t wait; |
| 68 | struct netlink_callback *cb; | 77 | struct netlink_callback *cb; |
| 69 | spinlock_t cb_lock; | 78 | spinlock_t cb_lock; |
| 70 | void (*data_ready)(struct sock *sk, int bytes); | 79 | void (*data_ready)(struct sock *sk, int bytes); |
| 80 | struct module *module; | ||
| 71 | }; | 81 | }; |
| 72 | 82 | ||
| 83 | #define NETLINK_KERNEL_SOCKET 0x1 | ||
| 84 | #define NETLINK_RECV_PKTINFO 0x2 | ||
| 85 | |||
| 73 | static inline struct netlink_sock *nlk_sk(struct sock *sk) | 86 | static inline struct netlink_sock *nlk_sk(struct sock *sk) |
| 74 | { | 87 | { |
| 75 | return (struct netlink_sock *)sk; | 88 | return (struct netlink_sock *)sk; |
| @@ -92,6 +105,9 @@ struct netlink_table { | |||
| 92 | struct nl_pid_hash hash; | 105 | struct nl_pid_hash hash; |
| 93 | struct hlist_head mc_list; | 106 | struct hlist_head mc_list; |
| 94 | unsigned int nl_nonroot; | 107 | unsigned int nl_nonroot; |
| 108 | unsigned int groups; | ||
| 109 | struct module *module; | ||
| 110 | int registered; | ||
| 95 | }; | 111 | }; |
| 96 | 112 | ||
| 97 | static struct netlink_table *nl_table; | 113 | static struct netlink_table *nl_table; |
| @@ -106,6 +122,11 @@ static atomic_t nl_table_users = ATOMIC_INIT(0); | |||
| 106 | 122 | ||
| 107 | static struct notifier_block *netlink_chain; | 123 | static struct notifier_block *netlink_chain; |
| 108 | 124 | ||
| 125 | static u32 netlink_group_mask(u32 group) | ||
| 126 | { | ||
| 127 | return group ? 1 << (group - 1) : 0; | ||
| 128 | } | ||
| 129 | |||
| 109 | static struct hlist_head *nl_pid_hashfn(struct nl_pid_hash *hash, u32 pid) | 130 | static struct hlist_head *nl_pid_hashfn(struct nl_pid_hash *hash, u32 pid) |
| 110 | { | 131 | { |
| 111 | return &hash->table[jhash_1word(pid, hash->rnd) & hash->mask]; | 132 | return &hash->table[jhash_1word(pid, hash->rnd) & hash->mask]; |
| @@ -122,6 +143,7 @@ static void netlink_sock_destruct(struct sock *sk) | |||
| 122 | BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc)); | 143 | BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc)); |
| 123 | BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc)); | 144 | BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc)); |
| 124 | BUG_TRAP(!nlk_sk(sk)->cb); | 145 | BUG_TRAP(!nlk_sk(sk)->cb); |
| 146 | BUG_TRAP(!nlk_sk(sk)->groups); | ||
| 125 | } | 147 | } |
| 126 | 148 | ||
| 127 | /* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on SMP. | 149 | /* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on SMP. |
| @@ -317,7 +339,7 @@ static void netlink_remove(struct sock *sk) | |||
| 317 | netlink_table_grab(); | 339 | netlink_table_grab(); |
| 318 | if (sk_del_node_init(sk)) | 340 | if (sk_del_node_init(sk)) |
| 319 | nl_table[sk->sk_protocol].hash.entries--; | 341 | nl_table[sk->sk_protocol].hash.entries--; |
| 320 | if (nlk_sk(sk)->groups) | 342 | if (nlk_sk(sk)->subscriptions) |
| 321 | __sk_del_bind_node(sk); | 343 | __sk_del_bind_node(sk); |
| 322 | netlink_table_ungrab(); | 344 | netlink_table_ungrab(); |
| 323 | } | 345 | } |
| @@ -328,19 +350,11 @@ static struct proto netlink_proto = { | |||
| 328 | .obj_size = sizeof(struct netlink_sock), | 350 | .obj_size = sizeof(struct netlink_sock), |
| 329 | }; | 351 | }; |
| 330 | 352 | ||
| 331 | static int netlink_create(struct socket *sock, int protocol) | 353 | static int __netlink_create(struct socket *sock, int protocol) |
| 332 | { | 354 | { |
| 333 | struct sock *sk; | 355 | struct sock *sk; |
| 334 | struct netlink_sock *nlk; | 356 | struct netlink_sock *nlk; |
| 335 | 357 | ||
| 336 | sock->state = SS_UNCONNECTED; | ||
| 337 | |||
| 338 | if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) | ||
| 339 | return -ESOCKTNOSUPPORT; | ||
| 340 | |||
| 341 | if (protocol<0 || protocol >= MAX_LINKS) | ||
| 342 | return -EPROTONOSUPPORT; | ||
| 343 | |||
| 344 | sock->ops = &netlink_ops; | 358 | sock->ops = &netlink_ops; |
| 345 | 359 | ||
| 346 | sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1); | 360 | sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1); |
| @@ -350,15 +364,67 @@ static int netlink_create(struct socket *sock, int protocol) | |||
| 350 | sock_init_data(sock, sk); | 364 | sock_init_data(sock, sk); |
| 351 | 365 | ||
| 352 | nlk = nlk_sk(sk); | 366 | nlk = nlk_sk(sk); |
| 353 | |||
| 354 | spin_lock_init(&nlk->cb_lock); | 367 | spin_lock_init(&nlk->cb_lock); |
| 355 | init_waitqueue_head(&nlk->wait); | 368 | init_waitqueue_head(&nlk->wait); |
| 356 | sk->sk_destruct = netlink_sock_destruct; | ||
| 357 | 369 | ||
| 370 | sk->sk_destruct = netlink_sock_destruct; | ||
| 358 | sk->sk_protocol = protocol; | 371 | sk->sk_protocol = protocol; |
| 359 | return 0; | 372 | return 0; |
| 360 | } | 373 | } |
| 361 | 374 | ||
| 375 | static int netlink_create(struct socket *sock, int protocol) | ||
| 376 | { | ||
| 377 | struct module *module = NULL; | ||
| 378 | struct netlink_sock *nlk; | ||
| 379 | unsigned int groups; | ||
| 380 | int err = 0; | ||
| 381 | |||
| 382 | sock->state = SS_UNCONNECTED; | ||
| 383 | |||
| 384 | if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) | ||
| 385 | return -ESOCKTNOSUPPORT; | ||
| 386 | |||
| 387 | if (protocol<0 || protocol >= MAX_LINKS) | ||
| 388 | return -EPROTONOSUPPORT; | ||
| 389 | |||
| 390 | netlink_lock_table(); | ||
| 391 | #ifdef CONFIG_KMOD | ||
| 392 | if (!nl_table[protocol].registered) { | ||
| 393 | netlink_unlock_table(); | ||
| 394 | request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol); | ||
| 395 | netlink_lock_table(); | ||
| 396 | } | ||
| 397 | #endif | ||
| 398 | if (nl_table[protocol].registered && | ||
| 399 | try_module_get(nl_table[protocol].module)) | ||
| 400 | module = nl_table[protocol].module; | ||
| 401 | else | ||
| 402 | err = -EPROTONOSUPPORT; | ||
| 403 | groups = nl_table[protocol].groups; | ||
| 404 | netlink_unlock_table(); | ||
| 405 | |||
| 406 | if (err || (err = __netlink_create(sock, protocol) < 0)) | ||
| 407 | goto out_module; | ||
| 408 | |||
| 409 | nlk = nlk_sk(sock->sk); | ||
| 410 | |||
| 411 | nlk->groups = kmalloc(NLGRPSZ(groups), GFP_KERNEL); | ||
| 412 | if (nlk->groups == NULL) { | ||
| 413 | err = -ENOMEM; | ||
| 414 | goto out_module; | ||
| 415 | } | ||
| 416 | memset(nlk->groups, 0, NLGRPSZ(groups)); | ||
| 417 | nlk->ngroups = groups; | ||
| 418 | |||
| 419 | nlk->module = module; | ||
| 420 | out: | ||
| 421 | return err; | ||
| 422 | |||
| 423 | out_module: | ||
| 424 | module_put(module); | ||
| 425 | goto out; | ||
| 426 | } | ||
| 427 | |||
| 362 | static int netlink_release(struct socket *sock) | 428 | static int netlink_release(struct socket *sock) |
| 363 | { | 429 | { |
| 364 | struct sock *sk = sock->sk; | 430 | struct sock *sk = sock->sk; |
| @@ -387,14 +453,27 @@ static int netlink_release(struct socket *sock) | |||
| 387 | 453 | ||
| 388 | skb_queue_purge(&sk->sk_write_queue); | 454 | skb_queue_purge(&sk->sk_write_queue); |
| 389 | 455 | ||
| 390 | if (nlk->pid && !nlk->groups) { | 456 | if (nlk->pid && !nlk->subscriptions) { |
| 391 | struct netlink_notify n = { | 457 | struct netlink_notify n = { |
| 392 | .protocol = sk->sk_protocol, | 458 | .protocol = sk->sk_protocol, |
| 393 | .pid = nlk->pid, | 459 | .pid = nlk->pid, |
| 394 | }; | 460 | }; |
| 395 | notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n); | 461 | notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n); |
| 396 | } | 462 | } |
| 397 | 463 | ||
| 464 | if (nlk->module) | ||
| 465 | module_put(nlk->module); | ||
| 466 | |||
| 467 | if (nlk->flags & NETLINK_KERNEL_SOCKET) { | ||
| 468 | netlink_table_grab(); | ||
| 469 | nl_table[sk->sk_protocol].module = NULL; | ||
| 470 | nl_table[sk->sk_protocol].registered = 0; | ||
| 471 | netlink_table_ungrab(); | ||
| 472 | } | ||
| 473 | |||
| 474 | kfree(nlk->groups); | ||
| 475 | nlk->groups = NULL; | ||
| 476 | |||
| 398 | sock_put(sk); | 477 | sock_put(sk); |
| 399 | return 0; | 478 | return 0; |
| 400 | } | 479 | } |
| @@ -443,6 +522,18 @@ static inline int netlink_capable(struct socket *sock, unsigned int flag) | |||
| 443 | capable(CAP_NET_ADMIN); | 522 | capable(CAP_NET_ADMIN); |
| 444 | } | 523 | } |
| 445 | 524 | ||
| 525 | static void | ||
| 526 | netlink_update_subscriptions(struct sock *sk, unsigned int subscriptions) | ||
| 527 | { | ||
| 528 | struct netlink_sock *nlk = nlk_sk(sk); | ||
| 529 | |||
| 530 | if (nlk->subscriptions && !subscriptions) | ||
| 531 | __sk_del_bind_node(sk); | ||
| 532 | else if (!nlk->subscriptions && subscriptions) | ||
| 533 | sk_add_bind_node(sk, &nl_table[sk->sk_protocol].mc_list); | ||
| 534 | nlk->subscriptions = subscriptions; | ||
| 535 | } | ||
| 536 | |||
| 446 | static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) | 537 | static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) |
| 447 | { | 538 | { |
| 448 | struct sock *sk = sock->sk; | 539 | struct sock *sk = sock->sk; |
| @@ -468,15 +559,14 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len | |||
| 468 | return err; | 559 | return err; |
| 469 | } | 560 | } |
| 470 | 561 | ||
| 471 | if (!nladdr->nl_groups && !nlk->groups) | 562 | if (!nladdr->nl_groups && !(u32)nlk->groups[0]) |
| 472 | return 0; | 563 | return 0; |
| 473 | 564 | ||
| 474 | netlink_table_grab(); | 565 | netlink_table_grab(); |
| 475 | if (nlk->groups && !nladdr->nl_groups) | 566 | netlink_update_subscriptions(sk, nlk->subscriptions + |
| 476 | __sk_del_bind_node(sk); | 567 | hweight32(nladdr->nl_groups) - |
| 477 | else if (!nlk->groups && nladdr->nl_groups) | 568 | hweight32(nlk->groups[0])); |
| 478 | sk_add_bind_node(sk, &nl_table[sk->sk_protocol].mc_list); | 569 | nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | nladdr->nl_groups; |
| 479 | nlk->groups = nladdr->nl_groups; | ||
| 480 | netlink_table_ungrab(); | 570 | netlink_table_ungrab(); |
| 481 | 571 | ||
| 482 | return 0; | 572 | return 0; |
| @@ -493,7 +583,7 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr, | |||
| 493 | if (addr->sa_family == AF_UNSPEC) { | 583 | if (addr->sa_family == AF_UNSPEC) { |
| 494 | sk->sk_state = NETLINK_UNCONNECTED; | 584 | sk->sk_state = NETLINK_UNCONNECTED; |
| 495 | nlk->dst_pid = 0; | 585 | nlk->dst_pid = 0; |
| 496 | nlk->dst_groups = 0; | 586 | nlk->dst_group = 0; |
| 497 | return 0; | 587 | return 0; |
| 498 | } | 588 | } |
| 499 | if (addr->sa_family != AF_NETLINK) | 589 | if (addr->sa_family != AF_NETLINK) |
| @@ -509,7 +599,7 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr, | |||
| 509 | if (err == 0) { | 599 | if (err == 0) { |
| 510 | sk->sk_state = NETLINK_CONNECTED; | 600 | sk->sk_state = NETLINK_CONNECTED; |
| 511 | nlk->dst_pid = nladdr->nl_pid; | 601 | nlk->dst_pid = nladdr->nl_pid; |
| 512 | nlk->dst_groups = nladdr->nl_groups; | 602 | nlk->dst_group = ffs(nladdr->nl_groups); |
| 513 | } | 603 | } |
| 514 | 604 | ||
| 515 | return err; | 605 | return err; |
| @@ -527,10 +617,10 @@ static int netlink_getname(struct socket *sock, struct sockaddr *addr, int *addr | |||
| 527 | 617 | ||
| 528 | if (peer) { | 618 | if (peer) { |
| 529 | nladdr->nl_pid = nlk->dst_pid; | 619 | nladdr->nl_pid = nlk->dst_pid; |
| 530 | nladdr->nl_groups = nlk->dst_groups; | 620 | nladdr->nl_groups = netlink_group_mask(nlk->dst_group); |
| 531 | } else { | 621 | } else { |
| 532 | nladdr->nl_pid = nlk->pid; | 622 | nladdr->nl_pid = nlk->pid; |
| 533 | nladdr->nl_groups = nlk->groups; | 623 | nladdr->nl_groups = nlk->groups[0]; |
| 534 | } | 624 | } |
| 535 | return 0; | 625 | return 0; |
| 536 | } | 626 | } |
| @@ -731,7 +821,8 @@ static inline int do_one_broadcast(struct sock *sk, | |||
| 731 | if (p->exclude_sk == sk) | 821 | if (p->exclude_sk == sk) |
| 732 | goto out; | 822 | goto out; |
| 733 | 823 | ||
| 734 | if (nlk->pid == p->pid || !(nlk->groups & p->group)) | 824 | if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups || |
| 825 | !test_bit(p->group - 1, nlk->groups)) | ||
| 735 | goto out; | 826 | goto out; |
| 736 | 827 | ||
| 737 | if (p->failure) { | 828 | if (p->failure) { |
| @@ -770,7 +861,7 @@ out: | |||
| 770 | } | 861 | } |
| 771 | 862 | ||
| 772 | int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, | 863 | int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, |
| 773 | u32 group, int allocation) | 864 | u32 group, unsigned int __nocast allocation) |
| 774 | { | 865 | { |
| 775 | struct netlink_broadcast_data info; | 866 | struct netlink_broadcast_data info; |
| 776 | struct hlist_node *node; | 867 | struct hlist_node *node; |
| @@ -827,7 +918,8 @@ static inline int do_one_set_err(struct sock *sk, | |||
| 827 | if (sk == p->exclude_sk) | 918 | if (sk == p->exclude_sk) |
| 828 | goto out; | 919 | goto out; |
| 829 | 920 | ||
| 830 | if (nlk->pid == p->pid || !(nlk->groups & p->group)) | 921 | if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups || |
| 922 | !test_bit(p->group - 1, nlk->groups)) | ||
| 831 | goto out; | 923 | goto out; |
| 832 | 924 | ||
| 833 | sk->sk_err = p->code; | 925 | sk->sk_err = p->code; |
| @@ -855,6 +947,94 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) | |||
| 855 | read_unlock(&nl_table_lock); | 947 | read_unlock(&nl_table_lock); |
| 856 | } | 948 | } |
| 857 | 949 | ||
| 950 | static int netlink_setsockopt(struct socket *sock, int level, int optname, | ||
| 951 | char __user *optval, int optlen) | ||
| 952 | { | ||
| 953 | struct sock *sk = sock->sk; | ||
| 954 | struct netlink_sock *nlk = nlk_sk(sk); | ||
| 955 | int val = 0, err; | ||
| 956 | |||
| 957 | if (level != SOL_NETLINK) | ||
| 958 | return -ENOPROTOOPT; | ||
| 959 | |||
| 960 | if (optlen >= sizeof(int) && | ||
| 961 | get_user(val, (int __user *)optval)) | ||
| 962 | return -EFAULT; | ||
| 963 | |||
| 964 | switch (optname) { | ||
| 965 | case NETLINK_PKTINFO: | ||
| 966 | if (val) | ||
| 967 | nlk->flags |= NETLINK_RECV_PKTINFO; | ||
| 968 | else | ||
| 969 | nlk->flags &= ~NETLINK_RECV_PKTINFO; | ||
| 970 | err = 0; | ||
| 971 | break; | ||
| 972 | case NETLINK_ADD_MEMBERSHIP: | ||
| 973 | case NETLINK_DROP_MEMBERSHIP: { | ||
| 974 | unsigned int subscriptions; | ||
| 975 | int old, new = optname == NETLINK_ADD_MEMBERSHIP ? 1 : 0; | ||
| 976 | |||
| 977 | if (!netlink_capable(sock, NL_NONROOT_RECV)) | ||
| 978 | return -EPERM; | ||
| 979 | if (!val || val - 1 >= nlk->ngroups) | ||
| 980 | return -EINVAL; | ||
| 981 | netlink_table_grab(); | ||
| 982 | old = test_bit(val - 1, nlk->groups); | ||
| 983 | subscriptions = nlk->subscriptions - old + new; | ||
| 984 | if (new) | ||
| 985 | __set_bit(val - 1, nlk->groups); | ||
| 986 | else | ||
| 987 | __clear_bit(val - 1, nlk->groups); | ||
| 988 | netlink_update_subscriptions(sk, subscriptions); | ||
| 989 | netlink_table_ungrab(); | ||
| 990 | err = 0; | ||
| 991 | break; | ||
| 992 | } | ||
| 993 | default: | ||
| 994 | err = -ENOPROTOOPT; | ||
| 995 | } | ||
| 996 | return err; | ||
| 997 | } | ||
| 998 | |||
| 999 | static int netlink_getsockopt(struct socket *sock, int level, int optname, | ||
| 1000 | char __user *optval, int __user *optlen) | ||
| 1001 | { | ||
| 1002 | struct sock *sk = sock->sk; | ||
| 1003 | struct netlink_sock *nlk = nlk_sk(sk); | ||
| 1004 | int len, val, err; | ||
| 1005 | |||
| 1006 | if (level != SOL_NETLINK) | ||
| 1007 | return -ENOPROTOOPT; | ||
| 1008 | |||
| 1009 | if (get_user(len, optlen)) | ||
| 1010 | return -EFAULT; | ||
| 1011 | if (len < 0) | ||
| 1012 | return -EINVAL; | ||
| 1013 | |||
| 1014 | switch (optname) { | ||
| 1015 | case NETLINK_PKTINFO: | ||
| 1016 | if (len < sizeof(int)) | ||
| 1017 | return -EINVAL; | ||
| 1018 | len = sizeof(int); | ||
| 1019 | val = nlk->flags & NETLINK_RECV_PKTINFO ? 1 : 0; | ||
| 1020 | put_user(len, optlen); | ||
| 1021 | put_user(val, optval); | ||
| 1022 | err = 0; | ||
| 1023 | break; | ||
| 1024 | default: | ||
| 1025 | err = -ENOPROTOOPT; | ||
| 1026 | } | ||
| 1027 | return err; | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | static void netlink_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) | ||
| 1031 | { | ||
| 1032 | struct nl_pktinfo info; | ||
| 1033 | |||
| 1034 | info.group = NETLINK_CB(skb).dst_group; | ||
| 1035 | put_cmsg(msg, SOL_NETLINK, NETLINK_PKTINFO, sizeof(info), &info); | ||
| 1036 | } | ||
| 1037 | |||
| 858 | static inline void netlink_rcv_wake(struct sock *sk) | 1038 | static inline void netlink_rcv_wake(struct sock *sk) |
| 859 | { | 1039 | { |
| 860 | struct netlink_sock *nlk = nlk_sk(sk); | 1040 | struct netlink_sock *nlk = nlk_sk(sk); |
| @@ -873,7 +1053,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
| 873 | struct netlink_sock *nlk = nlk_sk(sk); | 1053 | struct netlink_sock *nlk = nlk_sk(sk); |
| 874 | struct sockaddr_nl *addr=msg->msg_name; | 1054 | struct sockaddr_nl *addr=msg->msg_name; |
| 875 | u32 dst_pid; | 1055 | u32 dst_pid; |
| 876 | u32 dst_groups; | 1056 | u32 dst_group; |
| 877 | struct sk_buff *skb; | 1057 | struct sk_buff *skb; |
| 878 | int err; | 1058 | int err; |
| 879 | struct scm_cookie scm; | 1059 | struct scm_cookie scm; |
| @@ -891,12 +1071,12 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
| 891 | if (addr->nl_family != AF_NETLINK) | 1071 | if (addr->nl_family != AF_NETLINK) |
| 892 | return -EINVAL; | 1072 | return -EINVAL; |
| 893 | dst_pid = addr->nl_pid; | 1073 | dst_pid = addr->nl_pid; |
| 894 | dst_groups = addr->nl_groups; | 1074 | dst_group = ffs(addr->nl_groups); |
| 895 | if (dst_groups && !netlink_capable(sock, NL_NONROOT_SEND)) | 1075 | if (dst_group && !netlink_capable(sock, NL_NONROOT_SEND)) |
| 896 | return -EPERM; | 1076 | return -EPERM; |
| 897 | } else { | 1077 | } else { |
| 898 | dst_pid = nlk->dst_pid; | 1078 | dst_pid = nlk->dst_pid; |
| 899 | dst_groups = nlk->dst_groups; | 1079 | dst_group = nlk->dst_group; |
| 900 | } | 1080 | } |
| 901 | 1081 | ||
| 902 | if (!nlk->pid) { | 1082 | if (!nlk->pid) { |
| @@ -914,9 +1094,8 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
| 914 | goto out; | 1094 | goto out; |
| 915 | 1095 | ||
| 916 | NETLINK_CB(skb).pid = nlk->pid; | 1096 | NETLINK_CB(skb).pid = nlk->pid; |
| 917 | NETLINK_CB(skb).groups = nlk->groups; | ||
| 918 | NETLINK_CB(skb).dst_pid = dst_pid; | 1097 | NETLINK_CB(skb).dst_pid = dst_pid; |
| 919 | NETLINK_CB(skb).dst_groups = dst_groups; | 1098 | NETLINK_CB(skb).dst_group = dst_group; |
| 920 | NETLINK_CB(skb).loginuid = audit_get_loginuid(current->audit_context); | 1099 | NETLINK_CB(skb).loginuid = audit_get_loginuid(current->audit_context); |
| 921 | memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); | 1100 | memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); |
| 922 | 1101 | ||
| @@ -938,9 +1117,9 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
| 938 | goto out; | 1117 | goto out; |
| 939 | } | 1118 | } |
| 940 | 1119 | ||
| 941 | if (dst_groups) { | 1120 | if (dst_group) { |
| 942 | atomic_inc(&skb->users); | 1121 | atomic_inc(&skb->users); |
| 943 | netlink_broadcast(sk, skb, dst_pid, dst_groups, GFP_KERNEL); | 1122 | netlink_broadcast(sk, skb, dst_pid, dst_group, GFP_KERNEL); |
| 944 | } | 1123 | } |
| 945 | err = netlink_unicast(sk, skb, dst_pid, msg->msg_flags&MSG_DONTWAIT); | 1124 | err = netlink_unicast(sk, skb, dst_pid, msg->msg_flags&MSG_DONTWAIT); |
| 946 | 1125 | ||
| @@ -986,7 +1165,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, | |||
| 986 | addr->nl_family = AF_NETLINK; | 1165 | addr->nl_family = AF_NETLINK; |
| 987 | addr->nl_pad = 0; | 1166 | addr->nl_pad = 0; |
| 988 | addr->nl_pid = NETLINK_CB(skb).pid; | 1167 | addr->nl_pid = NETLINK_CB(skb).pid; |
| 989 | addr->nl_groups = NETLINK_CB(skb).dst_groups; | 1168 | addr->nl_groups = netlink_group_mask(NETLINK_CB(skb).dst_group); |
| 990 | msg->msg_namelen = sizeof(*addr); | 1169 | msg->msg_namelen = sizeof(*addr); |
| 991 | } | 1170 | } |
| 992 | 1171 | ||
| @@ -1001,6 +1180,8 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock, | |||
| 1001 | netlink_dump(sk); | 1180 | netlink_dump(sk); |
| 1002 | 1181 | ||
| 1003 | scm_recv(sock, msg, siocb->scm, flags); | 1182 | scm_recv(sock, msg, siocb->scm, flags); |
| 1183 | if (nlk->flags & NETLINK_RECV_PKTINFO) | ||
| 1184 | netlink_cmsg_recv_pktinfo(msg, skb); | ||
| 1004 | 1185 | ||
| 1005 | out: | 1186 | out: |
| 1006 | netlink_rcv_wake(sk); | 1187 | netlink_rcv_wake(sk); |
| @@ -1023,10 +1204,13 @@ static void netlink_data_ready(struct sock *sk, int len) | |||
| 1023 | */ | 1204 | */ |
| 1024 | 1205 | ||
| 1025 | struct sock * | 1206 | struct sock * |
| 1026 | netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len)) | 1207 | netlink_kernel_create(int unit, unsigned int groups, |
| 1208 | void (*input)(struct sock *sk, int len), | ||
| 1209 | struct module *module) | ||
| 1027 | { | 1210 | { |
| 1028 | struct socket *sock; | 1211 | struct socket *sock; |
| 1029 | struct sock *sk; | 1212 | struct sock *sk; |
| 1213 | struct netlink_sock *nlk; | ||
| 1030 | 1214 | ||
| 1031 | if (!nl_table) | 1215 | if (!nl_table) |
| 1032 | return NULL; | 1216 | return NULL; |
| @@ -1037,20 +1221,31 @@ netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len)) | |||
| 1037 | if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) | 1221 | if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) |
| 1038 | return NULL; | 1222 | return NULL; |
| 1039 | 1223 | ||
| 1040 | if (netlink_create(sock, unit) < 0) { | 1224 | if (__netlink_create(sock, unit) < 0) |
| 1041 | sock_release(sock); | 1225 | goto out_sock_release; |
| 1042 | return NULL; | 1226 | |
| 1043 | } | ||
| 1044 | sk = sock->sk; | 1227 | sk = sock->sk; |
| 1045 | sk->sk_data_ready = netlink_data_ready; | 1228 | sk->sk_data_ready = netlink_data_ready; |
| 1046 | if (input) | 1229 | if (input) |
| 1047 | nlk_sk(sk)->data_ready = input; | 1230 | nlk_sk(sk)->data_ready = input; |
| 1048 | 1231 | ||
| 1049 | if (netlink_insert(sk, 0)) { | 1232 | if (netlink_insert(sk, 0)) |
| 1050 | sock_release(sock); | 1233 | goto out_sock_release; |
| 1051 | return NULL; | 1234 | |
| 1052 | } | 1235 | nlk = nlk_sk(sk); |
| 1236 | nlk->flags |= NETLINK_KERNEL_SOCKET; | ||
| 1237 | |||
| 1238 | netlink_table_grab(); | ||
| 1239 | nl_table[unit].groups = groups < 32 ? 32 : groups; | ||
| 1240 | nl_table[unit].module = module; | ||
| 1241 | nl_table[unit].registered = 1; | ||
| 1242 | netlink_table_ungrab(); | ||
| 1243 | |||
| 1053 | return sk; | 1244 | return sk; |
| 1245 | |||
| 1246 | out_sock_release: | ||
| 1247 | sock_release(sock); | ||
| 1248 | return NULL; | ||
| 1054 | } | 1249 | } |
| 1055 | 1250 | ||
| 1056 | void netlink_set_nonroot(int protocol, unsigned int flags) | 1251 | void netlink_set_nonroot(int protocol, unsigned int flags) |
| @@ -1288,7 +1483,8 @@ static int netlink_seq_show(struct seq_file *seq, void *v) | |||
| 1288 | s, | 1483 | s, |
| 1289 | s->sk_protocol, | 1484 | s->sk_protocol, |
| 1290 | nlk->pid, | 1485 | nlk->pid, |
| 1291 | nlk->groups, | 1486 | nlk->flags & NETLINK_KERNEL_SOCKET ? |
| 1487 | 0 : (unsigned int)nlk->groups[0], | ||
| 1292 | atomic_read(&s->sk_rmem_alloc), | 1488 | atomic_read(&s->sk_rmem_alloc), |
| 1293 | atomic_read(&s->sk_wmem_alloc), | 1489 | atomic_read(&s->sk_wmem_alloc), |
| 1294 | nlk->cb, | 1490 | nlk->cb, |
| @@ -1362,8 +1558,8 @@ static struct proto_ops netlink_ops = { | |||
| 1362 | .ioctl = sock_no_ioctl, | 1558 | .ioctl = sock_no_ioctl, |
| 1363 | .listen = sock_no_listen, | 1559 | .listen = sock_no_listen, |
| 1364 | .shutdown = sock_no_shutdown, | 1560 | .shutdown = sock_no_shutdown, |
| 1365 | .setsockopt = sock_no_setsockopt, | 1561 | .setsockopt = netlink_setsockopt, |
| 1366 | .getsockopt = sock_no_getsockopt, | 1562 | .getsockopt = netlink_getsockopt, |
| 1367 | .sendmsg = netlink_sendmsg, | 1563 | .sendmsg = netlink_sendmsg, |
| 1368 | .recvmsg = netlink_recvmsg, | 1564 | .recvmsg = netlink_recvmsg, |
| 1369 | .mmap = sock_no_mmap, | 1565 | .mmap = sock_no_mmap, |
| @@ -1438,21 +1634,7 @@ out: | |||
| 1438 | return err; | 1634 | return err; |
| 1439 | } | 1635 | } |
| 1440 | 1636 | ||
| 1441 | static void __exit netlink_proto_exit(void) | ||
| 1442 | { | ||
| 1443 | sock_unregister(PF_NETLINK); | ||
| 1444 | proc_net_remove("netlink"); | ||
| 1445 | kfree(nl_table); | ||
| 1446 | nl_table = NULL; | ||
| 1447 | proto_unregister(&netlink_proto); | ||
| 1448 | } | ||
| 1449 | |||
| 1450 | core_initcall(netlink_proto_init); | 1637 | core_initcall(netlink_proto_init); |
| 1451 | module_exit(netlink_proto_exit); | ||
| 1452 | |||
| 1453 | MODULE_LICENSE("GPL"); | ||
| 1454 | |||
| 1455 | MODULE_ALIAS_NETPROTO(PF_NETLINK); | ||
| 1456 | 1638 | ||
| 1457 | EXPORT_SYMBOL(netlink_ack); | 1639 | EXPORT_SYMBOL(netlink_ack); |
| 1458 | EXPORT_SYMBOL(netlink_broadcast); | 1640 | EXPORT_SYMBOL(netlink_broadcast); |
