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); |