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