diff options
Diffstat (limited to 'net/netlink')
-rw-r--r-- | net/netlink/af_netlink.c | 72 |
1 files changed, 44 insertions, 28 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 3c56b96b4a4b..444ed223ee43 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -102,6 +102,7 @@ struct netlink_table { | |||
102 | struct hlist_head mc_list; | 102 | struct hlist_head mc_list; |
103 | unsigned int nl_nonroot; | 103 | unsigned int nl_nonroot; |
104 | struct module *module; | 104 | struct module *module; |
105 | int registered; | ||
105 | }; | 106 | }; |
106 | 107 | ||
107 | static struct netlink_table *nl_table; | 108 | static struct netlink_table *nl_table; |
@@ -343,11 +344,32 @@ static struct proto netlink_proto = { | |||
343 | .obj_size = sizeof(struct netlink_sock), | 344 | .obj_size = sizeof(struct netlink_sock), |
344 | }; | 345 | }; |
345 | 346 | ||
346 | static int netlink_create(struct socket *sock, int protocol) | 347 | static int __netlink_create(struct socket *sock, int protocol) |
347 | { | 348 | { |
348 | struct sock *sk; | 349 | struct sock *sk; |
349 | struct netlink_sock *nlk; | 350 | struct netlink_sock *nlk; |
350 | struct module *module; | 351 | |
352 | sock->ops = &netlink_ops; | ||
353 | |||
354 | sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1); | ||
355 | if (!sk) | ||
356 | return -ENOMEM; | ||
357 | |||
358 | sock_init_data(sock, sk); | ||
359 | |||
360 | nlk = nlk_sk(sk); | ||
361 | spin_lock_init(&nlk->cb_lock); | ||
362 | init_waitqueue_head(&nlk->wait); | ||
363 | |||
364 | sk->sk_destruct = netlink_sock_destruct; | ||
365 | sk->sk_protocol = protocol; | ||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static int netlink_create(struct socket *sock, int protocol) | ||
370 | { | ||
371 | struct module *module = NULL; | ||
372 | int err = 0; | ||
351 | 373 | ||
352 | sock->state = SS_UNCONNECTED; | 374 | sock->state = SS_UNCONNECTED; |
353 | 375 | ||
@@ -358,41 +380,33 @@ static int netlink_create(struct socket *sock, int protocol) | |||
358 | return -EPROTONOSUPPORT; | 380 | return -EPROTONOSUPPORT; |
359 | 381 | ||
360 | netlink_lock_table(); | 382 | netlink_lock_table(); |
361 | if (!nl_table[protocol].hash.entries) { | ||
362 | #ifdef CONFIG_KMOD | 383 | #ifdef CONFIG_KMOD |
363 | /* We do 'best effort'. If we find a matching module, | 384 | if (!nl_table[protocol].registered) { |
364 | * it is loaded. If not, we don't return an error to | ||
365 | * allow pure userspace<->userspace communication. -HW | ||
366 | */ | ||
367 | netlink_unlock_table(); | 385 | netlink_unlock_table(); |
368 | request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol); | 386 | request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol); |
369 | netlink_lock_table(); | 387 | netlink_lock_table(); |
370 | #endif | ||
371 | } | 388 | } |
372 | module = nl_table[protocol].module; | 389 | #endif |
373 | if (!try_module_get(module)) | 390 | if (nl_table[protocol].registered && |
374 | module = NULL; | 391 | try_module_get(nl_table[protocol].module)) |
392 | module = nl_table[protocol].module; | ||
393 | else | ||
394 | err = -EPROTONOSUPPORT; | ||
375 | netlink_unlock_table(); | 395 | netlink_unlock_table(); |
376 | 396 | ||
377 | sock->ops = &netlink_ops; | 397 | if (err) |
378 | 398 | goto out; | |
379 | sk = sk_alloc(PF_NETLINK, GFP_KERNEL, &netlink_proto, 1); | ||
380 | if (!sk) { | ||
381 | module_put(module); | ||
382 | return -ENOMEM; | ||
383 | } | ||
384 | |||
385 | sock_init_data(sock, sk); | ||
386 | 399 | ||
387 | nlk = nlk_sk(sk); | 400 | if ((err = __netlink_create(sock, protocol) < 0)) |
401 | goto out_module; | ||
388 | 402 | ||
389 | nlk->module = module; | 403 | nlk_sk(sock->sk)->module = module; |
390 | spin_lock_init(&nlk->cb_lock); | 404 | out: |
391 | init_waitqueue_head(&nlk->wait); | 405 | return err; |
392 | sk->sk_destruct = netlink_sock_destruct; | ||
393 | 406 | ||
394 | sk->sk_protocol = protocol; | 407 | out_module: |
395 | return 0; | 408 | module_put(module); |
409 | goto out; | ||
396 | } | 410 | } |
397 | 411 | ||
398 | static int netlink_release(struct socket *sock) | 412 | static int netlink_release(struct socket *sock) |
@@ -437,6 +451,7 @@ static int netlink_release(struct socket *sock) | |||
437 | if (nlk->flags & NETLINK_KERNEL_SOCKET) { | 451 | if (nlk->flags & NETLINK_KERNEL_SOCKET) { |
438 | netlink_table_grab(); | 452 | netlink_table_grab(); |
439 | nl_table[sk->sk_protocol].module = NULL; | 453 | nl_table[sk->sk_protocol].module = NULL; |
454 | nl_table[sk->sk_protocol].registered = 0; | ||
440 | netlink_table_ungrab(); | 455 | netlink_table_ungrab(); |
441 | } | 456 | } |
442 | 457 | ||
@@ -1082,7 +1097,7 @@ netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len), struct | |||
1082 | if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) | 1097 | if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) |
1083 | return NULL; | 1098 | return NULL; |
1084 | 1099 | ||
1085 | if (netlink_create(sock, unit) < 0) | 1100 | if (__netlink_create(sock, unit) < 0) |
1086 | goto out_sock_release; | 1101 | goto out_sock_release; |
1087 | 1102 | ||
1088 | sk = sock->sk; | 1103 | sk = sock->sk; |
@@ -1098,6 +1113,7 @@ netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len), struct | |||
1098 | 1113 | ||
1099 | netlink_table_grab(); | 1114 | netlink_table_grab(); |
1100 | nl_table[unit].module = module; | 1115 | nl_table[unit].module = module; |
1116 | nl_table[unit].registered = 1; | ||
1101 | netlink_table_ungrab(); | 1117 | netlink_table_ungrab(); |
1102 | 1118 | ||
1103 | return sk; | 1119 | return sk; |