aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlink/af_netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/netlink/af_netlink.c')
-rw-r--r--net/netlink/af_netlink.c116
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
158static void netlink_table_grab(void) 157static 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
180static __inline__ void netlink_table_ungrab(void) 179static __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
1384nlmsg_failure: 1384errout_skb:
1385 return -ENOBUFS; 1385 spin_unlock(&nlk->cb_lock);
1386 kfree_skb(skb);
1387errout:
1388 return err;
1386} 1389}
1387 1390
1388int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, 1391int 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
1464static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, 1466static 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 */
1561int 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
1554struct nl_seq_iter { 1585struct 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
1735extern void netlink_skb_parms_too_large(void);
1736
1737static int __init netlink_proto_init(void) 1765static 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) {
1753enomem:
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();
1793out: 1815out:
1794 return err; 1816 return err;
1817panic:
1818 panic("netlink_init: Cannot allocate nl_table\n");
1795} 1819}
1796 1820
1797core_initcall(netlink_proto_init); 1821core_initcall(netlink_proto_init);
@@ -1807,4 +1831,4 @@ EXPORT_SYMBOL(netlink_set_err);
1807EXPORT_SYMBOL(netlink_set_nonroot); 1831EXPORT_SYMBOL(netlink_set_nonroot);
1808EXPORT_SYMBOL(netlink_unicast); 1832EXPORT_SYMBOL(netlink_unicast);
1809EXPORT_SYMBOL(netlink_unregister_notifier); 1833EXPORT_SYMBOL(netlink_unregister_notifier);
1810 1834EXPORT_SYMBOL(nlmsg_notify);