aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2007-03-22 14:48:11 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-26 01:27:04 -0400
commite284986385b6420a5f30f2dcd743512bbe1a3202 (patch)
treeaee0d30b618ada57371fddfcaeb47bbd767e16e3
parent30833ffead66e1f0052150a51db0b45151189ac1 (diff)
[RTNL]: Message handler registration interface
This patch adds a new interface to register rtnetlink message handlers replacing the exported rtnl_links[] array which required many message handlers to be exported unnecessarly. Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/rtnetlink.h7
-rw-r--r--include/net/rtnetlink.h18
-rw-r--r--net/core/rtnetlink.c188
3 files changed, 184 insertions, 29 deletions
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 3a4cb242ecd2..1fae30af91f3 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -574,13 +574,6 @@ extern int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, in
574#define rtattr_parse_nested(tb, max, rta) \ 574#define rtattr_parse_nested(tb, max, rta) \
575 rtattr_parse((tb), (max), RTA_DATA((rta)), RTA_PAYLOAD((rta))) 575 rtattr_parse((tb), (max), RTA_DATA((rta)), RTA_PAYLOAD((rta)))
576 576
577struct rtnetlink_link
578{
579 int (*doit)(struct sk_buff *, struct nlmsghdr*, void *attr);
580 int (*dumpit)(struct sk_buff *, struct netlink_callback *cb);
581};
582
583extern struct rtnetlink_link * rtnetlink_links[NPROTO];
584extern int rtnetlink_send(struct sk_buff *skb, u32 pid, u32 group, int echo); 577extern int rtnetlink_send(struct sk_buff *skb, u32 pid, u32 group, int echo);
585extern int rtnl_unicast(struct sk_buff *skb, u32 pid); 578extern int rtnl_unicast(struct sk_buff *skb, u32 pid);
586extern int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group, 579extern int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group,
diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h
new file mode 100644
index 000000000000..dce7072bd28c
--- /dev/null
+++ b/include/net/rtnetlink.h
@@ -0,0 +1,18 @@
1#ifndef __NET_RTNETLINK_H
2#define __NET_RTNETLINK_H
3
4#include <linux/rtnetlink.h>
5#include <net/netlink.h>
6
7typedef int (*rtnl_doit_func)(struct sk_buff *, struct nlmsghdr *, void *);
8typedef int (*rtnl_dumpit_func)(struct sk_buff *, struct netlink_callback *);
9
10extern int __rtnl_register(int protocol, int msgtype,
11 rtnl_doit_func, rtnl_dumpit_func);
12extern void rtnl_register(int protocol, int msgtype,
13 rtnl_doit_func, rtnl_dumpit_func);
14extern int rtnl_unregister(int protocol, int msgtype);
15extern void rtnl_unregister_all(int protocol);
16extern int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb);
17
18#endif
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 33ea8eac7fe0..fb1630d82dd4 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -50,12 +50,18 @@
50#include <net/sock.h> 50#include <net/sock.h>
51#include <net/pkt_sched.h> 51#include <net/pkt_sched.h>
52#include <net/fib_rules.h> 52#include <net/fib_rules.h>
53#include <net/netlink.h> 53#include <net/rtnetlink.h>
54#ifdef CONFIG_NET_WIRELESS_RTNETLINK 54#ifdef CONFIG_NET_WIRELESS_RTNETLINK
55#include <linux/wireless.h> 55#include <linux/wireless.h>
56#include <net/iw_handler.h> 56#include <net/iw_handler.h>
57#endif /* CONFIG_NET_WIRELESS_RTNETLINK */ 57#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
58 58
59struct rtnl_link
60{
61 rtnl_doit_func doit;
62 rtnl_dumpit_func dumpit;
63};
64
59static DEFINE_MUTEX(rtnl_mutex); 65static DEFINE_MUTEX(rtnl_mutex);
60static struct sock *rtnl; 66static struct sock *rtnl;
61 67
@@ -95,7 +101,151 @@ int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len)
95 return 0; 101 return 0;
96} 102}
97 103
98struct rtnetlink_link * rtnetlink_links[NPROTO]; 104struct rtnl_link *rtnl_msg_handlers[NPROTO];
105
106static inline int rtm_msgindex(int msgtype)
107{
108 int msgindex = msgtype - RTM_BASE;
109
110 /*
111 * msgindex < 0 implies someone tried to register a netlink
112 * control code. msgindex >= RTM_NR_MSGTYPES may indicate that
113 * the message type has not been added to linux/rtnetlink.h
114 */
115 BUG_ON(msgindex < 0 || msgindex >= RTM_NR_MSGTYPES);
116
117 return msgindex;
118}
119
120static rtnl_doit_func rtnl_get_doit(int protocol, int msgindex)
121{
122 struct rtnl_link *tab;
123
124 tab = rtnl_msg_handlers[protocol];
125 if (tab == NULL || tab->doit == NULL)
126 tab = rtnl_msg_handlers[PF_UNSPEC];
127
128 return tab ? tab->doit : NULL;
129}
130
131static rtnl_dumpit_func rtnl_get_dumpit(int protocol, int msgindex)
132{
133 struct rtnl_link *tab;
134
135 tab = rtnl_msg_handlers[protocol];
136 if (tab == NULL || tab->dumpit == NULL)
137 tab = rtnl_msg_handlers[PF_UNSPEC];
138
139 return tab ? tab->dumpit : NULL;
140}
141
142/**
143 * __rtnl_register - Register a rtnetlink message type
144 * @protocol: Protocol family or PF_UNSPEC
145 * @msgtype: rtnetlink message type
146 * @doit: Function pointer called for each request message
147 * @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message
148 *
149 * Registers the specified function pointers (at least one of them has
150 * to be non-NULL) to be called whenever a request message for the
151 * specified protocol family and message type is received.
152 *
153 * The special protocol family PF_UNSPEC may be used to define fallback
154 * function pointers for the case when no entry for the specific protocol
155 * family exists.
156 *
157 * Returns 0 on success or a negative error code.
158 */
159int __rtnl_register(int protocol, int msgtype,
160 rtnl_doit_func doit, rtnl_dumpit_func dumpit)
161{
162 struct rtnl_link *tab;
163 int msgindex;
164
165 BUG_ON(protocol < 0 || protocol >= NPROTO);
166 msgindex = rtm_msgindex(msgtype);
167
168 tab = rtnl_msg_handlers[protocol];
169 if (tab == NULL) {
170 tab = kcalloc(RTM_NR_MSGTYPES, sizeof(*tab), GFP_KERNEL);
171 if (tab == NULL)
172 return -ENOBUFS;
173
174 rtnl_msg_handlers[protocol] = tab;
175 }
176
177 if (doit)
178 tab[msgindex].doit = doit;
179
180 if (dumpit)
181 tab[msgindex].dumpit = dumpit;
182
183 return 0;
184}
185
186EXPORT_SYMBOL_GPL(__rtnl_register);
187
188/**
189 * rtnl_register - Register a rtnetlink message type
190 *
191 * Identical to __rtnl_register() but panics on failure. This is useful
192 * as failure of this function is very unlikely, it can only happen due
193 * to lack of memory when allocating the chain to store all message
194 * handlers for a protocol. Meant for use in init functions where lack
195 * of memory implies no sense in continueing.
196 */
197void rtnl_register(int protocol, int msgtype,
198 rtnl_doit_func doit, rtnl_dumpit_func dumpit)
199{
200 if (__rtnl_register(protocol, msgtype, doit, dumpit) < 0)
201 panic("Unable to register rtnetlink message handler, "
202 "protocol = %d, message type = %d\n",
203 protocol, msgtype);
204}
205
206EXPORT_SYMBOL_GPL(rtnl_register);
207
208/**
209 * rtnl_unregister - Unregister a rtnetlink message type
210 * @protocol: Protocol family or PF_UNSPEC
211 * @msgtype: rtnetlink message type
212 *
213 * Returns 0 on success or a negative error code.
214 */
215int rtnl_unregister(int protocol, int msgtype)
216{
217 int msgindex;
218
219 BUG_ON(protocol < 0 || protocol >= NPROTO);
220 msgindex = rtm_msgindex(msgtype);
221
222 if (rtnl_msg_handlers[protocol] == NULL)
223 return -ENOENT;
224
225 rtnl_msg_handlers[protocol][msgindex].doit = NULL;
226 rtnl_msg_handlers[protocol][msgindex].dumpit = NULL;
227
228 return 0;
229}
230
231EXPORT_SYMBOL_GPL(rtnl_unregister);
232
233/**
234 * rtnl_unregister_all - Unregister all rtnetlink message type of a protocol
235 * @protocol : Protocol family or PF_UNSPEC
236 *
237 * Identical to calling rtnl_unregster() for all registered message types
238 * of a certain protocol family.
239 */
240void rtnl_unregister_all(int protocol)
241{
242 BUG_ON(protocol < 0 || protocol >= NPROTO);
243
244 kfree(rtnl_msg_handlers[protocol]);
245 rtnl_msg_handlers[protocol] = NULL;
246}
247
248EXPORT_SYMBOL_GPL(rtnl_unregister_all);
99 249
100static const int rtm_min[RTM_NR_FAMILIES] = 250static const int rtm_min[RTM_NR_FAMILIES] =
101{ 251{
@@ -648,7 +798,7 @@ errout:
648 return err; 798 return err;
649} 799}
650 800
651static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) 801int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
652{ 802{
653 int idx; 803 int idx;
654 int s_idx = cb->family; 804 int s_idx = cb->family;
@@ -659,12 +809,12 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
659 int type = cb->nlh->nlmsg_type-RTM_BASE; 809 int type = cb->nlh->nlmsg_type-RTM_BASE;
660 if (idx < s_idx || idx == PF_PACKET) 810 if (idx < s_idx || idx == PF_PACKET)
661 continue; 811 continue;
662 if (rtnetlink_links[idx] == NULL || 812 if (rtnl_msg_handlers[idx] == NULL ||
663 rtnetlink_links[idx][type].dumpit == NULL) 813 rtnl_msg_handlers[idx][type].dumpit == NULL)
664 continue; 814 continue;
665 if (idx > s_idx) 815 if (idx > s_idx)
666 memset(&cb->args[0], 0, sizeof(cb->args)); 816 memset(&cb->args[0], 0, sizeof(cb->args));
667 if (rtnetlink_links[idx][type].dumpit(skb, cb)) 817 if (rtnl_msg_handlers[idx][type].dumpit(skb, cb))
668 break; 818 break;
669 } 819 }
670 cb->family = idx; 820 cb->family = idx;
@@ -672,6 +822,8 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
672 return skb->len; 822 return skb->len;
673} 823}
674 824
825EXPORT_SYMBOL_GPL(rtnl_dump_all);
826
675void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) 827void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
676{ 828{
677 struct sk_buff *skb; 829 struct sk_buff *skb;
@@ -703,8 +855,7 @@ static int rtattr_max;
703static __inline__ int 855static __inline__ int
704rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp) 856rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
705{ 857{
706 struct rtnetlink_link *link; 858 rtnl_doit_func doit;
707 struct rtnetlink_link *link_tab;
708 int sz_idx, kind; 859 int sz_idx, kind;
709 int min_len; 860 int min_len;
710 int family; 861 int family;
@@ -737,11 +888,6 @@ rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
737 return -1; 888 return -1;
738 } 889 }
739 890
740 link_tab = rtnetlink_links[family];
741 if (link_tab == NULL)
742 link_tab = rtnetlink_links[PF_UNSPEC];
743 link = &link_tab[type];
744
745 sz_idx = type>>2; 891 sz_idx = type>>2;
746 kind = type&3; 892 kind = type&3;
747 893
@@ -751,14 +897,14 @@ rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
751 } 897 }
752 898
753 if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { 899 if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
754 if (link->dumpit == NULL) 900 rtnl_dumpit_func dumpit;
755 link = &(rtnetlink_links[PF_UNSPEC][type]);
756 901
757 if (link->dumpit == NULL) 902 dumpit = rtnl_get_dumpit(family, type);
903 if (dumpit == NULL)
758 goto err_inval; 904 goto err_inval;
759 905
760 if ((*errp = netlink_dump_start(rtnl, skb, nlh, 906 if ((*errp = netlink_dump_start(rtnl, skb, nlh,
761 link->dumpit, NULL)) != 0) { 907 dumpit, NULL)) != 0) {
762 return -1; 908 return -1;
763 } 909 }
764 910
@@ -787,11 +933,10 @@ rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
787 } 933 }
788 } 934 }
789 935
790 if (link->doit == NULL) 936 doit = rtnl_get_doit(family, type);
791 link = &(rtnetlink_links[PF_UNSPEC][type]); 937 if (doit == NULL)
792 if (link->doit == NULL)
793 goto err_inval; 938 goto err_inval;
794 err = link->doit(skb, nlh, (void *)&rta_buf[0]); 939 err = doit(skb, nlh, (void *)&rta_buf[0]);
795 940
796 *errp = err; 941 *errp = err;
797 return err; 942 return err;
@@ -886,7 +1031,6 @@ void __init rtnetlink_init(void)
886EXPORT_SYMBOL(__rta_fill); 1031EXPORT_SYMBOL(__rta_fill);
887EXPORT_SYMBOL(rtattr_strlcpy); 1032EXPORT_SYMBOL(rtattr_strlcpy);
888EXPORT_SYMBOL(rtattr_parse); 1033EXPORT_SYMBOL(rtattr_parse);
889EXPORT_SYMBOL(rtnetlink_links);
890EXPORT_SYMBOL(rtnetlink_put_metrics); 1034EXPORT_SYMBOL(rtnetlink_put_metrics);
891EXPORT_SYMBOL(rtnl_lock); 1035EXPORT_SYMBOL(rtnl_lock);
892EXPORT_SYMBOL(rtnl_trylock); 1036EXPORT_SYMBOL(rtnl_trylock);