2 * Copyright Samuel Mendoza-Jonas, IBM Corporation 2018.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
10 #include <linux/module.h>
11 #include <linux/kernel.h>
12 #include <linux/if_arp.h>
13 #include <linux/rtnetlink.h>
14 #include <linux/etherdevice.h>
15 #include <linux/module.h>
16 #include <net/genetlink.h>
18 #include <linux/skbuff.h>
20 #include <uapi/linux/ncsi.h>
23 #include "ncsi-netlink.h"
25 static struct genl_family ncsi_genl_family
;
27 static const struct nla_policy ncsi_genl_policy
[NCSI_ATTR_MAX
+ 1] = {
28 [NCSI_ATTR_IFINDEX
] = { .type
= NLA_U32
},
29 [NCSI_ATTR_PACKAGE_LIST
] = { .type
= NLA_NESTED
},
30 [NCSI_ATTR_PACKAGE_ID
] = { .type
= NLA_U32
},
31 [NCSI_ATTR_CHANNEL_ID
] = { .type
= NLA_U32
},
34 static struct ncsi_dev_priv
*ndp_from_ifindex(struct net
*net
, u32 ifindex
)
36 struct ncsi_dev_priv
*ndp
;
37 struct net_device
*dev
;
44 dev
= dev_get_by_index(net
, ifindex
);
46 pr_err("NCSI netlink: No device for ifindex %u\n", ifindex
);
50 nd
= ncsi_find_dev(dev
);
51 ndp
= nd
? TO_NCSI_DEV_PRIV(nd
) : NULL
;
57 static int ncsi_write_channel_info(struct sk_buff
*skb
,
58 struct ncsi_dev_priv
*ndp
,
59 struct ncsi_channel
*nc
)
61 struct ncsi_channel_vlan_filter
*ncf
;
62 struct ncsi_channel_mode
*m
;
63 struct nlattr
*vid_nest
;
66 nla_put_u32(skb
, NCSI_CHANNEL_ATTR_ID
, nc
->id
);
67 m
= &nc
->modes
[NCSI_MODE_LINK
];
68 nla_put_u32(skb
, NCSI_CHANNEL_ATTR_LINK_STATE
, m
->data
[2]);
69 if (nc
->state
== NCSI_CHANNEL_ACTIVE
)
70 nla_put_flag(skb
, NCSI_CHANNEL_ATTR_ACTIVE
);
71 if (ndp
->force_channel
== nc
)
72 nla_put_flag(skb
, NCSI_CHANNEL_ATTR_FORCED
);
74 nla_put_u32(skb
, NCSI_CHANNEL_ATTR_VERSION_MAJOR
, nc
->version
.version
);
75 nla_put_u32(skb
, NCSI_CHANNEL_ATTR_VERSION_MINOR
, nc
->version
.alpha2
);
76 nla_put_string(skb
, NCSI_CHANNEL_ATTR_VERSION_STR
, nc
->version
.fw_name
);
78 vid_nest
= nla_nest_start(skb
, NCSI_CHANNEL_ATTR_VLAN_LIST
);
81 ncf
= &nc
->vlan_filter
;
83 while ((i
= find_next_bit((void *)&ncf
->bitmap
, ncf
->n_vids
,
84 i
+ 1)) < ncf
->n_vids
) {
86 nla_put_u16(skb
, NCSI_CHANNEL_ATTR_VLAN_ID
,
89 nla_nest_end(skb
, vid_nest
);
94 static int ncsi_write_package_info(struct sk_buff
*skb
,
95 struct ncsi_dev_priv
*ndp
, unsigned int id
)
97 struct nlattr
*pnest
, *cnest
, *nest
;
98 struct ncsi_package
*np
;
99 struct ncsi_channel
*nc
;
103 if (id
> ndp
->package_num
- 1) {
104 netdev_info(ndp
->ndev
.dev
, "NCSI: No package with id %u\n", id
);
109 NCSI_FOR_EACH_PACKAGE(ndp
, np
) {
112 pnest
= nla_nest_start(skb
, NCSI_PKG_ATTR
);
115 nla_put_u32(skb
, NCSI_PKG_ATTR_ID
, np
->id
);
116 if (ndp
->force_package
== np
)
117 nla_put_flag(skb
, NCSI_PKG_ATTR_FORCED
);
118 cnest
= nla_nest_start(skb
, NCSI_PKG_ATTR_CHANNEL_LIST
);
120 nla_nest_cancel(skb
, pnest
);
123 NCSI_FOR_EACH_CHANNEL(np
, nc
) {
124 nest
= nla_nest_start(skb
, NCSI_CHANNEL_ATTR
);
126 nla_nest_cancel(skb
, cnest
);
127 nla_nest_cancel(skb
, pnest
);
130 rc
= ncsi_write_channel_info(skb
, ndp
, nc
);
132 nla_nest_cancel(skb
, nest
);
133 nla_nest_cancel(skb
, cnest
);
134 nla_nest_cancel(skb
, pnest
);
137 nla_nest_end(skb
, nest
);
139 nla_nest_end(skb
, cnest
);
140 nla_nest_end(skb
, pnest
);
150 static int ncsi_pkg_info_nl(struct sk_buff
*msg
, struct genl_info
*info
)
152 struct ncsi_dev_priv
*ndp
;
153 unsigned int package_id
;
159 if (!info
|| !info
->attrs
)
162 if (!info
->attrs
[NCSI_ATTR_IFINDEX
])
165 if (!info
->attrs
[NCSI_ATTR_PACKAGE_ID
])
168 ndp
= ndp_from_ifindex(genl_info_net(info
),
169 nla_get_u32(info
->attrs
[NCSI_ATTR_IFINDEX
]));
173 skb
= genlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
177 hdr
= genlmsg_put(skb
, info
->snd_portid
, info
->snd_seq
,
178 &ncsi_genl_family
, 0, NCSI_CMD_PKG_INFO
);
184 package_id
= nla_get_u32(info
->attrs
[NCSI_ATTR_PACKAGE_ID
]);
186 attr
= nla_nest_start(skb
, NCSI_ATTR_PACKAGE_LIST
);
191 rc
= ncsi_write_package_info(skb
, ndp
, package_id
);
194 nla_nest_cancel(skb
, attr
);
198 nla_nest_end(skb
, attr
);
200 genlmsg_end(skb
, hdr
);
201 return genlmsg_reply(skb
, info
);
208 static int ncsi_pkg_info_all_nl(struct sk_buff
*skb
,
209 struct netlink_callback
*cb
)
211 struct nlattr
*attrs
[NCSI_ATTR_MAX
+ 1];
212 struct ncsi_package
*np
, *package
;
213 struct ncsi_dev_priv
*ndp
;
214 unsigned int package_id
;
219 rc
= genlmsg_parse(cb
->nlh
, &ncsi_genl_family
, attrs
, NCSI_ATTR_MAX
,
220 ncsi_genl_policy
, NULL
);
224 if (!attrs
[NCSI_ATTR_IFINDEX
])
227 ndp
= ndp_from_ifindex(get_net(sock_net(skb
->sk
)),
228 nla_get_u32(attrs
[NCSI_ATTR_IFINDEX
]));
233 package_id
= cb
->args
[0];
235 NCSI_FOR_EACH_PACKAGE(ndp
, np
)
236 if (np
->id
== package_id
)
242 hdr
= genlmsg_put(skb
, NETLINK_CB(cb
->skb
).portid
, cb
->nlh
->nlmsg_seq
,
243 &ncsi_genl_family
, NLM_F_MULTI
, NCSI_CMD_PKG_INFO
);
249 attr
= nla_nest_start(skb
, NCSI_ATTR_PACKAGE_LIST
);
250 rc
= ncsi_write_package_info(skb
, ndp
, package
->id
);
252 nla_nest_cancel(skb
, attr
);
256 nla_nest_end(skb
, attr
);
257 genlmsg_end(skb
, hdr
);
259 cb
->args
[0] = package_id
+ 1;
263 genlmsg_cancel(skb
, hdr
);
267 static int ncsi_set_interface_nl(struct sk_buff
*msg
, struct genl_info
*info
)
269 struct ncsi_package
*np
, *package
;
270 struct ncsi_channel
*nc
, *channel
;
271 u32 package_id
, channel_id
;
272 struct ncsi_dev_priv
*ndp
;
275 if (!info
|| !info
->attrs
)
278 if (!info
->attrs
[NCSI_ATTR_IFINDEX
])
281 if (!info
->attrs
[NCSI_ATTR_PACKAGE_ID
])
284 ndp
= ndp_from_ifindex(get_net(sock_net(msg
->sk
)),
285 nla_get_u32(info
->attrs
[NCSI_ATTR_IFINDEX
]));
289 package_id
= nla_get_u32(info
->attrs
[NCSI_ATTR_PACKAGE_ID
]);
292 spin_lock_irqsave(&ndp
->lock
, flags
);
294 NCSI_FOR_EACH_PACKAGE(ndp
, np
)
295 if (np
->id
== package_id
)
298 /* The user has set a package that does not exist */
299 spin_unlock_irqrestore(&ndp
->lock
, flags
);
304 if (!info
->attrs
[NCSI_ATTR_CHANNEL_ID
]) {
305 /* Allow any channel */
306 channel_id
= NCSI_RESERVED_CHANNEL
;
308 channel_id
= nla_get_u32(info
->attrs
[NCSI_ATTR_CHANNEL_ID
]);
309 NCSI_FOR_EACH_CHANNEL(package
, nc
)
310 if (nc
->id
== channel_id
)
314 if (channel_id
!= NCSI_RESERVED_CHANNEL
&& !channel
) {
315 /* The user has set a channel that does not exist on this
318 spin_unlock_irqrestore(&ndp
->lock
, flags
);
319 netdev_info(ndp
->ndev
.dev
, "NCSI: Channel %u does not exist!\n",
324 ndp
->force_package
= package
;
325 ndp
->force_channel
= channel
;
326 spin_unlock_irqrestore(&ndp
->lock
, flags
);
328 netdev_info(ndp
->ndev
.dev
, "Set package 0x%x, channel 0x%x%s as preferred\n",
329 package_id
, channel_id
,
330 channel_id
== NCSI_RESERVED_CHANNEL
? " (any)" : "");
332 /* Bounce the NCSI channel to set changes */
333 ncsi_stop_dev(&ndp
->ndev
);
334 ncsi_start_dev(&ndp
->ndev
);
339 static int ncsi_clear_interface_nl(struct sk_buff
*msg
, struct genl_info
*info
)
341 struct ncsi_dev_priv
*ndp
;
344 if (!info
|| !info
->attrs
)
347 if (!info
->attrs
[NCSI_ATTR_IFINDEX
])
350 ndp
= ndp_from_ifindex(get_net(sock_net(msg
->sk
)),
351 nla_get_u32(info
->attrs
[NCSI_ATTR_IFINDEX
]));
355 /* Clear any override */
356 spin_lock_irqsave(&ndp
->lock
, flags
);
357 ndp
->force_package
= NULL
;
358 ndp
->force_channel
= NULL
;
359 spin_unlock_irqrestore(&ndp
->lock
, flags
);
360 netdev_info(ndp
->ndev
.dev
, "NCSI: Cleared preferred package/channel\n");
362 /* Bounce the NCSI channel to set changes */
363 ncsi_stop_dev(&ndp
->ndev
);
364 ncsi_start_dev(&ndp
->ndev
);
369 static const struct genl_ops ncsi_ops
[] = {
371 .cmd
= NCSI_CMD_PKG_INFO
,
372 .policy
= ncsi_genl_policy
,
373 .doit
= ncsi_pkg_info_nl
,
374 .dumpit
= ncsi_pkg_info_all_nl
,
378 .cmd
= NCSI_CMD_SET_INTERFACE
,
379 .policy
= ncsi_genl_policy
,
380 .doit
= ncsi_set_interface_nl
,
381 .flags
= GENL_ADMIN_PERM
,
384 .cmd
= NCSI_CMD_CLEAR_INTERFACE
,
385 .policy
= ncsi_genl_policy
,
386 .doit
= ncsi_clear_interface_nl
,
387 .flags
= GENL_ADMIN_PERM
,
391 static struct genl_family ncsi_genl_family __ro_after_init
= {
394 .maxattr
= NCSI_ATTR_MAX
,
395 .module
= THIS_MODULE
,
397 .n_ops
= ARRAY_SIZE(ncsi_ops
),
400 int ncsi_init_netlink(struct net_device
*dev
)
404 rc
= genl_register_family(&ncsi_genl_family
);
406 netdev_err(dev
, "ncsi: failed to register netlink family\n");
411 int ncsi_unregister_netlink(struct net_device
*dev
)
415 rc
= genl_unregister_family(&ncsi_genl_family
);
417 netdev_err(dev
, "ncsi: failed to unregister netlink family\n");