diff options
Diffstat (limited to 'net/netlink')
-rw-r--r-- | net/netlink/af_netlink.c | 80 | ||||
-rw-r--r-- | net/netlink/attr.c | 124 | ||||
-rw-r--r-- | net/netlink/genetlink.c | 54 |
3 files changed, 216 insertions, 42 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 8b85036ba8e3..d56e0d21f919 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -1147,7 +1147,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1147 | if (len > sk->sk_sndbuf - 32) | 1147 | if (len > sk->sk_sndbuf - 32) |
1148 | goto out; | 1148 | goto out; |
1149 | err = -ENOBUFS; | 1149 | err = -ENOBUFS; |
1150 | skb = alloc_skb(len, GFP_KERNEL); | 1150 | skb = nlmsg_new(len, GFP_KERNEL); |
1151 | if (skb==NULL) | 1151 | if (skb==NULL) |
1152 | goto out; | 1152 | goto out; |
1153 | 1153 | ||
@@ -1341,19 +1341,18 @@ static int netlink_dump(struct sock *sk) | |||
1341 | struct netlink_callback *cb; | 1341 | struct netlink_callback *cb; |
1342 | struct sk_buff *skb; | 1342 | struct sk_buff *skb; |
1343 | struct nlmsghdr *nlh; | 1343 | struct nlmsghdr *nlh; |
1344 | int len; | 1344 | int len, err = -ENOBUFS; |
1345 | 1345 | ||
1346 | skb = sock_rmalloc(sk, NLMSG_GOODSIZE, 0, GFP_KERNEL); | 1346 | skb = sock_rmalloc(sk, NLMSG_GOODSIZE, 0, GFP_KERNEL); |
1347 | if (!skb) | 1347 | if (!skb) |
1348 | return -ENOBUFS; | 1348 | goto errout; |
1349 | 1349 | ||
1350 | spin_lock(&nlk->cb_lock); | 1350 | spin_lock(&nlk->cb_lock); |
1351 | 1351 | ||
1352 | cb = nlk->cb; | 1352 | cb = nlk->cb; |
1353 | if (cb == NULL) { | 1353 | if (cb == NULL) { |
1354 | spin_unlock(&nlk->cb_lock); | 1354 | err = -EINVAL; |
1355 | kfree_skb(skb); | 1355 | goto errout_skb; |
1356 | return -EINVAL; | ||
1357 | } | 1356 | } |
1358 | 1357 | ||
1359 | len = cb->dump(skb, cb); | 1358 | len = cb->dump(skb, cb); |
@@ -1365,8 +1364,12 @@ static int netlink_dump(struct sock *sk) | |||
1365 | return 0; | 1364 | return 0; |
1366 | } | 1365 | } |
1367 | 1366 | ||
1368 | 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); |
1369 | memcpy(NLMSG_DATA(nlh), &len, sizeof(len)); | 1368 | if (!nlh) |
1369 | goto errout_skb; | ||
1370 | |||
1371 | memcpy(nlmsg_data(nlh), &len, sizeof(len)); | ||
1372 | |||
1370 | skb_queue_tail(&sk->sk_receive_queue, skb); | 1373 | skb_queue_tail(&sk->sk_receive_queue, skb); |
1371 | sk->sk_data_ready(sk, skb->len); | 1374 | sk->sk_data_ready(sk, skb->len); |
1372 | 1375 | ||
@@ -1378,8 +1381,11 @@ static int netlink_dump(struct sock *sk) | |||
1378 | netlink_destroy_callback(cb); | 1381 | netlink_destroy_callback(cb); |
1379 | return 0; | 1382 | return 0; |
1380 | 1383 | ||
1381 | nlmsg_failure: | 1384 | errout_skb: |
1382 | return -ENOBUFS; | 1385 | spin_unlock(&nlk->cb_lock); |
1386 | kfree_skb(skb); | ||
1387 | errout: | ||
1388 | return err; | ||
1383 | } | 1389 | } |
1384 | 1390 | ||
1385 | int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, | 1391 | int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, |
@@ -1431,11 +1437,11 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) | |||
1431 | int size; | 1437 | int size; |
1432 | 1438 | ||
1433 | if (err == 0) | 1439 | if (err == 0) |
1434 | size = NLMSG_SPACE(sizeof(struct nlmsgerr)); | 1440 | size = nlmsg_total_size(sizeof(*errmsg)); |
1435 | else | 1441 | else |
1436 | size = NLMSG_SPACE(4 + NLMSG_ALIGN(nlh->nlmsg_len)); | 1442 | size = nlmsg_total_size(sizeof(*errmsg) + nlmsg_len(nlh)); |
1437 | 1443 | ||
1438 | skb = alloc_skb(size, GFP_KERNEL); | 1444 | skb = nlmsg_new(size, GFP_KERNEL); |
1439 | if (!skb) { | 1445 | if (!skb) { |
1440 | struct sock *sk; | 1446 | struct sock *sk; |
1441 | 1447 | ||
@@ -1451,16 +1457,15 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) | |||
1451 | 1457 | ||
1452 | 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, |
1453 | NLMSG_ERROR, sizeof(struct nlmsgerr), 0); | 1459 | NLMSG_ERROR, sizeof(struct nlmsgerr), 0); |
1454 | errmsg = NLMSG_DATA(rep); | 1460 | errmsg = nlmsg_data(rep); |
1455 | errmsg->error = err; | 1461 | errmsg->error = err; |
1456 | memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(struct nlmsghdr)); | 1462 | memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(*nlh)); |
1457 | 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); |
1458 | } | 1464 | } |
1459 | 1465 | ||
1460 | 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 *, |
1461 | struct nlmsghdr *, int *)) | 1467 | struct nlmsghdr *, int *)) |
1462 | { | 1468 | { |
1463 | unsigned int total_len; | ||
1464 | struct nlmsghdr *nlh; | 1469 | struct nlmsghdr *nlh; |
1465 | int err; | 1470 | int err; |
1466 | 1471 | ||
@@ -1470,8 +1475,6 @@ static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, | |||
1470 | if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len) | 1475 | if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len) |
1471 | return 0; | 1476 | return 0; |
1472 | 1477 | ||
1473 | total_len = min(NLMSG_ALIGN(nlh->nlmsg_len), skb->len); | ||
1474 | |||
1475 | if (cb(skb, nlh, &err) < 0) { | 1478 | if (cb(skb, nlh, &err) < 0) { |
1476 | /* Not an error, but we have to interrupt processing | 1479 | /* Not an error, but we have to interrupt processing |
1477 | * here. Note: that in this case we do not pull | 1480 | * here. Note: that in this case we do not pull |
@@ -1483,7 +1486,7 @@ static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, | |||
1483 | } else if (nlh->nlmsg_flags & NLM_F_ACK) | 1486 | } else if (nlh->nlmsg_flags & NLM_F_ACK) |
1484 | netlink_ack(skb, nlh, 0); | 1487 | netlink_ack(skb, nlh, 0); |
1485 | 1488 | ||
1486 | skb_pull(skb, total_len); | 1489 | netlink_queue_skip(nlh, skb); |
1487 | } | 1490 | } |
1488 | 1491 | ||
1489 | return 0; | 1492 | return 0; |
@@ -1546,6 +1549,38 @@ void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb) | |||
1546 | skb_pull(skb, msglen); | 1549 | skb_pull(skb, msglen); |
1547 | } | 1550 | } |
1548 | 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 | |||
1549 | #ifdef CONFIG_PROC_FS | 1584 | #ifdef CONFIG_PROC_FS |
1550 | struct nl_seq_iter { | 1585 | struct nl_seq_iter { |
1551 | int link; | 1586 | int link; |
@@ -1727,8 +1762,6 @@ static struct net_proto_family netlink_family_ops = { | |||
1727 | .owner = THIS_MODULE, /* for consistency 8) */ | 1762 | .owner = THIS_MODULE, /* for consistency 8) */ |
1728 | }; | 1763 | }; |
1729 | 1764 | ||
1730 | extern void netlink_skb_parms_too_large(void); | ||
1731 | |||
1732 | static int __init netlink_proto_init(void) | 1765 | static int __init netlink_proto_init(void) |
1733 | { | 1766 | { |
1734 | struct sk_buff *dummy_skb; | 1767 | struct sk_buff *dummy_skb; |
@@ -1740,8 +1773,7 @@ static int __init netlink_proto_init(void) | |||
1740 | if (err != 0) | 1773 | if (err != 0) |
1741 | goto out; | 1774 | goto out; |
1742 | 1775 | ||
1743 | if (sizeof(struct netlink_skb_parms) > sizeof(dummy_skb->cb)) | 1776 | BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > sizeof(dummy_skb->cb)); |
1744 | netlink_skb_parms_too_large(); | ||
1745 | 1777 | ||
1746 | nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL); | 1778 | nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL); |
1747 | if (!nl_table) | 1779 | if (!nl_table) |
@@ -1799,4 +1831,4 @@ EXPORT_SYMBOL(netlink_set_err); | |||
1799 | EXPORT_SYMBOL(netlink_set_nonroot); | 1831 | EXPORT_SYMBOL(netlink_set_nonroot); |
1800 | EXPORT_SYMBOL(netlink_unicast); | 1832 | EXPORT_SYMBOL(netlink_unicast); |
1801 | EXPORT_SYMBOL(netlink_unregister_notifier); | 1833 | EXPORT_SYMBOL(netlink_unregister_notifier); |
1802 | 1834 | EXPORT_SYMBOL(nlmsg_notify); | |
diff --git a/net/netlink/attr.c b/net/netlink/attr.c index dddbd15135a8..004139557e09 100644 --- a/net/netlink/attr.c +++ b/net/netlink/attr.c | |||
@@ -20,7 +20,6 @@ static u16 nla_attr_minlen[NLA_TYPE_MAX+1] __read_mostly = { | |||
20 | [NLA_U16] = sizeof(u16), | 20 | [NLA_U16] = sizeof(u16), |
21 | [NLA_U32] = sizeof(u32), | 21 | [NLA_U32] = sizeof(u32), |
22 | [NLA_U64] = sizeof(u64), | 22 | [NLA_U64] = sizeof(u64), |
23 | [NLA_STRING] = 1, | ||
24 | [NLA_NESTED] = NLA_HDRLEN, | 23 | [NLA_NESTED] = NLA_HDRLEN, |
25 | }; | 24 | }; |
26 | 25 | ||
@@ -28,7 +27,7 @@ static int validate_nla(struct nlattr *nla, int maxtype, | |||
28 | struct nla_policy *policy) | 27 | struct nla_policy *policy) |
29 | { | 28 | { |
30 | struct nla_policy *pt; | 29 | struct nla_policy *pt; |
31 | int minlen = 0; | 30 | int minlen = 0, attrlen = nla_len(nla); |
32 | 31 | ||
33 | if (nla->nla_type <= 0 || nla->nla_type > maxtype) | 32 | if (nla->nla_type <= 0 || nla->nla_type > maxtype) |
34 | return 0; | 33 | return 0; |
@@ -37,16 +36,46 @@ static int validate_nla(struct nlattr *nla, int maxtype, | |||
37 | 36 | ||
38 | BUG_ON(pt->type > NLA_TYPE_MAX); | 37 | BUG_ON(pt->type > NLA_TYPE_MAX); |
39 | 38 | ||
40 | if (pt->minlen) | 39 | switch (pt->type) { |
41 | minlen = pt->minlen; | 40 | case NLA_FLAG: |
42 | else if (pt->type != NLA_UNSPEC) | 41 | if (attrlen > 0) |
43 | minlen = nla_attr_minlen[pt->type]; | 42 | return -ERANGE; |
43 | break; | ||
44 | 44 | ||
45 | if (pt->type == NLA_FLAG && nla_len(nla) > 0) | 45 | case NLA_NUL_STRING: |
46 | return -ERANGE; | 46 | if (pt->len) |
47 | minlen = min_t(int, attrlen, pt->len + 1); | ||
48 | else | ||
49 | minlen = attrlen; | ||
47 | 50 | ||
48 | if (nla_len(nla) < minlen) | 51 | if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL) |
49 | return -ERANGE; | 52 | return -EINVAL; |
53 | /* fall through */ | ||
54 | |||
55 | case NLA_STRING: | ||
56 | if (attrlen < 1) | ||
57 | return -ERANGE; | ||
58 | |||
59 | if (pt->len) { | ||
60 | char *buf = nla_data(nla); | ||
61 | |||
62 | if (buf[attrlen - 1] == '\0') | ||
63 | attrlen--; | ||
64 | |||
65 | if (attrlen > pt->len) | ||
66 | return -ERANGE; | ||
67 | } | ||
68 | break; | ||
69 | |||
70 | default: | ||
71 | if (pt->len) | ||
72 | minlen = pt->len; | ||
73 | else if (pt->type != NLA_UNSPEC) | ||
74 | minlen = nla_attr_minlen[pt->type]; | ||
75 | |||
76 | if (attrlen < minlen) | ||
77 | return -ERANGE; | ||
78 | } | ||
50 | 79 | ||
51 | return 0; | 80 | return 0; |
52 | } | 81 | } |
@@ -255,6 +284,26 @@ struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) | |||
255 | } | 284 | } |
256 | 285 | ||
257 | /** | 286 | /** |
287 | * __nla_reserve_nohdr - reserve room for attribute without header | ||
288 | * @skb: socket buffer to reserve room on | ||
289 | * @attrlen: length of attribute payload | ||
290 | * | ||
291 | * Reserves room for attribute payload without a header. | ||
292 | * | ||
293 | * The caller is responsible to ensure that the skb provides enough | ||
294 | * tailroom for the payload. | ||
295 | */ | ||
296 | void *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen) | ||
297 | { | ||
298 | void *start; | ||
299 | |||
300 | start = skb_put(skb, NLA_ALIGN(attrlen)); | ||
301 | memset(start, 0, NLA_ALIGN(attrlen)); | ||
302 | |||
303 | return start; | ||
304 | } | ||
305 | |||
306 | /** | ||
258 | * nla_reserve - reserve room for attribute on the skb | 307 | * nla_reserve - reserve room for attribute on the skb |
259 | * @skb: socket buffer to reserve room on | 308 | * @skb: socket buffer to reserve room on |
260 | * @attrtype: attribute type | 309 | * @attrtype: attribute type |
@@ -275,6 +324,24 @@ struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) | |||
275 | } | 324 | } |
276 | 325 | ||
277 | /** | 326 | /** |
327 | * nla_reserve - reserve room for attribute without header | ||
328 | * @skb: socket buffer to reserve room on | ||
329 | * @len: length of attribute payload | ||
330 | * | ||
331 | * Reserves room for attribute payload without a header. | ||
332 | * | ||
333 | * Returns NULL if the tailroom of the skb is insufficient to store | ||
334 | * the attribute payload. | ||
335 | */ | ||
336 | void *nla_reserve_nohdr(struct sk_buff *skb, int attrlen) | ||
337 | { | ||
338 | if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen))) | ||
339 | return NULL; | ||
340 | |||
341 | return __nla_reserve_nohdr(skb, attrlen); | ||
342 | } | ||
343 | |||
344 | /** | ||
278 | * __nla_put - Add a netlink attribute to a socket buffer | 345 | * __nla_put - Add a netlink attribute to a socket buffer |
279 | * @skb: socket buffer to add attribute to | 346 | * @skb: socket buffer to add attribute to |
280 | * @attrtype: attribute type | 347 | * @attrtype: attribute type |
@@ -293,6 +360,22 @@ void __nla_put(struct sk_buff *skb, int attrtype, int attrlen, | |||
293 | memcpy(nla_data(nla), data, attrlen); | 360 | memcpy(nla_data(nla), data, attrlen); |
294 | } | 361 | } |
295 | 362 | ||
363 | /** | ||
364 | * __nla_put_nohdr - Add a netlink attribute without header | ||
365 | * @skb: socket buffer to add attribute to | ||
366 | * @attrlen: length of attribute payload | ||
367 | * @data: head of attribute payload | ||
368 | * | ||
369 | * The caller is responsible to ensure that the skb provides enough | ||
370 | * tailroom for the attribute payload. | ||
371 | */ | ||
372 | void __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data) | ||
373 | { | ||
374 | void *start; | ||
375 | |||
376 | start = __nla_reserve_nohdr(skb, attrlen); | ||
377 | memcpy(start, data, attrlen); | ||
378 | } | ||
296 | 379 | ||
297 | /** | 380 | /** |
298 | * nla_put - Add a netlink attribute to a socket buffer | 381 | * nla_put - Add a netlink attribute to a socket buffer |
@@ -313,15 +396,36 @@ int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data) | |||
313 | return 0; | 396 | return 0; |
314 | } | 397 | } |
315 | 398 | ||
399 | /** | ||
400 | * nla_put_nohdr - Add a netlink attribute without header | ||
401 | * @skb: socket buffer to add attribute to | ||
402 | * @attrlen: length of attribute payload | ||
403 | * @data: head of attribute payload | ||
404 | * | ||
405 | * Returns -1 if the tailroom of the skb is insufficient to store | ||
406 | * the attribute payload. | ||
407 | */ | ||
408 | int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data) | ||
409 | { | ||
410 | if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen))) | ||
411 | return -1; | ||
412 | |||
413 | __nla_put_nohdr(skb, attrlen, data); | ||
414 | return 0; | ||
415 | } | ||
316 | 416 | ||
317 | EXPORT_SYMBOL(nla_validate); | 417 | EXPORT_SYMBOL(nla_validate); |
318 | EXPORT_SYMBOL(nla_parse); | 418 | EXPORT_SYMBOL(nla_parse); |
319 | EXPORT_SYMBOL(nla_find); | 419 | EXPORT_SYMBOL(nla_find); |
320 | EXPORT_SYMBOL(nla_strlcpy); | 420 | EXPORT_SYMBOL(nla_strlcpy); |
321 | EXPORT_SYMBOL(__nla_reserve); | 421 | EXPORT_SYMBOL(__nla_reserve); |
422 | EXPORT_SYMBOL(__nla_reserve_nohdr); | ||
322 | EXPORT_SYMBOL(nla_reserve); | 423 | EXPORT_SYMBOL(nla_reserve); |
424 | EXPORT_SYMBOL(nla_reserve_nohdr); | ||
323 | EXPORT_SYMBOL(__nla_put); | 425 | EXPORT_SYMBOL(__nla_put); |
426 | EXPORT_SYMBOL(__nla_put_nohdr); | ||
324 | EXPORT_SYMBOL(nla_put); | 427 | EXPORT_SYMBOL(nla_put); |
428 | EXPORT_SYMBOL(nla_put_nohdr); | ||
325 | EXPORT_SYMBOL(nla_memcpy); | 429 | EXPORT_SYMBOL(nla_memcpy); |
326 | EXPORT_SYMBOL(nla_memcmp); | 430 | EXPORT_SYMBOL(nla_memcmp); |
327 | EXPORT_SYMBOL(nla_strcmp); | 431 | EXPORT_SYMBOL(nla_strcmp); |
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index a298f77cc3e3..49bc2db7982b 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c | |||
@@ -387,7 +387,10 @@ static void genl_rcv(struct sock *sk, int len) | |||
387 | static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq, | 387 | static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq, |
388 | u32 flags, struct sk_buff *skb, u8 cmd) | 388 | u32 flags, struct sk_buff *skb, u8 cmd) |
389 | { | 389 | { |
390 | struct nlattr *nla_ops; | ||
391 | struct genl_ops *ops; | ||
390 | void *hdr; | 392 | void *hdr; |
393 | int idx = 1; | ||
391 | 394 | ||
392 | hdr = genlmsg_put(skb, pid, seq, GENL_ID_CTRL, 0, flags, cmd, | 395 | hdr = genlmsg_put(skb, pid, seq, GENL_ID_CTRL, 0, flags, cmd, |
393 | family->version); | 396 | family->version); |
@@ -396,6 +399,37 @@ static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq, | |||
396 | 399 | ||
397 | NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, family->name); | 400 | NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, family->name); |
398 | NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, family->id); | 401 | NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, family->id); |
402 | NLA_PUT_U32(skb, CTRL_ATTR_VERSION, family->version); | ||
403 | NLA_PUT_U32(skb, CTRL_ATTR_HDRSIZE, family->hdrsize); | ||
404 | NLA_PUT_U32(skb, CTRL_ATTR_MAXATTR, family->maxattr); | ||
405 | |||
406 | nla_ops = nla_nest_start(skb, CTRL_ATTR_OPS); | ||
407 | if (nla_ops == NULL) | ||
408 | goto nla_put_failure; | ||
409 | |||
410 | list_for_each_entry(ops, &family->ops_list, ops_list) { | ||
411 | struct nlattr *nest; | ||
412 | |||
413 | nest = nla_nest_start(skb, idx++); | ||
414 | if (nest == NULL) | ||
415 | goto nla_put_failure; | ||
416 | |||
417 | NLA_PUT_U32(skb, CTRL_ATTR_OP_ID, ops->cmd); | ||
418 | NLA_PUT_U32(skb, CTRL_ATTR_OP_FLAGS, ops->flags); | ||
419 | |||
420 | if (ops->policy) | ||
421 | NLA_PUT_FLAG(skb, CTRL_ATTR_OP_POLICY); | ||
422 | |||
423 | if (ops->doit) | ||
424 | NLA_PUT_FLAG(skb, CTRL_ATTR_OP_DOIT); | ||
425 | |||
426 | if (ops->dumpit) | ||
427 | NLA_PUT_FLAG(skb, CTRL_ATTR_OP_DUMPIT); | ||
428 | |||
429 | nla_nest_end(skb, nest); | ||
430 | } | ||
431 | |||
432 | nla_nest_end(skb, nla_ops); | ||
399 | 433 | ||
400 | return genlmsg_end(skb, hdr); | 434 | return genlmsg_end(skb, hdr); |
401 | 435 | ||
@@ -411,6 +445,9 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) | |||
411 | int chains_to_skip = cb->args[0]; | 445 | int chains_to_skip = cb->args[0]; |
412 | int fams_to_skip = cb->args[1]; | 446 | int fams_to_skip = cb->args[1]; |
413 | 447 | ||
448 | if (chains_to_skip != 0) | ||
449 | genl_lock(); | ||
450 | |||
414 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { | 451 | for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { |
415 | if (i < chains_to_skip) | 452 | if (i < chains_to_skip) |
416 | continue; | 453 | continue; |
@@ -428,6 +465,9 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) | |||
428 | } | 465 | } |
429 | 466 | ||
430 | errout: | 467 | errout: |
468 | if (chains_to_skip != 0) | ||
469 | genl_unlock(); | ||
470 | |||
431 | cb->args[0] = i; | 471 | cb->args[0] = i; |
432 | cb->args[1] = n; | 472 | cb->args[1] = n; |
433 | 473 | ||
@@ -440,7 +480,7 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid, | |||
440 | struct sk_buff *skb; | 480 | struct sk_buff *skb; |
441 | int err; | 481 | int err; |
442 | 482 | ||
443 | skb = nlmsg_new(NLMSG_GOODSIZE); | 483 | skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); |
444 | if (skb == NULL) | 484 | if (skb == NULL) |
445 | return ERR_PTR(-ENOBUFS); | 485 | return ERR_PTR(-ENOBUFS); |
446 | 486 | ||
@@ -455,7 +495,8 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid, | |||
455 | 495 | ||
456 | static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] __read_mostly = { | 496 | static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] __read_mostly = { |
457 | [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, | 497 | [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, |
458 | [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING }, | 498 | [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING, |
499 | .len = GENL_NAMSIZ - 1 }, | ||
459 | }; | 500 | }; |
460 | 501 | ||
461 | static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) | 502 | static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) |
@@ -470,12 +511,9 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) | |||
470 | } | 511 | } |
471 | 512 | ||
472 | if (info->attrs[CTRL_ATTR_FAMILY_NAME]) { | 513 | if (info->attrs[CTRL_ATTR_FAMILY_NAME]) { |
473 | char name[GENL_NAMSIZ]; | 514 | char *name; |
474 | |||
475 | if (nla_strlcpy(name, info->attrs[CTRL_ATTR_FAMILY_NAME], | ||
476 | GENL_NAMSIZ) >= GENL_NAMSIZ) | ||
477 | goto errout; | ||
478 | 515 | ||
516 | name = nla_data(info->attrs[CTRL_ATTR_FAMILY_NAME]); | ||
479 | res = genl_family_find_byname(name); | 517 | res = genl_family_find_byname(name); |
480 | } | 518 | } |
481 | 519 | ||
@@ -510,7 +548,7 @@ static int genl_ctrl_event(int event, void *data) | |||
510 | if (IS_ERR(msg)) | 548 | if (IS_ERR(msg)) |
511 | return PTR_ERR(msg); | 549 | return PTR_ERR(msg); |
512 | 550 | ||
513 | genlmsg_multicast(msg, 0, GENL_ID_CTRL); | 551 | genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL); |
514 | break; | 552 | break; |
515 | } | 553 | } |
516 | 554 | ||