Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 831119f

Browse files
mkjdavem330
authored andcommitted
mctp: Add neighbour netlink interface
This change adds the netlink interfaces for manipulating the MCTP neighbour table. Signed-off-by: Matt Johnston <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 4d8b931 commit 831119f

File tree

1 file changed

+204
-3
lines changed

1 file changed

+204
-3
lines changed

net/mctp/neigh.c

Lines changed: 204 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
#include <net/netlink.h>
2222
#include <net/sock.h>
2323

24-
static int __always_unused mctp_neigh_add(struct mctp_dev *mdev, mctp_eid_t eid,
25-
enum mctp_neigh_source source,
26-
size_t lladdr_len, const void *lladdr)
24+
static int mctp_neigh_add(struct mctp_dev *mdev, mctp_eid_t eid,
25+
enum mctp_neigh_source source,
26+
size_t lladdr_len, const void *lladdr)
2727
{
2828
struct net *net = dev_net(mdev->dev);
2929
struct mctp_neigh *neigh;
@@ -85,6 +85,196 @@ void mctp_neigh_remove_dev(struct mctp_dev *mdev)
8585
mutex_unlock(&net->mctp.neigh_lock);
8686
}
8787

88+
// TODO: add a "source" flag so netlink can only delete static neighbours?
89+
static int mctp_neigh_remove(struct mctp_dev *mdev, mctp_eid_t eid)
90+
{
91+
struct net *net = dev_net(mdev->dev);
92+
struct mctp_neigh *neigh, *tmp;
93+
bool dropped = false;
94+
95+
mutex_lock(&net->mctp.neigh_lock);
96+
list_for_each_entry_safe(neigh, tmp, &net->mctp.neighbours, list) {
97+
if (neigh->dev == mdev && neigh->eid == eid) {
98+
list_del_rcu(&neigh->list);
99+
/* TODO: immediate RTM_DELNEIGH */
100+
call_rcu(&neigh->rcu, __mctp_neigh_free);
101+
dropped = true;
102+
}
103+
}
104+
105+
mutex_unlock(&net->mctp.neigh_lock);
106+
return dropped ? 0 : -ENOENT;
107+
}
108+
109+
static const struct nla_policy nd_mctp_policy[NDA_MAX + 1] = {
110+
[NDA_DST] = { .type = NLA_U8 },
111+
[NDA_LLADDR] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
112+
};
113+
114+
static int mctp_rtm_newneigh(struct sk_buff *skb, struct nlmsghdr *nlh,
115+
struct netlink_ext_ack *extack)
116+
{
117+
struct net *net = sock_net(skb->sk);
118+
struct net_device *dev;
119+
struct mctp_dev *mdev;
120+
struct ndmsg *ndm;
121+
struct nlattr *tb[NDA_MAX + 1];
122+
int rc;
123+
mctp_eid_t eid;
124+
void *lladdr;
125+
int lladdr_len;
126+
127+
rc = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, nd_mctp_policy,
128+
extack);
129+
if (rc < 0) {
130+
NL_SET_ERR_MSG(extack, "lladdr too large?");
131+
return rc;
132+
}
133+
134+
if (!tb[NDA_DST]) {
135+
NL_SET_ERR_MSG(extack, "Neighbour EID must be specified");
136+
return -EINVAL;
137+
}
138+
139+
if (!tb[NDA_LLADDR]) {
140+
NL_SET_ERR_MSG(extack, "Neighbour lladdr must be specified");
141+
return -EINVAL;
142+
}
143+
144+
eid = nla_get_u8(tb[NDA_DST]);
145+
if (!mctp_address_ok(eid)) {
146+
NL_SET_ERR_MSG(extack, "Invalid neighbour EID");
147+
return -EINVAL;
148+
}
149+
150+
lladdr = nla_data(tb[NDA_LLADDR]);
151+
lladdr_len = nla_len(tb[NDA_LLADDR]);
152+
153+
ndm = nlmsg_data(nlh);
154+
155+
dev = __dev_get_by_index(net, ndm->ndm_ifindex);
156+
if (!dev)
157+
return -ENODEV;
158+
159+
mdev = mctp_dev_get_rtnl(dev);
160+
if (!mdev)
161+
return -ENODEV;
162+
163+
if (lladdr_len != dev->addr_len) {
164+
NL_SET_ERR_MSG(extack, "Wrong lladdr length");
165+
return -EINVAL;
166+
}
167+
168+
return mctp_neigh_add(mdev, eid, MCTP_NEIGH_STATIC,
169+
lladdr_len, lladdr);
170+
}
171+
172+
static int mctp_rtm_delneigh(struct sk_buff *skb, struct nlmsghdr *nlh,
173+
struct netlink_ext_ack *extack)
174+
{
175+
struct net *net = sock_net(skb->sk);
176+
struct nlattr *tb[NDA_MAX + 1];
177+
struct net_device *dev;
178+
struct mctp_dev *mdev;
179+
struct ndmsg *ndm;
180+
int rc;
181+
mctp_eid_t eid;
182+
183+
rc = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, nd_mctp_policy,
184+
extack);
185+
if (rc < 0) {
186+
NL_SET_ERR_MSG(extack, "incorrect format");
187+
return rc;
188+
}
189+
190+
if (!tb[NDA_DST]) {
191+
NL_SET_ERR_MSG(extack, "Neighbour EID must be specified");
192+
return -EINVAL;
193+
}
194+
eid = nla_get_u8(tb[NDA_DST]);
195+
196+
ndm = nlmsg_data(nlh);
197+
dev = __dev_get_by_index(net, ndm->ndm_ifindex);
198+
if (!dev)
199+
return -ENODEV;
200+
201+
mdev = mctp_dev_get_rtnl(dev);
202+
if (!mdev)
203+
return -ENODEV;
204+
205+
return mctp_neigh_remove(mdev, eid);
206+
}
207+
208+
static int mctp_fill_neigh(struct sk_buff *skb, u32 portid, u32 seq, int event,
209+
unsigned int flags, struct mctp_neigh *neigh)
210+
{
211+
struct net_device *dev = neigh->dev->dev;
212+
struct nlmsghdr *nlh;
213+
struct ndmsg *hdr;
214+
215+
nlh = nlmsg_put(skb, portid, seq, event, sizeof(*hdr), flags);
216+
if (!nlh)
217+
return -EMSGSIZE;
218+
219+
hdr = nlmsg_data(nlh);
220+
hdr->ndm_family = AF_MCTP;
221+
hdr->ndm_ifindex = dev->ifindex;
222+
hdr->ndm_state = 0; // TODO other state bits?
223+
if (neigh->source == MCTP_NEIGH_STATIC)
224+
hdr->ndm_state |= NUD_PERMANENT;
225+
hdr->ndm_flags = 0;
226+
hdr->ndm_type = RTN_UNICAST; // TODO: is loopback RTN_LOCAL?
227+
228+
if (nla_put_u8(skb, NDA_DST, neigh->eid))
229+
goto cancel;
230+
231+
if (nla_put(skb, NDA_LLADDR, dev->addr_len, neigh->ha))
232+
goto cancel;
233+
234+
nlmsg_end(skb, nlh);
235+
236+
return 0;
237+
cancel:
238+
nlmsg_cancel(skb, nlh);
239+
return -EMSGSIZE;
240+
}
241+
242+
static int mctp_rtm_getneigh(struct sk_buff *skb, struct netlink_callback *cb)
243+
{
244+
struct net *net = sock_net(skb->sk);
245+
int rc, idx, req_ifindex;
246+
struct mctp_neigh *neigh;
247+
struct ndmsg *ndmsg;
248+
struct {
249+
int idx;
250+
} *cbctx = (void *)cb->ctx;
251+
252+
ndmsg = nlmsg_data(cb->nlh);
253+
req_ifindex = ndmsg->ndm_ifindex;
254+
255+
idx = 0;
256+
rcu_read_lock();
257+
list_for_each_entry_rcu(neigh, &net->mctp.neighbours, list) {
258+
if (idx < cbctx->idx)
259+
goto cont;
260+
261+
rc = 0;
262+
if (req_ifindex == 0 || req_ifindex == neigh->dev->dev->ifindex)
263+
rc = mctp_fill_neigh(skb, NETLINK_CB(cb->skb).portid,
264+
cb->nlh->nlmsg_seq,
265+
RTM_NEWNEIGH, NLM_F_MULTI, neigh);
266+
267+
if (rc)
268+
break;
269+
cont:
270+
idx++;
271+
}
272+
rcu_read_unlock();
273+
274+
cbctx->idx = idx;
275+
return skb->len;
276+
}
277+
88278
int mctp_neigh_lookup(struct mctp_dev *mdev, mctp_eid_t eid, void *ret_hwaddr)
89279
{
90280
struct net *net = dev_net(mdev->dev);
@@ -111,6 +301,7 @@ static int __net_init mctp_neigh_net_init(struct net *net)
111301
struct netns_mctp *ns = &net->mctp;
112302

113303
INIT_LIST_HEAD(&ns->neighbours);
304+
mutex_init(&ns->neigh_lock);
114305
return 0;
115306
}
116307

@@ -132,10 +323,20 @@ static struct pernet_operations mctp_net_ops = {
132323

133324
int __init mctp_neigh_init(void)
134325
{
326+
rtnl_register_module(THIS_MODULE, PF_MCTP, RTM_NEWNEIGH,
327+
mctp_rtm_newneigh, NULL, 0);
328+
rtnl_register_module(THIS_MODULE, PF_MCTP, RTM_DELNEIGH,
329+
mctp_rtm_delneigh, NULL, 0);
330+
rtnl_register_module(THIS_MODULE, PF_MCTP, RTM_GETNEIGH,
331+
NULL, mctp_rtm_getneigh, 0);
332+
135333
return register_pernet_subsys(&mctp_net_ops);
136334
}
137335

138336
void __exit mctp_neigh_exit(void)
139337
{
140338
unregister_pernet_subsys(&mctp_net_ops);
339+
rtnl_unregister(PF_MCTP, RTM_GETNEIGH);
340+
rtnl_unregister(PF_MCTP, RTM_DELNEIGH);
341+
rtnl_unregister(PF_MCTP, RTM_NEWNEIGH);
141342
}

0 commit comments

Comments
 (0)