1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * RMNET configuration engine
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <net/sock.h>
8*4882a593Smuzhiyun #include <linux/module.h>
9*4882a593Smuzhiyun #include <linux/netlink.h>
10*4882a593Smuzhiyun #include <linux/netdevice.h>
11*4882a593Smuzhiyun #include "rmnet_config.h"
12*4882a593Smuzhiyun #include "rmnet_handlers.h"
13*4882a593Smuzhiyun #include "rmnet_vnd.h"
14*4882a593Smuzhiyun #include "rmnet_private.h"
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun /* Local Definitions and Declarations */
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun static const struct nla_policy rmnet_policy[IFLA_RMNET_MAX + 1] = {
19*4882a593Smuzhiyun [IFLA_RMNET_MUX_ID] = { .type = NLA_U16 },
20*4882a593Smuzhiyun [IFLA_RMNET_FLAGS] = { .len = sizeof(struct ifla_rmnet_flags) },
21*4882a593Smuzhiyun };
22*4882a593Smuzhiyun
rmnet_is_real_dev_registered(const struct net_device * real_dev)23*4882a593Smuzhiyun static int rmnet_is_real_dev_registered(const struct net_device *real_dev)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun return rcu_access_pointer(real_dev->rx_handler) == rmnet_rx_handler;
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun /* Needs rtnl lock */
29*4882a593Smuzhiyun struct rmnet_port*
rmnet_get_port_rtnl(const struct net_device * real_dev)30*4882a593Smuzhiyun rmnet_get_port_rtnl(const struct net_device *real_dev)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun return rtnl_dereference(real_dev->rx_handler_data);
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun
rmnet_unregister_real_device(struct net_device * real_dev)35*4882a593Smuzhiyun static int rmnet_unregister_real_device(struct net_device *real_dev)
36*4882a593Smuzhiyun {
37*4882a593Smuzhiyun struct rmnet_port *port = rmnet_get_port_rtnl(real_dev);
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun if (port->nr_rmnet_devs)
40*4882a593Smuzhiyun return -EINVAL;
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun netdev_rx_handler_unregister(real_dev);
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun kfree(port);
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun netdev_dbg(real_dev, "Removed from rmnet\n");
47*4882a593Smuzhiyun return 0;
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun
rmnet_register_real_device(struct net_device * real_dev,struct netlink_ext_ack * extack)50*4882a593Smuzhiyun static int rmnet_register_real_device(struct net_device *real_dev,
51*4882a593Smuzhiyun struct netlink_ext_ack *extack)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun struct rmnet_port *port;
54*4882a593Smuzhiyun int rc, entry;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun ASSERT_RTNL();
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun if (rmnet_is_real_dev_registered(real_dev)) {
59*4882a593Smuzhiyun port = rmnet_get_port_rtnl(real_dev);
60*4882a593Smuzhiyun if (port->rmnet_mode != RMNET_EPMODE_VND) {
61*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "bridge device already exists");
62*4882a593Smuzhiyun return -EINVAL;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun return 0;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun port = kzalloc(sizeof(*port), GFP_KERNEL);
69*4882a593Smuzhiyun if (!port)
70*4882a593Smuzhiyun return -ENOMEM;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun port->dev = real_dev;
73*4882a593Smuzhiyun rc = netdev_rx_handler_register(real_dev, rmnet_rx_handler, port);
74*4882a593Smuzhiyun if (rc) {
75*4882a593Smuzhiyun kfree(port);
76*4882a593Smuzhiyun return -EBUSY;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun for (entry = 0; entry < RMNET_MAX_LOGICAL_EP; entry++)
80*4882a593Smuzhiyun INIT_HLIST_HEAD(&port->muxed_ep[entry]);
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun netdev_dbg(real_dev, "registered with rmnet\n");
83*4882a593Smuzhiyun return 0;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
rmnet_unregister_bridge(struct rmnet_port * port)86*4882a593Smuzhiyun static void rmnet_unregister_bridge(struct rmnet_port *port)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun struct net_device *bridge_dev, *real_dev, *rmnet_dev;
89*4882a593Smuzhiyun struct rmnet_port *real_port;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun if (port->rmnet_mode != RMNET_EPMODE_BRIDGE)
92*4882a593Smuzhiyun return;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun rmnet_dev = port->rmnet_dev;
95*4882a593Smuzhiyun if (!port->nr_rmnet_devs) {
96*4882a593Smuzhiyun /* bridge device */
97*4882a593Smuzhiyun real_dev = port->bridge_ep;
98*4882a593Smuzhiyun bridge_dev = port->dev;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun real_port = rmnet_get_port_rtnl(real_dev);
101*4882a593Smuzhiyun real_port->bridge_ep = NULL;
102*4882a593Smuzhiyun real_port->rmnet_mode = RMNET_EPMODE_VND;
103*4882a593Smuzhiyun } else {
104*4882a593Smuzhiyun /* real device */
105*4882a593Smuzhiyun bridge_dev = port->bridge_ep;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun port->bridge_ep = NULL;
108*4882a593Smuzhiyun port->rmnet_mode = RMNET_EPMODE_VND;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun netdev_upper_dev_unlink(bridge_dev, rmnet_dev);
112*4882a593Smuzhiyun rmnet_unregister_real_device(bridge_dev);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
rmnet_newlink(struct net * src_net,struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)115*4882a593Smuzhiyun static int rmnet_newlink(struct net *src_net, struct net_device *dev,
116*4882a593Smuzhiyun struct nlattr *tb[], struct nlattr *data[],
117*4882a593Smuzhiyun struct netlink_ext_ack *extack)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun u32 data_format = RMNET_FLAGS_INGRESS_DEAGGREGATION;
120*4882a593Smuzhiyun struct net_device *real_dev;
121*4882a593Smuzhiyun int mode = RMNET_EPMODE_VND;
122*4882a593Smuzhiyun struct rmnet_endpoint *ep;
123*4882a593Smuzhiyun struct rmnet_port *port;
124*4882a593Smuzhiyun int err = 0;
125*4882a593Smuzhiyun u16 mux_id;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun if (!tb[IFLA_LINK]) {
128*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "link not specified");
129*4882a593Smuzhiyun return -EINVAL;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun real_dev = __dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
133*4882a593Smuzhiyun if (!real_dev) {
134*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "link does not exist");
135*4882a593Smuzhiyun return -ENODEV;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun ep = kzalloc(sizeof(*ep), GFP_KERNEL);
139*4882a593Smuzhiyun if (!ep)
140*4882a593Smuzhiyun return -ENOMEM;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun mux_id = nla_get_u16(data[IFLA_RMNET_MUX_ID]);
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun err = rmnet_register_real_device(real_dev, extack);
145*4882a593Smuzhiyun if (err)
146*4882a593Smuzhiyun goto err0;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun port = rmnet_get_port_rtnl(real_dev);
149*4882a593Smuzhiyun err = rmnet_vnd_newlink(mux_id, dev, port, real_dev, ep, extack);
150*4882a593Smuzhiyun if (err)
151*4882a593Smuzhiyun goto err1;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun err = netdev_upper_dev_link(real_dev, dev, extack);
154*4882a593Smuzhiyun if (err < 0)
155*4882a593Smuzhiyun goto err2;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun port->rmnet_mode = mode;
158*4882a593Smuzhiyun port->rmnet_dev = dev;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]);
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun if (data[IFLA_RMNET_FLAGS]) {
163*4882a593Smuzhiyun struct ifla_rmnet_flags *flags;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun flags = nla_data(data[IFLA_RMNET_FLAGS]);
166*4882a593Smuzhiyun data_format = flags->flags & flags->mask;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun netdev_dbg(dev, "data format [0x%08X]\n", data_format);
170*4882a593Smuzhiyun port->data_format = data_format;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun return 0;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun err2:
175*4882a593Smuzhiyun unregister_netdevice(dev);
176*4882a593Smuzhiyun rmnet_vnd_dellink(mux_id, port, ep);
177*4882a593Smuzhiyun err1:
178*4882a593Smuzhiyun rmnet_unregister_real_device(real_dev);
179*4882a593Smuzhiyun err0:
180*4882a593Smuzhiyun kfree(ep);
181*4882a593Smuzhiyun return err;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
rmnet_dellink(struct net_device * dev,struct list_head * head)184*4882a593Smuzhiyun static void rmnet_dellink(struct net_device *dev, struct list_head *head)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun struct rmnet_priv *priv = netdev_priv(dev);
187*4882a593Smuzhiyun struct net_device *real_dev, *bridge_dev;
188*4882a593Smuzhiyun struct rmnet_port *real_port, *bridge_port;
189*4882a593Smuzhiyun struct rmnet_endpoint *ep;
190*4882a593Smuzhiyun u8 mux_id = priv->mux_id;
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun real_dev = priv->real_dev;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun if (!rmnet_is_real_dev_registered(real_dev))
195*4882a593Smuzhiyun return;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun real_port = rmnet_get_port_rtnl(real_dev);
198*4882a593Smuzhiyun bridge_dev = real_port->bridge_ep;
199*4882a593Smuzhiyun if (bridge_dev) {
200*4882a593Smuzhiyun bridge_port = rmnet_get_port_rtnl(bridge_dev);
201*4882a593Smuzhiyun rmnet_unregister_bridge(bridge_port);
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun ep = rmnet_get_endpoint(real_port, mux_id);
205*4882a593Smuzhiyun if (ep) {
206*4882a593Smuzhiyun hlist_del_init_rcu(&ep->hlnode);
207*4882a593Smuzhiyun rmnet_vnd_dellink(mux_id, real_port, ep);
208*4882a593Smuzhiyun kfree(ep);
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun netdev_upper_dev_unlink(real_dev, dev);
212*4882a593Smuzhiyun rmnet_unregister_real_device(real_dev);
213*4882a593Smuzhiyun unregister_netdevice_queue(dev, head);
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
rmnet_force_unassociate_device(struct net_device * real_dev)216*4882a593Smuzhiyun static void rmnet_force_unassociate_device(struct net_device *real_dev)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun struct hlist_node *tmp_ep;
219*4882a593Smuzhiyun struct rmnet_endpoint *ep;
220*4882a593Smuzhiyun struct rmnet_port *port;
221*4882a593Smuzhiyun unsigned long bkt_ep;
222*4882a593Smuzhiyun LIST_HEAD(list);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun port = rmnet_get_port_rtnl(real_dev);
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun if (port->nr_rmnet_devs) {
227*4882a593Smuzhiyun /* real device */
228*4882a593Smuzhiyun rmnet_unregister_bridge(port);
229*4882a593Smuzhiyun hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {
230*4882a593Smuzhiyun unregister_netdevice_queue(ep->egress_dev, &list);
231*4882a593Smuzhiyun netdev_upper_dev_unlink(real_dev, ep->egress_dev);
232*4882a593Smuzhiyun rmnet_vnd_dellink(ep->mux_id, port, ep);
233*4882a593Smuzhiyun hlist_del_init_rcu(&ep->hlnode);
234*4882a593Smuzhiyun kfree(ep);
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun rmnet_unregister_real_device(real_dev);
237*4882a593Smuzhiyun unregister_netdevice_many(&list);
238*4882a593Smuzhiyun } else {
239*4882a593Smuzhiyun rmnet_unregister_bridge(port);
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun
rmnet_config_notify_cb(struct notifier_block * nb,unsigned long event,void * data)243*4882a593Smuzhiyun static int rmnet_config_notify_cb(struct notifier_block *nb,
244*4882a593Smuzhiyun unsigned long event, void *data)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun struct net_device *real_dev = netdev_notifier_info_to_dev(data);
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun if (!rmnet_is_real_dev_registered(real_dev))
249*4882a593Smuzhiyun return NOTIFY_DONE;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun switch (event) {
252*4882a593Smuzhiyun case NETDEV_UNREGISTER:
253*4882a593Smuzhiyun netdev_dbg(real_dev, "Kernel unregister\n");
254*4882a593Smuzhiyun rmnet_force_unassociate_device(real_dev);
255*4882a593Smuzhiyun break;
256*4882a593Smuzhiyun case NETDEV_CHANGEMTU:
257*4882a593Smuzhiyun if (rmnet_vnd_validate_real_dev_mtu(real_dev))
258*4882a593Smuzhiyun return NOTIFY_BAD;
259*4882a593Smuzhiyun break;
260*4882a593Smuzhiyun default:
261*4882a593Smuzhiyun break;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun return NOTIFY_DONE;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun static struct notifier_block rmnet_dev_notifier __read_mostly = {
268*4882a593Smuzhiyun .notifier_call = rmnet_config_notify_cb,
269*4882a593Smuzhiyun };
270*4882a593Smuzhiyun
rmnet_rtnl_validate(struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)271*4882a593Smuzhiyun static int rmnet_rtnl_validate(struct nlattr *tb[], struct nlattr *data[],
272*4882a593Smuzhiyun struct netlink_ext_ack *extack)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun u16 mux_id;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun if (!data || !data[IFLA_RMNET_MUX_ID]) {
277*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "MUX ID not specified");
278*4882a593Smuzhiyun return -EINVAL;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun mux_id = nla_get_u16(data[IFLA_RMNET_MUX_ID]);
282*4882a593Smuzhiyun if (mux_id > (RMNET_MAX_LOGICAL_EP - 1)) {
283*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "invalid MUX ID");
284*4882a593Smuzhiyun return -ERANGE;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun return 0;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
rmnet_changelink(struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)290*4882a593Smuzhiyun static int rmnet_changelink(struct net_device *dev, struct nlattr *tb[],
291*4882a593Smuzhiyun struct nlattr *data[],
292*4882a593Smuzhiyun struct netlink_ext_ack *extack)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun struct rmnet_priv *priv = netdev_priv(dev);
295*4882a593Smuzhiyun struct net_device *real_dev;
296*4882a593Smuzhiyun struct rmnet_port *port;
297*4882a593Smuzhiyun u16 mux_id;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun if (!dev)
300*4882a593Smuzhiyun return -ENODEV;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun real_dev = priv->real_dev;
303*4882a593Smuzhiyun if (!rmnet_is_real_dev_registered(real_dev))
304*4882a593Smuzhiyun return -ENODEV;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun port = rmnet_get_port_rtnl(real_dev);
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun if (data[IFLA_RMNET_MUX_ID]) {
309*4882a593Smuzhiyun mux_id = nla_get_u16(data[IFLA_RMNET_MUX_ID]);
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun if (mux_id != priv->mux_id) {
312*4882a593Smuzhiyun struct rmnet_endpoint *ep;
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun ep = rmnet_get_endpoint(port, priv->mux_id);
315*4882a593Smuzhiyun if (!ep)
316*4882a593Smuzhiyun return -ENODEV;
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun if (rmnet_get_endpoint(port, mux_id)) {
319*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack,
320*4882a593Smuzhiyun "MUX ID already exists");
321*4882a593Smuzhiyun return -EINVAL;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun hlist_del_init_rcu(&ep->hlnode);
325*4882a593Smuzhiyun hlist_add_head_rcu(&ep->hlnode,
326*4882a593Smuzhiyun &port->muxed_ep[mux_id]);
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun ep->mux_id = mux_id;
329*4882a593Smuzhiyun priv->mux_id = mux_id;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun if (data[IFLA_RMNET_FLAGS]) {
334*4882a593Smuzhiyun struct ifla_rmnet_flags *flags;
335*4882a593Smuzhiyun u32 old_data_format;
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun old_data_format = port->data_format;
338*4882a593Smuzhiyun flags = nla_data(data[IFLA_RMNET_FLAGS]);
339*4882a593Smuzhiyun port->data_format = flags->flags & flags->mask;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun if (rmnet_vnd_update_dev_mtu(port, real_dev)) {
342*4882a593Smuzhiyun port->data_format = old_data_format;
343*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "Invalid MTU on real dev");
344*4882a593Smuzhiyun return -EINVAL;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun return 0;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun
rmnet_get_size(const struct net_device * dev)351*4882a593Smuzhiyun static size_t rmnet_get_size(const struct net_device *dev)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun return
354*4882a593Smuzhiyun /* IFLA_RMNET_MUX_ID */
355*4882a593Smuzhiyun nla_total_size(2) +
356*4882a593Smuzhiyun /* IFLA_RMNET_FLAGS */
357*4882a593Smuzhiyun nla_total_size(sizeof(struct ifla_rmnet_flags));
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun
rmnet_fill_info(struct sk_buff * skb,const struct net_device * dev)360*4882a593Smuzhiyun static int rmnet_fill_info(struct sk_buff *skb, const struct net_device *dev)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun struct rmnet_priv *priv = netdev_priv(dev);
363*4882a593Smuzhiyun struct net_device *real_dev;
364*4882a593Smuzhiyun struct ifla_rmnet_flags f;
365*4882a593Smuzhiyun struct rmnet_port *port;
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun real_dev = priv->real_dev;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun if (nla_put_u16(skb, IFLA_RMNET_MUX_ID, priv->mux_id))
370*4882a593Smuzhiyun goto nla_put_failure;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun if (rmnet_is_real_dev_registered(real_dev)) {
373*4882a593Smuzhiyun port = rmnet_get_port_rtnl(real_dev);
374*4882a593Smuzhiyun f.flags = port->data_format;
375*4882a593Smuzhiyun } else {
376*4882a593Smuzhiyun f.flags = 0;
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun f.mask = ~0;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun if (nla_put(skb, IFLA_RMNET_FLAGS, sizeof(f), &f))
382*4882a593Smuzhiyun goto nla_put_failure;
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun return 0;
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun nla_put_failure:
387*4882a593Smuzhiyun return -EMSGSIZE;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun struct rtnl_link_ops rmnet_link_ops __read_mostly = {
391*4882a593Smuzhiyun .kind = "rmnet",
392*4882a593Smuzhiyun .maxtype = __IFLA_RMNET_MAX,
393*4882a593Smuzhiyun .priv_size = sizeof(struct rmnet_priv),
394*4882a593Smuzhiyun .setup = rmnet_vnd_setup,
395*4882a593Smuzhiyun .validate = rmnet_rtnl_validate,
396*4882a593Smuzhiyun .newlink = rmnet_newlink,
397*4882a593Smuzhiyun .dellink = rmnet_dellink,
398*4882a593Smuzhiyun .get_size = rmnet_get_size,
399*4882a593Smuzhiyun .changelink = rmnet_changelink,
400*4882a593Smuzhiyun .policy = rmnet_policy,
401*4882a593Smuzhiyun .fill_info = rmnet_fill_info,
402*4882a593Smuzhiyun };
403*4882a593Smuzhiyun
rmnet_get_port_rcu(struct net_device * real_dev)404*4882a593Smuzhiyun struct rmnet_port *rmnet_get_port_rcu(struct net_device *real_dev)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun if (rmnet_is_real_dev_registered(real_dev))
407*4882a593Smuzhiyun return rcu_dereference_bh(real_dev->rx_handler_data);
408*4882a593Smuzhiyun else
409*4882a593Smuzhiyun return NULL;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun
rmnet_get_endpoint(struct rmnet_port * port,u8 mux_id)412*4882a593Smuzhiyun struct rmnet_endpoint *rmnet_get_endpoint(struct rmnet_port *port, u8 mux_id)
413*4882a593Smuzhiyun {
414*4882a593Smuzhiyun struct rmnet_endpoint *ep;
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun hlist_for_each_entry_rcu(ep, &port->muxed_ep[mux_id], hlnode) {
417*4882a593Smuzhiyun if (ep->mux_id == mux_id)
418*4882a593Smuzhiyun return ep;
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun return NULL;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
rmnet_add_bridge(struct net_device * rmnet_dev,struct net_device * slave_dev,struct netlink_ext_ack * extack)424*4882a593Smuzhiyun int rmnet_add_bridge(struct net_device *rmnet_dev,
425*4882a593Smuzhiyun struct net_device *slave_dev,
426*4882a593Smuzhiyun struct netlink_ext_ack *extack)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun struct rmnet_priv *priv = netdev_priv(rmnet_dev);
429*4882a593Smuzhiyun struct net_device *real_dev = priv->real_dev;
430*4882a593Smuzhiyun struct rmnet_port *port, *slave_port;
431*4882a593Smuzhiyun int err;
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun port = rmnet_get_port_rtnl(real_dev);
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun /* If there is more than one rmnet dev attached, its probably being
436*4882a593Smuzhiyun * used for muxing. Skip the briding in that case
437*4882a593Smuzhiyun */
438*4882a593Smuzhiyun if (port->nr_rmnet_devs > 1) {
439*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "more than one rmnet dev attached");
440*4882a593Smuzhiyun return -EINVAL;
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun if (port->rmnet_mode != RMNET_EPMODE_VND) {
444*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack, "more than one bridge dev attached");
445*4882a593Smuzhiyun return -EINVAL;
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun if (rmnet_is_real_dev_registered(slave_dev)) {
449*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack,
450*4882a593Smuzhiyun "slave cannot be another rmnet dev");
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun return -EBUSY;
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun err = rmnet_register_real_device(slave_dev, extack);
456*4882a593Smuzhiyun if (err)
457*4882a593Smuzhiyun return -EBUSY;
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun err = netdev_master_upper_dev_link(slave_dev, rmnet_dev, NULL, NULL,
460*4882a593Smuzhiyun extack);
461*4882a593Smuzhiyun if (err) {
462*4882a593Smuzhiyun rmnet_unregister_real_device(slave_dev);
463*4882a593Smuzhiyun return err;
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun slave_port = rmnet_get_port_rtnl(slave_dev);
467*4882a593Smuzhiyun slave_port->rmnet_mode = RMNET_EPMODE_BRIDGE;
468*4882a593Smuzhiyun slave_port->bridge_ep = real_dev;
469*4882a593Smuzhiyun slave_port->rmnet_dev = rmnet_dev;
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun port->rmnet_mode = RMNET_EPMODE_BRIDGE;
472*4882a593Smuzhiyun port->bridge_ep = slave_dev;
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun netdev_dbg(slave_dev, "registered with rmnet as slave\n");
475*4882a593Smuzhiyun return 0;
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun
rmnet_del_bridge(struct net_device * rmnet_dev,struct net_device * slave_dev)478*4882a593Smuzhiyun int rmnet_del_bridge(struct net_device *rmnet_dev,
479*4882a593Smuzhiyun struct net_device *slave_dev)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun struct rmnet_port *port = rmnet_get_port_rtnl(slave_dev);
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun rmnet_unregister_bridge(port);
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun netdev_dbg(slave_dev, "removed from rmnet as slave\n");
486*4882a593Smuzhiyun return 0;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun /* Startup/Shutdown */
490*4882a593Smuzhiyun
rmnet_init(void)491*4882a593Smuzhiyun static int __init rmnet_init(void)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun int rc;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun rc = register_netdevice_notifier(&rmnet_dev_notifier);
496*4882a593Smuzhiyun if (rc != 0)
497*4882a593Smuzhiyun return rc;
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun rc = rtnl_link_register(&rmnet_link_ops);
500*4882a593Smuzhiyun if (rc != 0) {
501*4882a593Smuzhiyun unregister_netdevice_notifier(&rmnet_dev_notifier);
502*4882a593Smuzhiyun return rc;
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun return rc;
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun
rmnet_exit(void)507*4882a593Smuzhiyun static void __exit rmnet_exit(void)
508*4882a593Smuzhiyun {
509*4882a593Smuzhiyun rtnl_link_unregister(&rmnet_link_ops);
510*4882a593Smuzhiyun unregister_netdevice_notifier(&rmnet_dev_notifier);
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun module_init(rmnet_init)
514*4882a593Smuzhiyun module_exit(rmnet_exit)
515*4882a593Smuzhiyun MODULE_ALIAS_RTNL_LINK("rmnet");
516*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
517