aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2005-11-09 20:25:53 -0500
committerThomas Graf <tgr@axs.localdomain>2005-11-09 20:26:40 -0500
commit82ace47a7256fd39d370a6442e0649f75961b831 (patch)
tree261fafd7cb6b8b7bf023fa26cba1636ae2ec2f79
parenta8f74b228826eef1cbe04a05647d61e896f5fd63 (diff)
[NETLINK]: Generic netlink receive queue processor
Introduces netlink_run_queue() to handle the receive queue of a netlink socket in a generic way. Processes as much as there was in the queue upon entry and invokes a callback function for each netlink message found. The callback function may refuse a message by returning a negative error code but setting the error pointer to 0 in which case netlink_run_queue() will return with a qlen != 0. Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/netlink.h6
-rw-r--r--net/netlink/af_netlink.c91
2 files changed, 97 insertions, 0 deletions
diff --git a/include/net/netlink.h b/include/net/netlink.h
index c99e22db9632..640c26a90cf1 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -183,6 +183,12 @@ struct nla_policy {
183 u16 minlen; 183 u16 minlen;
184}; 184};
185 185
186extern void netlink_run_queue(struct sock *sk, unsigned int *qlen,
187 int (*cb)(struct sk_buff *,
188 struct nlmsghdr *, int *));
189extern void netlink_queue_skip(struct nlmsghdr *nlh,
190 struct sk_buff *skb);
191
186extern int nla_validate(struct nlattr *head, int len, int maxtype, 192extern int nla_validate(struct nlattr *head, int len, int maxtype,
187 struct nla_policy *policy); 193 struct nla_policy *policy);
188extern int nla_parse(struct nlattr *tb[], int maxtype, 194extern int nla_parse(struct nlattr *tb[], int maxtype,
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index f3fb7e575816..8c38ee6d255e 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -58,6 +58,7 @@
58 58
59#include <net/sock.h> 59#include <net/sock.h>
60#include <net/scm.h> 60#include <net/scm.h>
61#include <net/netlink.h>
61 62
62#define Nprintk(a...) 63#define Nprintk(a...)
63#define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) 64#define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8)
@@ -1411,6 +1412,94 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
1411 netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); 1412 netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
1412} 1413}
1413 1414
1415static int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
1416 struct nlmsghdr *, int *))
1417{
1418 unsigned int total_len;
1419 struct nlmsghdr *nlh;
1420 int err;
1421
1422 while (skb->len >= nlmsg_total_size(0)) {
1423 nlh = (struct nlmsghdr *) skb->data;
1424
1425 if (skb->len < nlh->nlmsg_len)
1426 return 0;
1427
1428 total_len = min(NLMSG_ALIGN(nlh->nlmsg_len), skb->len);
1429
1430 if (cb(skb, nlh, &err) < 0) {
1431 /* Not an error, but we have to interrupt processing
1432 * here. Note: that in this case we do not pull
1433 * message from skb, it will be processed later.
1434 */
1435 if (err == 0)
1436 return -1;
1437 netlink_ack(skb, nlh, err);
1438 } else if (nlh->nlmsg_flags & NLM_F_ACK)
1439 netlink_ack(skb, nlh, 0);
1440
1441 skb_pull(skb, total_len);
1442 }
1443
1444 return 0;
1445}
1446
1447/**
1448 * nelink_run_queue - Process netlink receive queue.
1449 * @sk: Netlink socket containing the queue
1450 * @qlen: Place to store queue length upon entry
1451 * @cb: Callback function invoked for each netlink message found
1452 *
1453 * Processes as much as there was in the queue upon entry and invokes
1454 * a callback function for each netlink message found. The callback
1455 * function may refuse a message by returning a negative error code
1456 * but setting the error pointer to 0 in which case this function
1457 * returns with a qlen != 0.
1458 *
1459 * qlen must be initialized to 0 before the initial entry, afterwards
1460 * the function may be called repeatedly until qlen reaches 0.
1461 */
1462void netlink_run_queue(struct sock *sk, unsigned int *qlen,
1463 int (*cb)(struct sk_buff *, struct nlmsghdr *, int *))
1464{
1465 struct sk_buff *skb;
1466
1467 if (!*qlen || *qlen > skb_queue_len(&sk->sk_receive_queue))
1468 *qlen = skb_queue_len(&sk->sk_receive_queue);
1469
1470 for (; *qlen; (*qlen)--) {
1471 skb = skb_dequeue(&sk->sk_receive_queue);
1472 if (netlink_rcv_skb(skb, cb)) {
1473 if (skb->len)
1474 skb_queue_head(&sk->sk_receive_queue, skb);
1475 else {
1476 kfree_skb(skb);
1477 (*qlen)--;
1478 }
1479 break;
1480 }
1481
1482 kfree_skb(skb);
1483 }
1484}
1485
1486/**
1487 * netlink_queue_skip - Skip netlink message while processing queue.
1488 * @nlh: Netlink message to be skipped
1489 * @skb: Socket buffer containing the netlink messages.
1490 *
1491 * Pulls the given netlink message off the socket buffer so the next
1492 * call to netlink_queue_run() will not reconsider the message.
1493 */
1494void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb)
1495{
1496 int msglen = NLMSG_ALIGN(nlh->nlmsg_len);
1497
1498 if (msglen > skb->len)
1499 msglen = skb->len;
1500
1501 skb_pull(skb, msglen);
1502}
1414 1503
1415#ifdef CONFIG_PROC_FS 1504#ifdef CONFIG_PROC_FS
1416struct nl_seq_iter { 1505struct nl_seq_iter {
@@ -1659,6 +1748,8 @@ out:
1659core_initcall(netlink_proto_init); 1748core_initcall(netlink_proto_init);
1660 1749
1661EXPORT_SYMBOL(netlink_ack); 1750EXPORT_SYMBOL(netlink_ack);
1751EXPORT_SYMBOL(netlink_run_queue);
1752EXPORT_SYMBOL(netlink_queue_skip);
1662EXPORT_SYMBOL(netlink_broadcast); 1753EXPORT_SYMBOL(netlink_broadcast);
1663EXPORT_SYMBOL(netlink_dump_start); 1754EXPORT_SYMBOL(netlink_dump_start);
1664EXPORT_SYMBOL(netlink_kernel_create); 1755EXPORT_SYMBOL(netlink_kernel_create);