1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/module.h>
14#include <linux/skbuff.h>
15#include <linux/slab.h>
16#include <linux/init.h>
17#include <linux/netdevice.h>
18#include <linux/netfilter.h>
19#include <linux/spinlock.h>
20#include <net/netlink.h>
21#include <linux/netfilter_decnet.h>
22
23#include <net/sock.h>
24#include <net/flow.h>
25#include <net/dn.h>
26#include <net/dn_route.h>
27
28static struct sock *dnrmg = NULL;
29
30
31static struct sk_buff *dnrmg_build_message(struct sk_buff *rt_skb, int *errp)
32{
33 struct sk_buff *skb = NULL;
34 size_t size;
35 sk_buff_data_t old_tail;
36 struct nlmsghdr *nlh;
37 unsigned char *ptr;
38 struct nf_dn_rtmsg *rtm;
39
40 size = NLMSG_ALIGN(rt_skb->len) +
41 NLMSG_ALIGN(sizeof(struct nf_dn_rtmsg));
42 skb = nlmsg_new(size, GFP_ATOMIC);
43 if (!skb) {
44 *errp = -ENOMEM;
45 return NULL;
46 }
47 old_tail = skb->tail;
48 nlh = nlmsg_put(skb, 0, 0, 0, size, 0);
49 if (!nlh) {
50 kfree_skb(skb);
51 *errp = -ENOMEM;
52 return NULL;
53 }
54 rtm = (struct nf_dn_rtmsg *)nlmsg_data(nlh);
55 rtm->nfdn_ifindex = rt_skb->dev->ifindex;
56 ptr = NFDN_RTMSG(rtm);
57 skb_copy_from_linear_data(rt_skb, ptr, rt_skb->len);
58 nlh->nlmsg_len = skb->tail - old_tail;
59 return skb;
60}
61
62static void dnrmg_send_peer(struct sk_buff *skb)
63{
64 struct sk_buff *skb2;
65 int status = 0;
66 int group = 0;
67 unsigned char flags = *skb->data;
68
69 switch (flags & DN_RT_CNTL_MSK) {
70 case DN_RT_PKT_L1RT:
71 group = DNRNG_NLGRP_L1;
72 break;
73 case DN_RT_PKT_L2RT:
74 group = DNRNG_NLGRP_L2;
75 break;
76 default:
77 return;
78 }
79
80 skb2 = dnrmg_build_message(skb, &status);
81 if (skb2 == NULL)
82 return;
83 NETLINK_CB(skb2).dst_group = group;
84 netlink_broadcast(dnrmg, skb2, 0, group, GFP_ATOMIC);
85}
86
87
88static unsigned int dnrmg_hook(void *priv,
89 struct sk_buff *skb,
90 const struct nf_hook_state *state)
91{
92 dnrmg_send_peer(skb);
93 return NF_ACCEPT;
94}
95
96
97#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err), NULL); return; } while (0)
98
99static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
100{
101 struct nlmsghdr *nlh = nlmsg_hdr(skb);
102
103 if (skb->len < sizeof(*nlh) ||
104 nlh->nlmsg_len < sizeof(*nlh) ||
105 skb->len < nlh->nlmsg_len)
106 return;
107
108 if (!netlink_capable(skb, CAP_NET_ADMIN))
109 RCV_SKB_FAIL(-EPERM);
110
111
112
113 RCV_SKB_FAIL(-EINVAL);
114}
115
116static const struct nf_hook_ops dnrmg_ops = {
117 .hook = dnrmg_hook,
118 .pf = NFPROTO_DECNET,
119 .hooknum = NF_DN_ROUTE,
120 .priority = NF_DN_PRI_DNRTMSG,
121};
122
123static int __init dn_rtmsg_init(void)
124{
125 int rv = 0;
126 struct netlink_kernel_cfg cfg = {
127 .groups = DNRNG_NLGRP_MAX,
128 .input = dnrmg_receive_user_skb,
129 };
130
131 dnrmg = netlink_kernel_create(&init_net, NETLINK_DNRTMSG, &cfg);
132 if (dnrmg == NULL) {
133 printk(KERN_ERR "dn_rtmsg: Cannot create netlink socket");
134 return -ENOMEM;
135 }
136
137 rv = nf_register_net_hook(&init_net, &dnrmg_ops);
138 if (rv) {
139 netlink_kernel_release(dnrmg);
140 }
141
142 return rv;
143}
144
145static void __exit dn_rtmsg_fini(void)
146{
147 nf_unregister_net_hook(&init_net, &dnrmg_ops);
148 netlink_kernel_release(dnrmg);
149}
150
151
152MODULE_DESCRIPTION("DECnet Routing Message Grabulator");
153MODULE_AUTHOR("Steven Whitehouse <steve@chygwyn.com>");
154MODULE_LICENSE("GPL");
155MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_DNRTMSG);
156
157module_init(dn_rtmsg_init);
158module_exit(dn_rtmsg_fini);
159