1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) ST-Ericsson AB 2010
4*4882a593Smuzhiyun * Authors: Sjur Brendeland
5*4882a593Smuzhiyun * Daniel Martensson
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/fs.h>
11*4882a593Smuzhiyun #include <linux/init.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/netdevice.h>
14*4882a593Smuzhiyun #include <linux/if_ether.h>
15*4882a593Smuzhiyun #include <linux/ip.h>
16*4882a593Smuzhiyun #include <linux/sched.h>
17*4882a593Smuzhiyun #include <linux/sockios.h>
18*4882a593Smuzhiyun #include <linux/caif/if_caif.h>
19*4882a593Smuzhiyun #include <net/rtnetlink.h>
20*4882a593Smuzhiyun #include <net/caif/caif_layer.h>
21*4882a593Smuzhiyun #include <net/caif/cfpkt.h>
22*4882a593Smuzhiyun #include <net/caif/caif_dev.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun /* GPRS PDP connection has MTU to 1500 */
25*4882a593Smuzhiyun #define GPRS_PDP_MTU 1500
26*4882a593Smuzhiyun /* 5 sec. connect timeout */
27*4882a593Smuzhiyun #define CONNECT_TIMEOUT (5 * HZ)
28*4882a593Smuzhiyun #define CAIF_NET_DEFAULT_QUEUE_LEN 500
29*4882a593Smuzhiyun #define UNDEF_CONNID 0xffffffff
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun /*This list is protected by the rtnl lock. */
32*4882a593Smuzhiyun static LIST_HEAD(chnl_net_list);
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun MODULE_LICENSE("GPL");
35*4882a593Smuzhiyun MODULE_ALIAS_RTNL_LINK("caif");
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun enum caif_states {
38*4882a593Smuzhiyun CAIF_CONNECTED = 1,
39*4882a593Smuzhiyun CAIF_CONNECTING,
40*4882a593Smuzhiyun CAIF_DISCONNECTED,
41*4882a593Smuzhiyun CAIF_SHUTDOWN
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun struct chnl_net {
45*4882a593Smuzhiyun struct cflayer chnl;
46*4882a593Smuzhiyun struct caif_connect_request conn_req;
47*4882a593Smuzhiyun struct list_head list_field;
48*4882a593Smuzhiyun struct net_device *netdev;
49*4882a593Smuzhiyun char name[256];
50*4882a593Smuzhiyun wait_queue_head_t netmgmt_wq;
51*4882a593Smuzhiyun /* Flow status to remember and control the transmission. */
52*4882a593Smuzhiyun bool flowenabled;
53*4882a593Smuzhiyun enum caif_states state;
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun
chnl_recv_cb(struct cflayer * layr,struct cfpkt * pkt)56*4882a593Smuzhiyun static int chnl_recv_cb(struct cflayer *layr, struct cfpkt *pkt)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun struct sk_buff *skb;
59*4882a593Smuzhiyun struct chnl_net *priv;
60*4882a593Smuzhiyun int pktlen;
61*4882a593Smuzhiyun const u8 *ip_version;
62*4882a593Smuzhiyun u8 buf;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun priv = container_of(layr, struct chnl_net, chnl);
65*4882a593Smuzhiyun if (!priv)
66*4882a593Smuzhiyun return -EINVAL;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun skb = (struct sk_buff *) cfpkt_tonative(pkt);
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun /* Get length of CAIF packet. */
71*4882a593Smuzhiyun pktlen = skb->len;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun /* Pass some minimum information and
74*4882a593Smuzhiyun * send the packet to the net stack.
75*4882a593Smuzhiyun */
76*4882a593Smuzhiyun skb->dev = priv->netdev;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun /* check the version of IP */
79*4882a593Smuzhiyun ip_version = skb_header_pointer(skb, 0, 1, &buf);
80*4882a593Smuzhiyun if (!ip_version) {
81*4882a593Smuzhiyun kfree_skb(skb);
82*4882a593Smuzhiyun return -EINVAL;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun switch (*ip_version >> 4) {
86*4882a593Smuzhiyun case 4:
87*4882a593Smuzhiyun skb->protocol = htons(ETH_P_IP);
88*4882a593Smuzhiyun break;
89*4882a593Smuzhiyun case 6:
90*4882a593Smuzhiyun skb->protocol = htons(ETH_P_IPV6);
91*4882a593Smuzhiyun break;
92*4882a593Smuzhiyun default:
93*4882a593Smuzhiyun kfree_skb(skb);
94*4882a593Smuzhiyun priv->netdev->stats.rx_errors++;
95*4882a593Smuzhiyun return -EINVAL;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /* If we change the header in loop mode, the checksum is corrupted. */
99*4882a593Smuzhiyun if (priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP)
100*4882a593Smuzhiyun skb->ip_summed = CHECKSUM_UNNECESSARY;
101*4882a593Smuzhiyun else
102*4882a593Smuzhiyun skb->ip_summed = CHECKSUM_NONE;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun if (in_interrupt())
105*4882a593Smuzhiyun netif_rx(skb);
106*4882a593Smuzhiyun else
107*4882a593Smuzhiyun netif_rx_ni(skb);
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun /* Update statistics. */
110*4882a593Smuzhiyun priv->netdev->stats.rx_packets++;
111*4882a593Smuzhiyun priv->netdev->stats.rx_bytes += pktlen;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun return 0;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
delete_device(struct chnl_net * dev)116*4882a593Smuzhiyun static int delete_device(struct chnl_net *dev)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun ASSERT_RTNL();
119*4882a593Smuzhiyun if (dev->netdev)
120*4882a593Smuzhiyun unregister_netdevice(dev->netdev);
121*4882a593Smuzhiyun return 0;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
close_work(struct work_struct * work)124*4882a593Smuzhiyun static void close_work(struct work_struct *work)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun struct chnl_net *dev = NULL;
127*4882a593Smuzhiyun struct list_head *list_node;
128*4882a593Smuzhiyun struct list_head *_tmp;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun rtnl_lock();
131*4882a593Smuzhiyun list_for_each_safe(list_node, _tmp, &chnl_net_list) {
132*4882a593Smuzhiyun dev = list_entry(list_node, struct chnl_net, list_field);
133*4882a593Smuzhiyun if (dev->state == CAIF_SHUTDOWN)
134*4882a593Smuzhiyun dev_close(dev->netdev);
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun rtnl_unlock();
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun static DECLARE_WORK(close_worker, close_work);
139*4882a593Smuzhiyun
chnl_hold(struct cflayer * lyr)140*4882a593Smuzhiyun static void chnl_hold(struct cflayer *lyr)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun struct chnl_net *priv = container_of(lyr, struct chnl_net, chnl);
143*4882a593Smuzhiyun dev_hold(priv->netdev);
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
chnl_put(struct cflayer * lyr)146*4882a593Smuzhiyun static void chnl_put(struct cflayer *lyr)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun struct chnl_net *priv = container_of(lyr, struct chnl_net, chnl);
149*4882a593Smuzhiyun dev_put(priv->netdev);
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
chnl_flowctrl_cb(struct cflayer * layr,enum caif_ctrlcmd flow,int phyid)152*4882a593Smuzhiyun static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow,
153*4882a593Smuzhiyun int phyid)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun struct chnl_net *priv = container_of(layr, struct chnl_net, chnl);
156*4882a593Smuzhiyun pr_debug("NET flowctrl func called flow: %s\n",
157*4882a593Smuzhiyun flow == CAIF_CTRLCMD_FLOW_ON_IND ? "ON" :
158*4882a593Smuzhiyun flow == CAIF_CTRLCMD_INIT_RSP ? "INIT" :
159*4882a593Smuzhiyun flow == CAIF_CTRLCMD_FLOW_OFF_IND ? "OFF" :
160*4882a593Smuzhiyun flow == CAIF_CTRLCMD_DEINIT_RSP ? "CLOSE/DEINIT" :
161*4882a593Smuzhiyun flow == CAIF_CTRLCMD_INIT_FAIL_RSP ? "OPEN_FAIL" :
162*4882a593Smuzhiyun flow == CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND ?
163*4882a593Smuzhiyun "REMOTE_SHUTDOWN" : "UNKNOWN CTRL COMMAND");
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun switch (flow) {
168*4882a593Smuzhiyun case CAIF_CTRLCMD_FLOW_OFF_IND:
169*4882a593Smuzhiyun priv->flowenabled = false;
170*4882a593Smuzhiyun netif_stop_queue(priv->netdev);
171*4882a593Smuzhiyun break;
172*4882a593Smuzhiyun case CAIF_CTRLCMD_DEINIT_RSP:
173*4882a593Smuzhiyun priv->state = CAIF_DISCONNECTED;
174*4882a593Smuzhiyun break;
175*4882a593Smuzhiyun case CAIF_CTRLCMD_INIT_FAIL_RSP:
176*4882a593Smuzhiyun priv->state = CAIF_DISCONNECTED;
177*4882a593Smuzhiyun wake_up_interruptible(&priv->netmgmt_wq);
178*4882a593Smuzhiyun break;
179*4882a593Smuzhiyun case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
180*4882a593Smuzhiyun priv->state = CAIF_SHUTDOWN;
181*4882a593Smuzhiyun netif_tx_disable(priv->netdev);
182*4882a593Smuzhiyun schedule_work(&close_worker);
183*4882a593Smuzhiyun break;
184*4882a593Smuzhiyun case CAIF_CTRLCMD_FLOW_ON_IND:
185*4882a593Smuzhiyun priv->flowenabled = true;
186*4882a593Smuzhiyun netif_wake_queue(priv->netdev);
187*4882a593Smuzhiyun break;
188*4882a593Smuzhiyun case CAIF_CTRLCMD_INIT_RSP:
189*4882a593Smuzhiyun caif_client_register_refcnt(&priv->chnl, chnl_hold, chnl_put);
190*4882a593Smuzhiyun priv->state = CAIF_CONNECTED;
191*4882a593Smuzhiyun priv->flowenabled = true;
192*4882a593Smuzhiyun netif_wake_queue(priv->netdev);
193*4882a593Smuzhiyun wake_up_interruptible(&priv->netmgmt_wq);
194*4882a593Smuzhiyun break;
195*4882a593Smuzhiyun default:
196*4882a593Smuzhiyun break;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun
chnl_net_start_xmit(struct sk_buff * skb,struct net_device * dev)200*4882a593Smuzhiyun static netdev_tx_t chnl_net_start_xmit(struct sk_buff *skb,
201*4882a593Smuzhiyun struct net_device *dev)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun struct chnl_net *priv;
204*4882a593Smuzhiyun struct cfpkt *pkt = NULL;
205*4882a593Smuzhiyun int len;
206*4882a593Smuzhiyun int result = -1;
207*4882a593Smuzhiyun /* Get our private data. */
208*4882a593Smuzhiyun priv = netdev_priv(dev);
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun if (skb->len > priv->netdev->mtu) {
211*4882a593Smuzhiyun pr_warn("Size of skb exceeded MTU\n");
212*4882a593Smuzhiyun kfree_skb(skb);
213*4882a593Smuzhiyun dev->stats.tx_errors++;
214*4882a593Smuzhiyun return NETDEV_TX_OK;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun if (!priv->flowenabled) {
218*4882a593Smuzhiyun pr_debug("dropping packets flow off\n");
219*4882a593Smuzhiyun kfree_skb(skb);
220*4882a593Smuzhiyun dev->stats.tx_dropped++;
221*4882a593Smuzhiyun return NETDEV_TX_OK;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun if (priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP)
225*4882a593Smuzhiyun swap(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun /* Store original SKB length. */
228*4882a593Smuzhiyun len = skb->len;
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun pkt = cfpkt_fromnative(CAIF_DIR_OUT, (void *) skb);
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun /* Send the packet down the stack. */
233*4882a593Smuzhiyun result = priv->chnl.dn->transmit(priv->chnl.dn, pkt);
234*4882a593Smuzhiyun if (result) {
235*4882a593Smuzhiyun dev->stats.tx_dropped++;
236*4882a593Smuzhiyun return NETDEV_TX_OK;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun /* Update statistics. */
240*4882a593Smuzhiyun dev->stats.tx_packets++;
241*4882a593Smuzhiyun dev->stats.tx_bytes += len;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun return NETDEV_TX_OK;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun
chnl_net_open(struct net_device * dev)246*4882a593Smuzhiyun static int chnl_net_open(struct net_device *dev)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun struct chnl_net *priv = NULL;
249*4882a593Smuzhiyun int result = -1;
250*4882a593Smuzhiyun int llifindex, headroom, tailroom, mtu;
251*4882a593Smuzhiyun struct net_device *lldev;
252*4882a593Smuzhiyun ASSERT_RTNL();
253*4882a593Smuzhiyun priv = netdev_priv(dev);
254*4882a593Smuzhiyun if (!priv) {
255*4882a593Smuzhiyun pr_debug("chnl_net_open: no priv\n");
256*4882a593Smuzhiyun return -ENODEV;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun if (priv->state != CAIF_CONNECTING) {
260*4882a593Smuzhiyun priv->state = CAIF_CONNECTING;
261*4882a593Smuzhiyun result = caif_connect_client(dev_net(dev), &priv->conn_req,
262*4882a593Smuzhiyun &priv->chnl, &llifindex,
263*4882a593Smuzhiyun &headroom, &tailroom);
264*4882a593Smuzhiyun if (result != 0) {
265*4882a593Smuzhiyun pr_debug("err: "
266*4882a593Smuzhiyun "Unable to register and open device,"
267*4882a593Smuzhiyun " Err:%d\n",
268*4882a593Smuzhiyun result);
269*4882a593Smuzhiyun goto error;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun lldev = __dev_get_by_index(dev_net(dev), llifindex);
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun if (lldev == NULL) {
275*4882a593Smuzhiyun pr_debug("no interface?\n");
276*4882a593Smuzhiyun result = -ENODEV;
277*4882a593Smuzhiyun goto error;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun dev->needed_tailroom = tailroom + lldev->needed_tailroom;
281*4882a593Smuzhiyun dev->hard_header_len = headroom + lldev->hard_header_len +
282*4882a593Smuzhiyun lldev->needed_tailroom;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun /*
285*4882a593Smuzhiyun * MTU, head-room etc is not know before we have a
286*4882a593Smuzhiyun * CAIF link layer device available. MTU calculation may
287*4882a593Smuzhiyun * override initial RTNL configuration.
288*4882a593Smuzhiyun * MTU is minimum of current mtu, link layer mtu pluss
289*4882a593Smuzhiyun * CAIF head and tail, and PDP GPRS contexts max MTU.
290*4882a593Smuzhiyun */
291*4882a593Smuzhiyun mtu = min_t(int, dev->mtu, lldev->mtu - (headroom + tailroom));
292*4882a593Smuzhiyun mtu = min_t(int, GPRS_PDP_MTU, mtu);
293*4882a593Smuzhiyun dev_set_mtu(dev, mtu);
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun if (mtu < 100) {
296*4882a593Smuzhiyun pr_warn("CAIF Interface MTU too small (%d)\n", mtu);
297*4882a593Smuzhiyun result = -ENODEV;
298*4882a593Smuzhiyun goto error;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun rtnl_unlock(); /* Release RTNL lock during connect wait */
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun result = wait_event_interruptible_timeout(priv->netmgmt_wq,
305*4882a593Smuzhiyun priv->state != CAIF_CONNECTING,
306*4882a593Smuzhiyun CONNECT_TIMEOUT);
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun rtnl_lock();
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun if (result == -ERESTARTSYS) {
311*4882a593Smuzhiyun pr_debug("wait_event_interruptible woken by a signal\n");
312*4882a593Smuzhiyun result = -ERESTARTSYS;
313*4882a593Smuzhiyun goto error;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun if (result == 0) {
317*4882a593Smuzhiyun pr_debug("connect timeout\n");
318*4882a593Smuzhiyun result = -ETIMEDOUT;
319*4882a593Smuzhiyun goto error;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun if (priv->state != CAIF_CONNECTED) {
323*4882a593Smuzhiyun pr_debug("connect failed\n");
324*4882a593Smuzhiyun result = -ECONNREFUSED;
325*4882a593Smuzhiyun goto error;
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun pr_debug("CAIF Netdevice connected\n");
328*4882a593Smuzhiyun return 0;
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun error:
331*4882a593Smuzhiyun caif_disconnect_client(dev_net(dev), &priv->chnl);
332*4882a593Smuzhiyun priv->state = CAIF_DISCONNECTED;
333*4882a593Smuzhiyun pr_debug("state disconnected\n");
334*4882a593Smuzhiyun return result;
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun
chnl_net_stop(struct net_device * dev)338*4882a593Smuzhiyun static int chnl_net_stop(struct net_device *dev)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun struct chnl_net *priv;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun ASSERT_RTNL();
343*4882a593Smuzhiyun priv = netdev_priv(dev);
344*4882a593Smuzhiyun priv->state = CAIF_DISCONNECTED;
345*4882a593Smuzhiyun caif_disconnect_client(dev_net(dev), &priv->chnl);
346*4882a593Smuzhiyun return 0;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
chnl_net_init(struct net_device * dev)349*4882a593Smuzhiyun static int chnl_net_init(struct net_device *dev)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun struct chnl_net *priv;
352*4882a593Smuzhiyun ASSERT_RTNL();
353*4882a593Smuzhiyun priv = netdev_priv(dev);
354*4882a593Smuzhiyun strncpy(priv->name, dev->name, sizeof(priv->name));
355*4882a593Smuzhiyun INIT_LIST_HEAD(&priv->list_field);
356*4882a593Smuzhiyun return 0;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun
chnl_net_uninit(struct net_device * dev)359*4882a593Smuzhiyun static void chnl_net_uninit(struct net_device *dev)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun struct chnl_net *priv;
362*4882a593Smuzhiyun ASSERT_RTNL();
363*4882a593Smuzhiyun priv = netdev_priv(dev);
364*4882a593Smuzhiyun list_del_init(&priv->list_field);
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun static const struct net_device_ops netdev_ops = {
368*4882a593Smuzhiyun .ndo_open = chnl_net_open,
369*4882a593Smuzhiyun .ndo_stop = chnl_net_stop,
370*4882a593Smuzhiyun .ndo_init = chnl_net_init,
371*4882a593Smuzhiyun .ndo_uninit = chnl_net_uninit,
372*4882a593Smuzhiyun .ndo_start_xmit = chnl_net_start_xmit,
373*4882a593Smuzhiyun };
374*4882a593Smuzhiyun
chnl_net_destructor(struct net_device * dev)375*4882a593Smuzhiyun static void chnl_net_destructor(struct net_device *dev)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun struct chnl_net *priv = netdev_priv(dev);
378*4882a593Smuzhiyun caif_free_client(&priv->chnl);
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun
ipcaif_net_setup(struct net_device * dev)381*4882a593Smuzhiyun static void ipcaif_net_setup(struct net_device *dev)
382*4882a593Smuzhiyun {
383*4882a593Smuzhiyun struct chnl_net *priv;
384*4882a593Smuzhiyun dev->netdev_ops = &netdev_ops;
385*4882a593Smuzhiyun dev->needs_free_netdev = true;
386*4882a593Smuzhiyun dev->priv_destructor = chnl_net_destructor;
387*4882a593Smuzhiyun dev->flags |= IFF_NOARP;
388*4882a593Smuzhiyun dev->flags |= IFF_POINTOPOINT;
389*4882a593Smuzhiyun dev->mtu = GPRS_PDP_MTU;
390*4882a593Smuzhiyun dev->tx_queue_len = CAIF_NET_DEFAULT_QUEUE_LEN;
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun priv = netdev_priv(dev);
393*4882a593Smuzhiyun priv->chnl.receive = chnl_recv_cb;
394*4882a593Smuzhiyun priv->chnl.ctrlcmd = chnl_flowctrl_cb;
395*4882a593Smuzhiyun priv->netdev = dev;
396*4882a593Smuzhiyun priv->conn_req.protocol = CAIFPROTO_DATAGRAM;
397*4882a593Smuzhiyun priv->conn_req.link_selector = CAIF_LINK_HIGH_BANDW;
398*4882a593Smuzhiyun priv->conn_req.priority = CAIF_PRIO_LOW;
399*4882a593Smuzhiyun /* Insert illegal value */
400*4882a593Smuzhiyun priv->conn_req.sockaddr.u.dgm.connection_id = UNDEF_CONNID;
401*4882a593Smuzhiyun priv->flowenabled = false;
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun init_waitqueue_head(&priv->netmgmt_wq);
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun
ipcaif_fill_info(struct sk_buff * skb,const struct net_device * dev)407*4882a593Smuzhiyun static int ipcaif_fill_info(struct sk_buff *skb, const struct net_device *dev)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun struct chnl_net *priv;
410*4882a593Smuzhiyun u8 loop;
411*4882a593Smuzhiyun priv = netdev_priv(dev);
412*4882a593Smuzhiyun if (nla_put_u32(skb, IFLA_CAIF_IPV4_CONNID,
413*4882a593Smuzhiyun priv->conn_req.sockaddr.u.dgm.connection_id) ||
414*4882a593Smuzhiyun nla_put_u32(skb, IFLA_CAIF_IPV6_CONNID,
415*4882a593Smuzhiyun priv->conn_req.sockaddr.u.dgm.connection_id))
416*4882a593Smuzhiyun goto nla_put_failure;
417*4882a593Smuzhiyun loop = priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP;
418*4882a593Smuzhiyun if (nla_put_u8(skb, IFLA_CAIF_LOOPBACK, loop))
419*4882a593Smuzhiyun goto nla_put_failure;
420*4882a593Smuzhiyun return 0;
421*4882a593Smuzhiyun nla_put_failure:
422*4882a593Smuzhiyun return -EMSGSIZE;
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun
caif_netlink_parms(struct nlattr * data[],struct caif_connect_request * conn_req)426*4882a593Smuzhiyun static void caif_netlink_parms(struct nlattr *data[],
427*4882a593Smuzhiyun struct caif_connect_request *conn_req)
428*4882a593Smuzhiyun {
429*4882a593Smuzhiyun if (!data) {
430*4882a593Smuzhiyun pr_warn("no params data found\n");
431*4882a593Smuzhiyun return;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun if (data[IFLA_CAIF_IPV4_CONNID])
434*4882a593Smuzhiyun conn_req->sockaddr.u.dgm.connection_id =
435*4882a593Smuzhiyun nla_get_u32(data[IFLA_CAIF_IPV4_CONNID]);
436*4882a593Smuzhiyun if (data[IFLA_CAIF_IPV6_CONNID])
437*4882a593Smuzhiyun conn_req->sockaddr.u.dgm.connection_id =
438*4882a593Smuzhiyun nla_get_u32(data[IFLA_CAIF_IPV6_CONNID]);
439*4882a593Smuzhiyun if (data[IFLA_CAIF_LOOPBACK]) {
440*4882a593Smuzhiyun if (nla_get_u8(data[IFLA_CAIF_LOOPBACK]))
441*4882a593Smuzhiyun conn_req->protocol = CAIFPROTO_DATAGRAM_LOOP;
442*4882a593Smuzhiyun else
443*4882a593Smuzhiyun conn_req->protocol = CAIFPROTO_DATAGRAM;
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun
ipcaif_newlink(struct net * src_net,struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)447*4882a593Smuzhiyun static int ipcaif_newlink(struct net *src_net, struct net_device *dev,
448*4882a593Smuzhiyun struct nlattr *tb[], struct nlattr *data[],
449*4882a593Smuzhiyun struct netlink_ext_ack *extack)
450*4882a593Smuzhiyun {
451*4882a593Smuzhiyun int ret;
452*4882a593Smuzhiyun struct chnl_net *caifdev;
453*4882a593Smuzhiyun ASSERT_RTNL();
454*4882a593Smuzhiyun caifdev = netdev_priv(dev);
455*4882a593Smuzhiyun caif_netlink_parms(data, &caifdev->conn_req);
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun ret = register_netdevice(dev);
458*4882a593Smuzhiyun if (ret)
459*4882a593Smuzhiyun pr_warn("device rtml registration failed\n");
460*4882a593Smuzhiyun else
461*4882a593Smuzhiyun list_add(&caifdev->list_field, &chnl_net_list);
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun /* Use ifindex as connection id, and use loopback channel default. */
464*4882a593Smuzhiyun if (caifdev->conn_req.sockaddr.u.dgm.connection_id == UNDEF_CONNID) {
465*4882a593Smuzhiyun caifdev->conn_req.sockaddr.u.dgm.connection_id = dev->ifindex;
466*4882a593Smuzhiyun caifdev->conn_req.protocol = CAIFPROTO_DATAGRAM_LOOP;
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun return ret;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun
ipcaif_changelink(struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)471*4882a593Smuzhiyun static int ipcaif_changelink(struct net_device *dev, struct nlattr *tb[],
472*4882a593Smuzhiyun struct nlattr *data[],
473*4882a593Smuzhiyun struct netlink_ext_ack *extack)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun struct chnl_net *caifdev;
476*4882a593Smuzhiyun ASSERT_RTNL();
477*4882a593Smuzhiyun caifdev = netdev_priv(dev);
478*4882a593Smuzhiyun caif_netlink_parms(data, &caifdev->conn_req);
479*4882a593Smuzhiyun netdev_state_change(dev);
480*4882a593Smuzhiyun return 0;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun
ipcaif_get_size(const struct net_device * dev)483*4882a593Smuzhiyun static size_t ipcaif_get_size(const struct net_device *dev)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun return
486*4882a593Smuzhiyun /* IFLA_CAIF_IPV4_CONNID */
487*4882a593Smuzhiyun nla_total_size(4) +
488*4882a593Smuzhiyun /* IFLA_CAIF_IPV6_CONNID */
489*4882a593Smuzhiyun nla_total_size(4) +
490*4882a593Smuzhiyun /* IFLA_CAIF_LOOPBACK */
491*4882a593Smuzhiyun nla_total_size(2) +
492*4882a593Smuzhiyun 0;
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun static const struct nla_policy ipcaif_policy[IFLA_CAIF_MAX + 1] = {
496*4882a593Smuzhiyun [IFLA_CAIF_IPV4_CONNID] = { .type = NLA_U32 },
497*4882a593Smuzhiyun [IFLA_CAIF_IPV6_CONNID] = { .type = NLA_U32 },
498*4882a593Smuzhiyun [IFLA_CAIF_LOOPBACK] = { .type = NLA_U8 }
499*4882a593Smuzhiyun };
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun static struct rtnl_link_ops ipcaif_link_ops __read_mostly = {
503*4882a593Smuzhiyun .kind = "caif",
504*4882a593Smuzhiyun .priv_size = sizeof(struct chnl_net),
505*4882a593Smuzhiyun .setup = ipcaif_net_setup,
506*4882a593Smuzhiyun .maxtype = IFLA_CAIF_MAX,
507*4882a593Smuzhiyun .policy = ipcaif_policy,
508*4882a593Smuzhiyun .newlink = ipcaif_newlink,
509*4882a593Smuzhiyun .changelink = ipcaif_changelink,
510*4882a593Smuzhiyun .get_size = ipcaif_get_size,
511*4882a593Smuzhiyun .fill_info = ipcaif_fill_info,
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun };
514*4882a593Smuzhiyun
chnl_init_module(void)515*4882a593Smuzhiyun static int __init chnl_init_module(void)
516*4882a593Smuzhiyun {
517*4882a593Smuzhiyun return rtnl_link_register(&ipcaif_link_ops);
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun
chnl_exit_module(void)520*4882a593Smuzhiyun static void __exit chnl_exit_module(void)
521*4882a593Smuzhiyun {
522*4882a593Smuzhiyun struct chnl_net *dev = NULL;
523*4882a593Smuzhiyun struct list_head *list_node;
524*4882a593Smuzhiyun struct list_head *_tmp;
525*4882a593Smuzhiyun rtnl_link_unregister(&ipcaif_link_ops);
526*4882a593Smuzhiyun rtnl_lock();
527*4882a593Smuzhiyun list_for_each_safe(list_node, _tmp, &chnl_net_list) {
528*4882a593Smuzhiyun dev = list_entry(list_node, struct chnl_net, list_field);
529*4882a593Smuzhiyun list_del_init(list_node);
530*4882a593Smuzhiyun delete_device(dev);
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun rtnl_unlock();
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun module_init(chnl_init_module);
536*4882a593Smuzhiyun module_exit(chnl_exit_module);
537