diff options
Diffstat (limited to 'net/netlink')
-rw-r--r-- | net/netlink/af_netlink.c | 100 |
1 files changed, 35 insertions, 65 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 7b7b45a19597..c41a88100fea 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -73,8 +73,12 @@ struct netlink_sock { | |||
73 | struct netlink_callback *cb; | 73 | struct netlink_callback *cb; |
74 | spinlock_t cb_lock; | 74 | spinlock_t cb_lock; |
75 | void (*data_ready)(struct sock *sk, int bytes); | 75 | void (*data_ready)(struct sock *sk, int bytes); |
76 | struct module *module; | ||
77 | u32 flags; | ||
76 | }; | 78 | }; |
77 | 79 | ||
80 | #define NETLINK_KERNEL_SOCKET 0x1 | ||
81 | |||
78 | static inline struct netlink_sock *nlk_sk(struct sock *sk) | 82 | static inline struct netlink_sock *nlk_sk(struct sock *sk) |
79 | { | 83 | { |
80 | return (struct netlink_sock *)sk; | 84 | return (struct netlink_sock *)sk; |
@@ -97,7 +101,7 @@ struct netlink_table { | |||
97 | struct nl_pid_hash hash; | 101 | struct nl_pid_hash hash; |
98 | struct hlist_head mc_list; | 102 | struct hlist_head mc_list; |
99 | unsigned int nl_nonroot; | 103 | unsigned int nl_nonroot; |
100 | struct proto_ops *p_ops; | 104 | struct module *module; |
101 | }; | 105 | }; |
102 | 106 | ||
103 | static struct netlink_table *nl_table; | 107 | static struct netlink_table *nl_table; |
@@ -338,6 +342,7 @@ static int netlink_create(struct socket *sock, int protocol) | |||
338 | { | 342 | { |
339 | struct sock *sk; | 343 | struct sock *sk; |
340 | struct netlink_sock *nlk; | 344 | struct netlink_sock *nlk; |
345 | struct module *module; | ||
341 | 346 | ||
342 | sock->state = SS_UNCONNECTED; | 347 | sock->state = SS_UNCONNECTED; |
343 | 348 | ||
@@ -347,30 +352,36 @@ static int netlink_create(struct socket *sock, int protocol) | |||
347 | if (protocol<0 || protocol >= MAX_LINKS) | 352 | if (protocol<0 || protocol >= MAX_LINKS) |
348 | return -EPROTONOSUPPORT; | 353 | return -EPROTONOSUPPORT; |
349 | 354 | ||
350 | netlink_table_grab(); | 355 | netlink_lock_table(); |
351 | if (!nl_table[protocol].hash.entries) { | 356 | if (!nl_table[protocol].hash.entries) { |
352 | #ifdef CONFIG_KMOD | 357 | #ifdef CONFIG_KMOD |
353 | /* We do 'best effort'. If we find a matching module, | 358 | /* We do 'best effort'. If we find a matching module, |
354 | * it is loaded. If not, we don't return an error to | 359 | * it is loaded. If not, we don't return an error to |
355 | * allow pure userspace<->userspace communication. -HW | 360 | * allow pure userspace<->userspace communication. -HW |
356 | */ | 361 | */ |
357 | netlink_table_ungrab(); | 362 | netlink_unlock_table(); |
358 | request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol); | 363 | request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol); |
359 | netlink_table_grab(); | 364 | netlink_lock_table(); |
360 | #endif | 365 | #endif |
361 | } | 366 | } |
362 | netlink_table_ungrab(); | 367 | module = nl_table[protocol].module; |
368 | if (!try_module_get(module)) | ||
369 | module = NULL; | ||
370 | netlink_unlock_table(); | ||
363 | 371 | ||
364 | sock->ops = nl_table[protocol].p_ops; | 372 | sock->ops = &netlink_ops; |
365 | 373 | ||
366 | sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1); | 374 | sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1); |
367 | if (!sk) | 375 | if (!sk) { |
376 | module_put(module); | ||
368 | return -ENOMEM; | 377 | return -ENOMEM; |
378 | } | ||
369 | 379 | ||
370 | sock_init_data(sock, sk); | 380 | sock_init_data(sock, sk); |
371 | 381 | ||
372 | nlk = nlk_sk(sk); | 382 | nlk = nlk_sk(sk); |
373 | 383 | ||
384 | nlk->module = module; | ||
374 | spin_lock_init(&nlk->cb_lock); | 385 | spin_lock_init(&nlk->cb_lock); |
375 | init_waitqueue_head(&nlk->wait); | 386 | init_waitqueue_head(&nlk->wait); |
376 | sk->sk_destruct = netlink_sock_destruct; | 387 | sk->sk_destruct = netlink_sock_destruct; |
@@ -415,22 +426,15 @@ static int netlink_release(struct socket *sock) | |||
415 | notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n); | 426 | notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n); |
416 | } | 427 | } |
417 | 428 | ||
418 | /* When this is a kernel socket, we need to remove the owner pointer, | 429 | if (nlk->module) |
419 | * since we don't know whether the module will be dying at any given | 430 | module_put(nlk->module); |
420 | * point - HW | ||
421 | */ | ||
422 | if (!nlk->pid) { | ||
423 | struct proto_ops *p_tmp; | ||
424 | 431 | ||
432 | if (nlk->flags & NETLINK_KERNEL_SOCKET) { | ||
425 | netlink_table_grab(); | 433 | netlink_table_grab(); |
426 | p_tmp = nl_table[sk->sk_protocol].p_ops; | 434 | nl_table[sk->sk_protocol].module = NULL; |
427 | if (p_tmp != &netlink_ops) { | ||
428 | nl_table[sk->sk_protocol].p_ops = &netlink_ops; | ||
429 | kfree(p_tmp); | ||
430 | } | ||
431 | netlink_table_ungrab(); | 435 | netlink_table_ungrab(); |
432 | } | 436 | } |
433 | 437 | ||
434 | sock_put(sk); | 438 | sock_put(sk); |
435 | return 0; | 439 | return 0; |
436 | } | 440 | } |
@@ -1060,9 +1064,9 @@ static void netlink_data_ready(struct sock *sk, int len) | |||
1060 | struct sock * | 1064 | struct sock * |
1061 | netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len), struct module *module) | 1065 | netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len), struct module *module) |
1062 | { | 1066 | { |
1063 | struct proto_ops *p_ops; | ||
1064 | struct socket *sock; | 1067 | struct socket *sock; |
1065 | struct sock *sk; | 1068 | struct sock *sk; |
1069 | struct netlink_sock *nlk; | ||
1066 | 1070 | ||
1067 | if (!nl_table) | 1071 | if (!nl_table) |
1068 | return NULL; | 1072 | return NULL; |
@@ -1070,64 +1074,32 @@ netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len), struct | |||
1070 | if (unit<0 || unit>=MAX_LINKS) | 1074 | if (unit<0 || unit>=MAX_LINKS) |
1071 | return NULL; | 1075 | return NULL; |
1072 | 1076 | ||
1073 | /* Do a quick check, to make us not go down to netlink_insert() | ||
1074 | * if protocol already has kernel socket. | ||
1075 | */ | ||
1076 | sk = netlink_lookup(unit, 0); | ||
1077 | if (unlikely(sk)) { | ||
1078 | sock_put(sk); | ||
1079 | return NULL; | ||
1080 | } | ||
1081 | |||
1082 | if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) | 1077 | if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) |
1083 | return NULL; | 1078 | return NULL; |
1084 | 1079 | ||
1085 | sk = NULL; | 1080 | if (netlink_create(sock, unit) < 0) |
1086 | if (module) { | 1081 | goto out_sock_release; |
1087 | /* Every registering protocol implemented in a module needs | ||
1088 | * it's own p_ops, since the socket code cannot deal with | ||
1089 | * module refcounting otherwise. -HW | ||
1090 | */ | ||
1091 | p_ops = kmalloc(sizeof(*p_ops), GFP_KERNEL); | ||
1092 | if (!p_ops) | ||
1093 | goto out_sock_release; | ||
1094 | |||
1095 | memcpy(p_ops, &netlink_ops, sizeof(*p_ops)); | ||
1096 | p_ops->owner = module; | ||
1097 | } else | ||
1098 | p_ops = &netlink_ops; | ||
1099 | |||
1100 | netlink_table_grab(); | ||
1101 | nl_table[unit].p_ops = p_ops; | ||
1102 | netlink_table_ungrab(); | ||
1103 | |||
1104 | if (netlink_create(sock, unit) < 0) { | ||
1105 | sk = NULL; | ||
1106 | goto out_kfree_p_ops; | ||
1107 | } | ||
1108 | 1082 | ||
1109 | sk = sock->sk; | 1083 | sk = sock->sk; |
1110 | sk->sk_data_ready = netlink_data_ready; | 1084 | sk->sk_data_ready = netlink_data_ready; |
1111 | if (input) | 1085 | if (input) |
1112 | nlk_sk(sk)->data_ready = input; | 1086 | nlk_sk(sk)->data_ready = input; |
1113 | 1087 | ||
1114 | if (netlink_insert(sk, 0)) { | 1088 | if (netlink_insert(sk, 0)) |
1115 | sk = NULL; | 1089 | goto out_sock_release; |
1116 | goto out_kfree_p_ops; | ||
1117 | } | ||
1118 | 1090 | ||
1119 | return sk; | 1091 | nlk = nlk_sk(sk); |
1092 | nlk->flags |= NETLINK_KERNEL_SOCKET; | ||
1120 | 1093 | ||
1121 | out_kfree_p_ops: | ||
1122 | netlink_table_grab(); | 1094 | netlink_table_grab(); |
1123 | if (nl_table[unit].p_ops != &netlink_ops) { | 1095 | nl_table[unit].module = module; |
1124 | kfree(nl_table[unit].p_ops); | ||
1125 | nl_table[unit].p_ops = &netlink_ops; | ||
1126 | } | ||
1127 | netlink_table_ungrab(); | 1096 | netlink_table_ungrab(); |
1097 | |||
1098 | return sk; | ||
1099 | |||
1128 | out_sock_release: | 1100 | out_sock_release: |
1129 | sock_release(sock); | 1101 | sock_release(sock); |
1130 | return sk; | 1102 | return NULL; |
1131 | } | 1103 | } |
1132 | 1104 | ||
1133 | void netlink_set_nonroot(int protocol, unsigned int flags) | 1105 | void netlink_set_nonroot(int protocol, unsigned int flags) |
@@ -1490,8 +1462,6 @@ enomem: | |||
1490 | for (i = 0; i < MAX_LINKS; i++) { | 1462 | for (i = 0; i < MAX_LINKS; i++) { |
1491 | struct nl_pid_hash *hash = &nl_table[i].hash; | 1463 | struct nl_pid_hash *hash = &nl_table[i].hash; |
1492 | 1464 | ||
1493 | nl_table[i].p_ops = &netlink_ops; | ||
1494 | |||
1495 | hash->table = nl_pid_hash_alloc(1 * sizeof(*hash->table)); | 1465 | hash->table = nl_pid_hash_alloc(1 * sizeof(*hash->table)); |
1496 | if (!hash->table) { | 1466 | if (!hash->table) { |
1497 | while (i-- > 0) | 1467 | while (i-- > 0) |