diff options
Diffstat (limited to 'net/netlink/af_netlink.c')
| -rw-r--r-- | net/netlink/af_netlink.c | 116 |
1 files changed, 70 insertions, 46 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 3862e73d14d7..d56e0d21f919 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
| @@ -21,7 +21,6 @@ | |||
| 21 | * mandatory if CONFIG_NET=y these days | 21 | * mandatory if CONFIG_NET=y these days |
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | #include <linux/config.h> | ||
| 25 | #include <linux/module.h> | 24 | #include <linux/module.h> |
| 26 | 25 | ||
| 27 | #include <linux/capability.h> | 26 | #include <linux/capability.h> |
| @@ -157,7 +156,7 @@ static void netlink_sock_destruct(struct sock *sk) | |||
| 157 | 156 | ||
| 158 | static void netlink_table_grab(void) | 157 | static void netlink_table_grab(void) |
| 159 | { | 158 | { |
| 160 | write_lock_bh(&nl_table_lock); | 159 | write_lock_irq(&nl_table_lock); |
| 161 | 160 | ||
| 162 | if (atomic_read(&nl_table_users)) { | 161 | if (atomic_read(&nl_table_users)) { |
| 163 | DECLARE_WAITQUEUE(wait, current); | 162 | DECLARE_WAITQUEUE(wait, current); |
| @@ -167,9 +166,9 @@ static void netlink_table_grab(void) | |||
| 167 | set_current_state(TASK_UNINTERRUPTIBLE); | 166 | set_current_state(TASK_UNINTERRUPTIBLE); |
| 168 | if (atomic_read(&nl_table_users) == 0) | 167 | if (atomic_read(&nl_table_users) == 0) |
| 169 | break; | 168 | break; |
| 170 | write_unlock_bh(&nl_table_lock); | 169 | write_unlock_irq(&nl_table_lock); |
| 171 | schedule(); | 170 | schedule(); |
| 172 | write_lock_bh(&nl_table_lock); | 171 | write_lock_irq(&nl_table_lock); |
| 173 | } | 172 | } |
| 174 | 173 | ||
| 175 | __set_current_state(TASK_RUNNING); | 174 | __set_current_state(TASK_RUNNING); |
| @@ -179,7 +178,7 @@ static void netlink_table_grab(void) | |||
| 179 | 178 | ||
| 180 | static __inline__ void netlink_table_ungrab(void) | 179 | static __inline__ void netlink_table_ungrab(void) |
| 181 | { | 180 | { |
| 182 | write_unlock_bh(&nl_table_lock); | 181 | write_unlock_irq(&nl_table_lock); |
| 183 | wake_up(&nl_table_wait); | 182 | wake_up(&nl_table_wait); |
| 184 | } | 183 | } |
| 185 | 184 | ||
| @@ -563,10 +562,9 @@ static int netlink_alloc_groups(struct sock *sk) | |||
| 563 | if (err) | 562 | if (err) |
| 564 | return err; | 563 | return err; |
| 565 | 564 | ||
| 566 | nlk->groups = kmalloc(NLGRPSZ(groups), GFP_KERNEL); | 565 | nlk->groups = kzalloc(NLGRPSZ(groups), GFP_KERNEL); |
| 567 | if (nlk->groups == NULL) | 566 | if (nlk->groups == NULL) |
| 568 | return -ENOMEM; | 567 | return -ENOMEM; |
| 569 | memset(nlk->groups, 0, NLGRPSZ(groups)); | ||
| 570 | nlk->ngroups = groups; | 568 | nlk->ngroups = groups; |
| 571 | return 0; | 569 | return 0; |
| 572 | } | 570 | } |
| @@ -1149,7 +1147,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
| 1149 | if (len > sk->sk_sndbuf - 32) | 1147 | if (len > sk->sk_sndbuf - 32) |
| 1150 | goto out; | 1148 | goto out; |
| 1151 | err = -ENOBUFS; | 1149 | err = -ENOBUFS; |
| 1152 | skb = alloc_skb(len, GFP_KERNEL); | 1150 | skb = nlmsg_new(len, GFP_KERNEL); |
| 1153 | if (skb==NULL) | 1151 | if (skb==NULL) |
| 1154 | goto out; | 1152 | goto out; |
| 1155 | 1153 | ||
| @@ -1275,8 +1273,7 @@ netlink_kernel_create(int unit, unsigned int groups, | |||
| 1275 | struct netlink_sock *nlk; | 1273 | struct netlink_sock *nlk; |
| 1276 | unsigned long *listeners = NULL; | 1274 | unsigned long *listeners = NULL; |
| 1277 | 1275 | ||
| 1278 | if (!nl_table) | 1276 | BUG_ON(!nl_table); |
| 1279 | return NULL; | ||
| 1280 | 1277 | ||
| 1281 | if (unit<0 || unit>=MAX_LINKS) | 1278 | if (unit<0 || unit>=MAX_LINKS) |
| 1282 | return NULL; | 1279 | return NULL; |
| @@ -1344,19 +1341,18 @@ static int netlink_dump(struct sock *sk) | |||
| 1344 | struct netlink_callback *cb; | 1341 | struct netlink_callback *cb; |
| 1345 | struct sk_buff *skb; | 1342 | struct sk_buff *skb; |
| 1346 | struct nlmsghdr *nlh; | 1343 | struct nlmsghdr *nlh; |
| 1347 | int len; | 1344 | int len, err = -ENOBUFS; |
| 1348 | 1345 | ||
| 1349 | skb = sock_rmalloc(sk, NLMSG_GOODSIZE, 0, GFP_KERNEL); | 1346 | skb = sock_rmalloc(sk, NLMSG_GOODSIZE, 0, GFP_KERNEL); |
| 1350 | if (!skb) | 1347 | if (!skb) |
| 1351 | return -ENOBUFS; | 1348 | goto errout; |
| 1352 | 1349 | ||
| 1353 | spin_lock(&nlk->cb_lock); | 1350 | spin_lock(&nlk->cb_lock); |
| 1354 | 1351 | ||
| 1355 | cb = nlk->cb; | 1352 | cb = nlk->cb; |
| 1356 | if (cb == NULL) { | 1353 | if (cb == NULL) { |
| 1357 | spin_unlock(&nlk->cb_lock); | 1354 | err = -EINVAL; |
| 1358 | kfree_skb(skb); | 1355 | goto errout_skb; |
| 1359 | return -EINVAL; | ||
| 1360 | } | 1356 | } |
| 1361 | 1357 | ||
| 1362 | len = cb->dump(skb, cb); | 1358 | len = cb->dump(skb, cb); |
| @@ -1368,8 +1364,12 @@ static int netlink_dump(struct sock *sk) | |||
| 1368 | return 0; | 1364 | return 0; |
| 1369 | } | 1365 | } |
| 1370 | 1366 | ||
| 1371 | nlh = NLMSG_NEW_ANSWER(skb, cb, NLMSG_DONE, sizeof(len), NLM_F_MULTI); | 1367 | nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, sizeof(len), NLM_F_MULTI); |
| 1372 | memcpy(NLMSG_DATA(nlh), &len, sizeof(len)); | 1368 | if (!nlh) |
| 1369 | goto errout_skb; | ||
| 1370 | |||
| 1371 | memcpy(nlmsg_data(nlh), &len, sizeof(len)); | ||
| 1372 | |||
| 1373 | skb_queue_tail(&sk->sk_receive_queue, skb); | 1373 | skb_queue_tail(&sk->sk_receive_queue, skb); |
| 1374 | sk->sk_data_ready(sk, skb->len); | 1374 | sk->sk_data_ready(sk, skb->len); |
| 1375 | 1375 | ||
| @@ -1381,8 +1381,11 @@ static int netlink_dump(struct sock *sk) | |||
| 1381 | netlink_destroy_callback(cb); | 1381 | netlink_destroy_callback(cb); |
| 1382 | return 0; | 1382 | return 0; |
| 1383 | 1383 | ||
| 1384 | nlmsg_failure: | 1384 | errout_skb: |
| 1385 | return -ENOBUFS; | 1385 | spin_unlock(&nlk->cb_lock); |
| 1386 | kfree_skb(skb); | ||
| 1387 | errout: | ||
| 1388 | return err; | ||
| 1386 | } | 1389 | } |
| 1387 | 1390 | ||
| 1388 | int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, | 1391 | int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, |
| @@ -1394,11 +1397,10 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, | |||
| 1394 | struct sock *sk; | 1397 | struct sock *sk; |
| 1395 | struct netlink_sock *nlk; | 1398 | struct netlink_sock *nlk; |
| 1396 | 1399 | ||
| 1397 | cb = kmalloc(sizeof(*cb), GFP_KERNEL); | 1400 | cb = kzalloc(sizeof(*cb), GFP_KERNEL); |
| 1398 | if (cb == NULL) | 1401 | if (cb == NULL) |
| 1399 | return -ENOBUFS; | 1402 | return -ENOBUFS; |
| 1400 | 1403 | ||
| 1401 | memset(cb, 0, sizeof(*cb)); | ||
| 1402 | cb->dump = dump; | 1404 | cb->dump = dump; |
| 1403 | cb->done = done; | 1405 | cb->done = done; |
| 1404 | cb->nlh = nlh; | 1406 | cb->nlh = nlh; |
| @@ -1435,11 +1437,11 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) | |||
| 1435 | int size; | 1437 | int size; |
| 1436 | 1438 | ||
| 1437 | if (err == 0) | 1439 | if (err == 0) |
| 1438 | size = NLMSG_SPACE(sizeof(struct nlmsgerr)); | 1440 | size = nlmsg_total_size(sizeof(*errmsg)); |
| 1439 | else | 1441 | else |
| 1440 | size = NLMSG_SPACE(4 + NLMSG_ALIGN(nlh->nlmsg_len)); | 1442 | size = nlmsg_total_size(sizeof(*errmsg) + nlmsg_len(nlh)); |
| 1441 | 1443 | ||
| 1442 | skb = alloc_skb(size, GFP_KERNEL); | 1444 | skb = nlmsg_new(size, GFP_KERNEL); |
| 1443 | if (!skb) { | 1445 | if (!skb) { |
| 1444 | struct sock *sk; | 1446 | struct sock *sk; |
| 1445 | 1447 | ||
| @@ -1455,16 +1457,15 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) | |||
| 1455 | 1457 | ||
| 1456 | rep = __nlmsg_put(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, | 1458 | rep = __nlmsg_put(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, |
| 1457 | NLMSG_ERROR, sizeof(struct nlmsgerr), 0); | 1459 | NLMSG_ERROR, sizeof(struct nlmsgerr), 0); |
| 1458 | errmsg = NLMSG_DATA(rep); | 1460 | errmsg = nlmsg_data(rep); |
| 1459 | errmsg->error = err; | 1461 | errmsg->error = err; |
| 1460 | memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(struct nlmsghdr)); | 1462 | memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(*nlh)); |
| 1461 | netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); | 1463 | netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); |
| 1462 | } | 1464 | } |
| 1463 | 1465 | ||
| 1464 | static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, | 1466 | static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, |
| 1465 | struct nlmsghdr *, int *)) | 1467 | struct nlmsghdr *, int *)) |
| 1466 | { | 1468 | { |
| 1467 | unsigned int total_len; | ||
| 1468 | struct nlmsghdr *nlh; | 1469 | struct nlmsghdr *nlh; |
| 1469 | int err; | 1470 | int err; |
| 1470 | 1471 | ||
| @@ -1474,8 +1475,6 @@ static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, | |||
| 1474 | if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len) | 1475 | if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len) |
| 1475 | return 0; | 1476 | return 0; |
| 1476 | 1477 | ||
| 1477 | total_len = min(NLMSG_ALIGN(nlh->nlmsg_len), skb->len); | ||
| 1478 | |||
| 1479 | if (cb(skb, nlh, &err) < 0) { | 1478 | if (cb(skb, nlh, &err) < 0) { |
| 1480 | /* Not an error, but we have to interrupt processing | 1479 | /* Not an error, but we have to interrupt processing |
| 1481 | * here. Note: that in this case we do not pull | 1480 | * here. Note: that in this case we do not pull |
| @@ -1487,7 +1486,7 @@ static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, | |||
| 1487 | } else if (nlh->nlmsg_flags & NLM_F_ACK) | 1486 | } else if (nlh->nlmsg_flags & NLM_F_ACK) |
| 1488 | netlink_ack(skb, nlh, 0); | 1487 | netlink_ack(skb, nlh, 0); |
| 1489 | 1488 | ||
| 1490 | skb_pull(skb, total_len); | 1489 | netlink_queue_skip(nlh, skb); |
| 1491 | } | 1490 | } |
| 1492 | 1491 | ||
| 1493 | return 0; | 1492 | return 0; |
| @@ -1550,6 +1549,38 @@ void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb) | |||
| 1550 | skb_pull(skb, msglen); | 1549 | skb_pull(skb, msglen); |
| 1551 | } | 1550 | } |
| 1552 | 1551 | ||
| 1552 | /** | ||
| 1553 | * nlmsg_notify - send a notification netlink message | ||
| 1554 | * @sk: netlink socket to use | ||
| 1555 | * @skb: notification message | ||
| 1556 | * @pid: destination netlink pid for reports or 0 | ||
| 1557 | * @group: destination multicast group or 0 | ||
| 1558 | * @report: 1 to report back, 0 to disable | ||
| 1559 | * @flags: allocation flags | ||
| 1560 | */ | ||
| 1561 | int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid, | ||
| 1562 | unsigned int group, int report, gfp_t flags) | ||
| 1563 | { | ||
| 1564 | int err = 0; | ||
| 1565 | |||
| 1566 | if (group) { | ||
| 1567 | int exclude_pid = 0; | ||
| 1568 | |||
| 1569 | if (report) { | ||
| 1570 | atomic_inc(&skb->users); | ||
| 1571 | exclude_pid = pid; | ||
| 1572 | } | ||
| 1573 | |||
| 1574 | /* errors reported via destination sk->sk_err */ | ||
| 1575 | nlmsg_multicast(sk, skb, exclude_pid, group, flags); | ||
| 1576 | } | ||
| 1577 | |||
| 1578 | if (report) | ||
| 1579 | err = nlmsg_unicast(sk, skb, pid); | ||
| 1580 | |||
| 1581 | return err; | ||
| 1582 | } | ||
| 1583 | |||
| 1553 | #ifdef CONFIG_PROC_FS | 1584 | #ifdef CONFIG_PROC_FS |
| 1554 | struct nl_seq_iter { | 1585 | struct nl_seq_iter { |
| 1555 | int link; | 1586 | int link; |
| @@ -1669,7 +1700,7 @@ static int netlink_seq_open(struct inode *inode, struct file *file) | |||
| 1669 | struct nl_seq_iter *iter; | 1700 | struct nl_seq_iter *iter; |
| 1670 | int err; | 1701 | int err; |
| 1671 | 1702 | ||
| 1672 | iter = kmalloc(sizeof(*iter), GFP_KERNEL); | 1703 | iter = kzalloc(sizeof(*iter), GFP_KERNEL); |
| 1673 | if (!iter) | 1704 | if (!iter) |
| 1674 | return -ENOMEM; | 1705 | return -ENOMEM; |
| 1675 | 1706 | ||
| @@ -1679,7 +1710,6 @@ static int netlink_seq_open(struct inode *inode, struct file *file) | |||
| 1679 | return err; | 1710 | return err; |
| 1680 | } | 1711 | } |
| 1681 | 1712 | ||
| 1682 | memset(iter, 0, sizeof(*iter)); | ||
| 1683 | seq = file->private_data; | 1713 | seq = file->private_data; |
| 1684 | seq->private = iter; | 1714 | seq->private = iter; |
| 1685 | return 0; | 1715 | return 0; |
| @@ -1732,8 +1762,6 @@ static struct net_proto_family netlink_family_ops = { | |||
| 1732 | .owner = THIS_MODULE, /* for consistency 8) */ | 1762 | .owner = THIS_MODULE, /* for consistency 8) */ |
| 1733 | }; | 1763 | }; |
| 1734 | 1764 | ||
| 1735 | extern void netlink_skb_parms_too_large(void); | ||
| 1736 | |||
| 1737 | static int __init netlink_proto_init(void) | 1765 | static int __init netlink_proto_init(void) |
| 1738 | { | 1766 | { |
| 1739 | struct sk_buff *dummy_skb; | 1767 | struct sk_buff *dummy_skb; |
| @@ -1745,17 +1773,11 @@ static int __init netlink_proto_init(void) | |||
| 1745 | if (err != 0) | 1773 | if (err != 0) |
| 1746 | goto out; | 1774 | goto out; |
| 1747 | 1775 | ||
| 1748 | if (sizeof(struct netlink_skb_parms) > sizeof(dummy_skb->cb)) | 1776 | BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > sizeof(dummy_skb->cb)); |
| 1749 | netlink_skb_parms_too_large(); | ||
| 1750 | |||
| 1751 | nl_table = kmalloc(sizeof(*nl_table) * MAX_LINKS, GFP_KERNEL); | ||
| 1752 | if (!nl_table) { | ||
| 1753 | enomem: | ||
| 1754 | printk(KERN_CRIT "netlink_init: Cannot allocate nl_table\n"); | ||
| 1755 | return -ENOMEM; | ||
| 1756 | } | ||
| 1757 | 1777 | ||
| 1758 | memset(nl_table, 0, sizeof(*nl_table) * MAX_LINKS); | 1778 | nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL); |
| 1779 | if (!nl_table) | ||
| 1780 | goto panic; | ||
| 1759 | 1781 | ||
| 1760 | if (num_physpages >= (128 * 1024)) | 1782 | if (num_physpages >= (128 * 1024)) |
| 1761 | max = num_physpages >> (21 - PAGE_SHIFT); | 1783 | max = num_physpages >> (21 - PAGE_SHIFT); |
| @@ -1775,7 +1797,7 @@ enomem: | |||
| 1775 | nl_pid_hash_free(nl_table[i].hash.table, | 1797 | nl_pid_hash_free(nl_table[i].hash.table, |
| 1776 | 1 * sizeof(*hash->table)); | 1798 | 1 * sizeof(*hash->table)); |
| 1777 | kfree(nl_table); | 1799 | kfree(nl_table); |
| 1778 | goto enomem; | 1800 | goto panic; |
| 1779 | } | 1801 | } |
| 1780 | memset(hash->table, 0, 1 * sizeof(*hash->table)); | 1802 | memset(hash->table, 0, 1 * sizeof(*hash->table)); |
| 1781 | hash->max_shift = order; | 1803 | hash->max_shift = order; |
| @@ -1792,6 +1814,8 @@ enomem: | |||
| 1792 | rtnetlink_init(); | 1814 | rtnetlink_init(); |
| 1793 | out: | 1815 | out: |
| 1794 | return err; | 1816 | return err; |
| 1817 | panic: | ||
| 1818 | panic("netlink_init: Cannot allocate nl_table\n"); | ||
| 1795 | } | 1819 | } |
| 1796 | 1820 | ||
| 1797 | core_initcall(netlink_proto_init); | 1821 | core_initcall(netlink_proto_init); |
| @@ -1807,4 +1831,4 @@ EXPORT_SYMBOL(netlink_set_err); | |||
| 1807 | EXPORT_SYMBOL(netlink_set_nonroot); | 1831 | EXPORT_SYMBOL(netlink_set_nonroot); |
| 1808 | EXPORT_SYMBOL(netlink_unicast); | 1832 | EXPORT_SYMBOL(netlink_unicast); |
| 1809 | EXPORT_SYMBOL(netlink_unregister_notifier); | 1833 | EXPORT_SYMBOL(netlink_unregister_notifier); |
| 1810 | 1834 | EXPORT_SYMBOL(nlmsg_notify); | |
