aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemi Denis-Courmont <remi.denis-courmont@nokia.com>2008-09-22 23:04:30 -0400
committerDavid S. Miller <davem@davemloft.net>2008-09-22 23:04:30 -0400
commit8fb397406f6470f79040c41eec49af20900a9e3b (patch)
tree019a843c84fc4b427b957a42b49562f8c33e33b6
parentf8ff60283de2b6775d7a14619056a08e3083bd40 (diff)
Phonet: Netlink interface
This provides support for configuring Phonet addresses, notifying Phonet configuration changes, and dumping the configuration. Signed-off-by: Remi Denis-Courmont <remi.denis-courmont@nokia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/phonet/phonet.h1
-rw-r--r--net/phonet/Makefile1
-rw-r--r--net/phonet/af_phonet.c1
-rw-r--r--net/phonet/pn_netlink.c186
4 files changed, 189 insertions, 0 deletions
diff --git a/include/net/phonet/phonet.h b/include/net/phonet/phonet.h
index c53f2abc0595..8b777943d201 100644
--- a/include/net/phonet/phonet.h
+++ b/include/net/phonet/phonet.h
@@ -71,4 +71,5 @@ struct phonet_protocol {
71int phonet_proto_register(int protocol, struct phonet_protocol *pp); 71int phonet_proto_register(int protocol, struct phonet_protocol *pp);
72void phonet_proto_unregister(int protocol, struct phonet_protocol *pp); 72void phonet_proto_unregister(int protocol, struct phonet_protocol *pp);
73 73
74void phonet_netlink_register(void);
74#endif 75#endif
diff --git a/net/phonet/Makefile b/net/phonet/Makefile
index 980a3866c9a3..4143c3e1dfdc 100644
--- a/net/phonet/Makefile
+++ b/net/phonet/Makefile
@@ -2,4 +2,5 @@ obj-$(CONFIG_PHONET) += phonet.o
2 2
3phonet-objs := \ 3phonet-objs := \
4 pn_dev.o \ 4 pn_dev.o \
5 pn_netlink.o \
5 af_phonet.o 6 af_phonet.o
diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c
index a8ba6f177b29..5c729ba56939 100644
--- a/net/phonet/af_phonet.c
+++ b/net/phonet/af_phonet.c
@@ -203,6 +203,7 @@ static int __init phonet_init(void)
203 203
204 phonet_device_init(); 204 phonet_device_init();
205 dev_add_pack(&phonet_packet_type); 205 dev_add_pack(&phonet_packet_type);
206 phonet_netlink_register();
206 return 0; 207 return 0;
207} 208}
208 209
diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c
new file mode 100644
index 000000000000..b1ea19a230dd
--- /dev/null
+++ b/net/phonet/pn_netlink.c
@@ -0,0 +1,186 @@
1/*
2 * File: pn_netlink.c
3 *
4 * Phonet netlink interface
5 *
6 * Copyright (C) 2008 Nokia Corporation.
7 *
8 * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
9 * Original author: Sakari Ailus <sakari.ailus@nokia.com>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * version 2 as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301 USA
24 */
25
26#include <linux/kernel.h>
27#include <linux/netlink.h>
28#include <linux/phonet.h>
29#include <net/sock.h>
30#include <net/phonet/pn_dev.h>
31
32static int fill_addr(struct sk_buff *skb, struct net_device *dev, u8 addr,
33 u32 pid, u32 seq, int event);
34
35static void rtmsg_notify(int event, struct net_device *dev, u8 addr)
36{
37 struct sk_buff *skb;
38 int err = -ENOBUFS;
39
40 skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct ifaddrmsg)) +
41 nla_total_size(1), GFP_KERNEL);
42 if (skb == NULL)
43 goto errout;
44 err = fill_addr(skb, dev, addr, 0, 0, event);
45 if (err < 0) {
46 WARN_ON(err == -EMSGSIZE);
47 kfree_skb(skb);
48 goto errout;
49 }
50 err = rtnl_notify(skb, dev_net(dev), 0,
51 RTNLGRP_PHONET_IFADDR, NULL, GFP_KERNEL);
52errout:
53 if (err < 0)
54 rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_IFADDR, err);
55}
56
57static int newaddr_doit(struct sk_buff *skb, struct nlmsghdr *nlm, void *attr)
58{
59 struct rtattr **rta = attr;
60 struct ifaddrmsg *ifm = NLMSG_DATA(nlm);
61 struct net_device *dev;
62 int err;
63 u8 pnaddr;
64
65 if (!capable(CAP_SYS_ADMIN))
66 return -EPERM;
67
68 ASSERT_RTNL();
69
70 if (rta[IFA_LOCAL - 1] == NULL)
71 return -EINVAL;
72
73 dev = __dev_get_by_index(&init_net, ifm->ifa_index);
74 if (dev == NULL)
75 return -ENODEV;
76
77 if (ifm->ifa_prefixlen > 0)
78 return -EINVAL;
79
80 memcpy(&pnaddr, RTA_DATA(rta[IFA_LOCAL - 1]), 1);
81
82 err = phonet_address_add(dev, pnaddr);
83 if (!err)
84 rtmsg_notify(RTM_NEWADDR, dev, pnaddr);
85 return err;
86}
87
88static int deladdr_doit(struct sk_buff *skb, struct nlmsghdr *nlm, void *attr)
89{
90 struct rtattr **rta = attr;
91 struct ifaddrmsg *ifm = NLMSG_DATA(nlm);
92 struct net_device *dev;
93 int err;
94 u8 pnaddr;
95
96 if (!capable(CAP_SYS_ADMIN))
97 return -EPERM;
98
99 ASSERT_RTNL();
100
101 if (rta[IFA_LOCAL - 1] == NULL)
102 return -EINVAL;
103
104 dev = __dev_get_by_index(&init_net, ifm->ifa_index);
105 if (dev == NULL)
106 return -ENODEV;
107
108 if (ifm->ifa_prefixlen > 0)
109 return -EADDRNOTAVAIL;
110
111 memcpy(&pnaddr, RTA_DATA(rta[IFA_LOCAL - 1]), 1);
112
113 err = phonet_address_del(dev, pnaddr);
114 if (!err)
115 rtmsg_notify(RTM_DELADDR, dev, pnaddr);
116 return err;
117}
118
119static int fill_addr(struct sk_buff *skb, struct net_device *dev, u8 addr,
120 u32 pid, u32 seq, int event)
121{
122 struct ifaddrmsg *ifm;
123 struct nlmsghdr *nlh;
124 unsigned int orig_len = skb->len;
125
126 nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct ifaddrmsg));
127 ifm = NLMSG_DATA(nlh);
128 ifm->ifa_family = AF_PHONET;
129 ifm->ifa_prefixlen = 0;
130 ifm->ifa_flags = IFA_F_PERMANENT;
131 ifm->ifa_scope = RT_SCOPE_HOST;
132 ifm->ifa_index = dev->ifindex;
133 RTA_PUT(skb, IFA_LOCAL, 1, &addr);
134 nlh->nlmsg_len = skb->len - orig_len;
135
136 return 0;
137
138nlmsg_failure:
139rtattr_failure:
140 skb_trim(skb, orig_len);
141
142 return -1;
143}
144
145static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
146{
147 struct phonet_device *pnd;
148 int dev_idx = 0, dev_start_idx = cb->args[0];
149 int addr_idx = 0, addr_start_idx = cb->args[1];
150
151 spin_lock_bh(&pndevs.lock);
152 list_for_each_entry(pnd, &pndevs.list, list) {
153 u8 addr;
154
155 if (dev_idx > dev_start_idx)
156 addr_start_idx = 0;
157 if (dev_idx++ < dev_start_idx)
158 continue;
159
160 addr_idx = 0;
161 for (addr = find_first_bit(pnd->addrs, 64); addr < 64;
162 addr = find_next_bit(pnd->addrs, 64, 1+addr)) {
163 if (addr_idx++ < addr_start_idx)
164 continue;
165
166 if (fill_addr(skb, pnd->netdev, addr << 2,
167 NETLINK_CB(cb->skb).pid,
168 cb->nlh->nlmsg_seq, RTM_NEWADDR))
169 goto out;
170 }
171 }
172
173out:
174 spin_unlock_bh(&pndevs.lock);
175 cb->args[0] = dev_idx;
176 cb->args[1] = addr_idx;
177
178 return skb->len;
179}
180
181void __init phonet_netlink_register(void)
182{
183 rtnl_register(PF_PHONET, RTM_NEWADDR, newaddr_doit, NULL);
184 rtnl_register(PF_PHONET, RTM_DELADDR, deladdr_doit, NULL);
185 rtnl_register(PF_PHONET, RTM_GETADDR, NULL, getaddr_dumpit);
186}