diff options
Diffstat (limited to 'net/netlink')
-rw-r--r-- | net/netlink/af_netlink.c | 43 | ||||
-rw-r--r-- | net/netlink/genetlink.c | 37 |
2 files changed, 45 insertions, 35 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 19e98007691c..795424396aff 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -428,7 +428,8 @@ static int __netlink_create(struct net *net, struct socket *sock, | |||
428 | return 0; | 428 | return 0; |
429 | } | 429 | } |
430 | 430 | ||
431 | static int netlink_create(struct net *net, struct socket *sock, int protocol) | 431 | static int netlink_create(struct net *net, struct socket *sock, int protocol, |
432 | int kern) | ||
432 | { | 433 | { |
433 | struct module *module = NULL; | 434 | struct module *module = NULL; |
434 | struct mutex *cb_mutex; | 435 | struct mutex *cb_mutex; |
@@ -454,9 +455,14 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol) | |||
454 | if (nl_table[protocol].registered && | 455 | if (nl_table[protocol].registered && |
455 | try_module_get(nl_table[protocol].module)) | 456 | try_module_get(nl_table[protocol].module)) |
456 | module = nl_table[protocol].module; | 457 | module = nl_table[protocol].module; |
458 | else | ||
459 | err = -EPROTONOSUPPORT; | ||
457 | cb_mutex = nl_table[protocol].cb_mutex; | 460 | cb_mutex = nl_table[protocol].cb_mutex; |
458 | netlink_unlock_table(); | 461 | netlink_unlock_table(); |
459 | 462 | ||
463 | if (err < 0) | ||
464 | goto out; | ||
465 | |||
460 | err = __netlink_create(net, sock, cb_mutex, protocol); | 466 | err = __netlink_create(net, sock, cb_mutex, protocol); |
461 | if (err < 0) | 467 | if (err < 0) |
462 | goto out_module; | 468 | goto out_module; |
@@ -497,7 +503,7 @@ static int netlink_release(struct socket *sock) | |||
497 | 503 | ||
498 | skb_queue_purge(&sk->sk_write_queue); | 504 | skb_queue_purge(&sk->sk_write_queue); |
499 | 505 | ||
500 | if (nlk->pid && !nlk->subscriptions) { | 506 | if (nlk->pid) { |
501 | struct netlink_notify n = { | 507 | struct netlink_notify n = { |
502 | .net = sock_net(sk), | 508 | .net = sock_net(sk), |
503 | .protocol = sk->sk_protocol, | 509 | .protocol = sk->sk_protocol, |
@@ -677,6 +683,9 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr, | |||
677 | struct netlink_sock *nlk = nlk_sk(sk); | 683 | struct netlink_sock *nlk = nlk_sk(sk); |
678 | struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; | 684 | struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; |
679 | 685 | ||
686 | if (alen < sizeof(addr->sa_family)) | ||
687 | return -EINVAL; | ||
688 | |||
680 | if (addr->sa_family == AF_UNSPEC) { | 689 | if (addr->sa_family == AF_UNSPEC) { |
681 | sk->sk_state = NETLINK_UNCONNECTED; | 690 | sk->sk_state = NETLINK_UNCONNECTED; |
682 | nlk->dst_pid = 0; | 691 | nlk->dst_pid = 0; |
@@ -707,7 +716,7 @@ static int netlink_getname(struct socket *sock, struct sockaddr *addr, | |||
707 | { | 716 | { |
708 | struct sock *sk = sock->sk; | 717 | struct sock *sk = sock->sk; |
709 | struct netlink_sock *nlk = nlk_sk(sk); | 718 | struct netlink_sock *nlk = nlk_sk(sk); |
710 | struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; | 719 | DECLARE_SOCKADDR(struct sockaddr_nl *, nladdr, addr); |
711 | 720 | ||
712 | nladdr->nl_family = AF_NETLINK; | 721 | nladdr->nl_family = AF_NETLINK; |
713 | nladdr->nl_pad = 0; | 722 | nladdr->nl_pad = 0; |
@@ -1087,21 +1096,27 @@ static inline int do_one_set_err(struct sock *sk, | |||
1087 | struct netlink_set_err_data *p) | 1096 | struct netlink_set_err_data *p) |
1088 | { | 1097 | { |
1089 | struct netlink_sock *nlk = nlk_sk(sk); | 1098 | struct netlink_sock *nlk = nlk_sk(sk); |
1099 | int ret = 0; | ||
1090 | 1100 | ||
1091 | if (sk == p->exclude_sk) | 1101 | if (sk == p->exclude_sk) |
1092 | goto out; | 1102 | goto out; |
1093 | 1103 | ||
1094 | if (sock_net(sk) != sock_net(p->exclude_sk)) | 1104 | if (!net_eq(sock_net(sk), sock_net(p->exclude_sk))) |
1095 | goto out; | 1105 | goto out; |
1096 | 1106 | ||
1097 | if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups || | 1107 | if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups || |
1098 | !test_bit(p->group - 1, nlk->groups)) | 1108 | !test_bit(p->group - 1, nlk->groups)) |
1099 | goto out; | 1109 | goto out; |
1100 | 1110 | ||
1111 | if (p->code == ENOBUFS && nlk->flags & NETLINK_RECV_NO_ENOBUFS) { | ||
1112 | ret = 1; | ||
1113 | goto out; | ||
1114 | } | ||
1115 | |||
1101 | sk->sk_err = p->code; | 1116 | sk->sk_err = p->code; |
1102 | sk->sk_error_report(sk); | 1117 | sk->sk_error_report(sk); |
1103 | out: | 1118 | out: |
1104 | return 0; | 1119 | return ret; |
1105 | } | 1120 | } |
1106 | 1121 | ||
1107 | /** | 1122 | /** |
@@ -1110,12 +1125,16 @@ out: | |||
1110 | * @pid: the PID of a process that we want to skip (if any) | 1125 | * @pid: the PID of a process that we want to skip (if any) |
1111 | * @groups: the broadcast group that will notice the error | 1126 | * @groups: the broadcast group that will notice the error |
1112 | * @code: error code, must be negative (as usual in kernelspace) | 1127 | * @code: error code, must be negative (as usual in kernelspace) |
1128 | * | ||
1129 | * This function returns the number of broadcast listeners that have set the | ||
1130 | * NETLINK_RECV_NO_ENOBUFS socket option. | ||
1113 | */ | 1131 | */ |
1114 | void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) | 1132 | int netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) |
1115 | { | 1133 | { |
1116 | struct netlink_set_err_data info; | 1134 | struct netlink_set_err_data info; |
1117 | struct hlist_node *node; | 1135 | struct hlist_node *node; |
1118 | struct sock *sk; | 1136 | struct sock *sk; |
1137 | int ret = 0; | ||
1119 | 1138 | ||
1120 | info.exclude_sk = ssk; | 1139 | info.exclude_sk = ssk; |
1121 | info.pid = pid; | 1140 | info.pid = pid; |
@@ -1126,9 +1145,10 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) | |||
1126 | read_lock(&nl_table_lock); | 1145 | read_lock(&nl_table_lock); |
1127 | 1146 | ||
1128 | sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list) | 1147 | sk_for_each_bound(sk, node, &nl_table[ssk->sk_protocol].mc_list) |
1129 | do_one_set_err(sk, &info); | 1148 | ret += do_one_set_err(sk, &info); |
1130 | 1149 | ||
1131 | read_unlock(&nl_table_lock); | 1150 | read_unlock(&nl_table_lock); |
1151 | return ret; | ||
1132 | } | 1152 | } |
1133 | EXPORT_SYMBOL(netlink_set_err); | 1153 | EXPORT_SYMBOL(netlink_set_err); |
1134 | 1154 | ||
@@ -1972,12 +1992,12 @@ static int netlink_seq_show(struct seq_file *seq, void *v) | |||
1972 | if (v == SEQ_START_TOKEN) | 1992 | if (v == SEQ_START_TOKEN) |
1973 | seq_puts(seq, | 1993 | seq_puts(seq, |
1974 | "sk Eth Pid Groups " | 1994 | "sk Eth Pid Groups " |
1975 | "Rmem Wmem Dump Locks Drops\n"); | 1995 | "Rmem Wmem Dump Locks Drops Inode\n"); |
1976 | else { | 1996 | else { |
1977 | struct sock *s = v; | 1997 | struct sock *s = v; |
1978 | struct netlink_sock *nlk = nlk_sk(s); | 1998 | struct netlink_sock *nlk = nlk_sk(s); |
1979 | 1999 | ||
1980 | seq_printf(seq, "%p %-3d %-6d %08x %-8d %-8d %p %-8d %-8d\n", | 2000 | seq_printf(seq, "%p %-3d %-6d %08x %-8d %-8d %p %-8d %-8d %-8lu\n", |
1981 | s, | 2001 | s, |
1982 | s->sk_protocol, | 2002 | s->sk_protocol, |
1983 | nlk->pid, | 2003 | nlk->pid, |
@@ -1986,7 +2006,8 @@ static int netlink_seq_show(struct seq_file *seq, void *v) | |||
1986 | sk_wmem_alloc_get(s), | 2006 | sk_wmem_alloc_get(s), |
1987 | nlk->cb, | 2007 | nlk->cb, |
1988 | atomic_read(&s->sk_refcnt), | 2008 | atomic_read(&s->sk_refcnt), |
1989 | atomic_read(&s->sk_drops) | 2009 | atomic_read(&s->sk_drops), |
2010 | sock_i_ino(s) | ||
1990 | ); | 2011 | ); |
1991 | 2012 | ||
1992 | } | 2013 | } |
@@ -2050,7 +2071,7 @@ static const struct proto_ops netlink_ops = { | |||
2050 | .sendpage = sock_no_sendpage, | 2071 | .sendpage = sock_no_sendpage, |
2051 | }; | 2072 | }; |
2052 | 2073 | ||
2053 | static struct net_proto_family netlink_family_ops = { | 2074 | static const struct net_proto_family netlink_family_ops = { |
2054 | .family = PF_NETLINK, | 2075 | .family = PF_NETLINK, |
2055 | .create = netlink_create, | 2076 | .create = netlink_create, |
2056 | .owner = THIS_MODULE, /* for consistency 8) */ | 2077 | .owner = THIS_MODULE, /* for consistency 8) */ |
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 44ff3f3810fa..06438fa2b1e5 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c | |||
@@ -8,6 +8,7 @@ | |||
8 | 8 | ||
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
11 | #include <linux/slab.h> | ||
11 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
12 | #include <linux/types.h> | 13 | #include <linux/types.h> |
13 | #include <linux/socket.h> | 14 | #include <linux/socket.h> |
@@ -97,25 +98,17 @@ static struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family) | |||
97 | */ | 98 | */ |
98 | static inline u16 genl_generate_id(void) | 99 | static inline u16 genl_generate_id(void) |
99 | { | 100 | { |
100 | static u16 id_gen_idx; | 101 | static u16 id_gen_idx = GENL_MIN_ID; |
101 | int overflowed = 0; | 102 | int i; |
102 | 103 | ||
103 | do { | 104 | for (i = 0; i <= GENL_MAX_ID - GENL_MIN_ID; i++) { |
104 | if (id_gen_idx == 0) | 105 | if (!genl_family_find_byid(id_gen_idx)) |
106 | return id_gen_idx; | ||
107 | if (++id_gen_idx > GENL_MAX_ID) | ||
105 | id_gen_idx = GENL_MIN_ID; | 108 | id_gen_idx = GENL_MIN_ID; |
109 | } | ||
106 | 110 | ||
107 | if (++id_gen_idx > GENL_MAX_ID) { | 111 | return 0; |
108 | if (!overflowed) { | ||
109 | overflowed = 1; | ||
110 | id_gen_idx = 0; | ||
111 | continue; | ||
112 | } else | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | } while (genl_family_find_byid(id_gen_idx)); | ||
117 | |||
118 | return id_gen_idx; | ||
119 | } | 112 | } |
120 | 113 | ||
121 | static struct genl_multicast_group notify_grp; | 114 | static struct genl_multicast_group notify_grp; |
@@ -374,11 +367,6 @@ int genl_register_family(struct genl_family *family) | |||
374 | goto errout_locked; | 367 | goto errout_locked; |
375 | } | 368 | } |
376 | 369 | ||
377 | if (genl_family_find_byid(family->id)) { | ||
378 | err = -EEXIST; | ||
379 | goto errout_locked; | ||
380 | } | ||
381 | |||
382 | if (family->id == GENL_ID_GENERATE) { | 370 | if (family->id == GENL_ID_GENERATE) { |
383 | u16 newid = genl_generate_id(); | 371 | u16 newid = genl_generate_id(); |
384 | 372 | ||
@@ -388,6 +376,9 @@ int genl_register_family(struct genl_family *family) | |||
388 | } | 376 | } |
389 | 377 | ||
390 | family->id = newid; | 378 | family->id = newid; |
379 | } else if (genl_family_find_byid(family->id)) { | ||
380 | err = -EEXIST; | ||
381 | goto errout_locked; | ||
391 | } | 382 | } |
392 | 383 | ||
393 | if (family->maxattr) { | 384 | if (family->maxattr) { |
@@ -691,9 +682,7 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) | |||
691 | int chains_to_skip = cb->args[0]; | 682 | int chains_to_skip = cb->args[0]; |
692 | int fams_to_skip = cb->args[1]; | 683 | int fams_to_skip = cb->args[1]; |
693 | 684 | ||
694 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { | 685 | for (i = chains_to_skip; i < GENL_FAM_TAB_SIZE; i++) { |
695 | if (i < chains_to_skip) | ||
696 | continue; | ||
697 | n = 0; | 686 | n = 0; |
698 | list_for_each_entry(rt, genl_family_chain(i), family_list) { | 687 | list_for_each_entry(rt, genl_family_chain(i), family_list) { |
699 | if (!rt->netnsok && !net_eq(net, &init_net)) | 688 | if (!rt->netnsok && !net_eq(net, &init_net)) |