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