Blame view

net/caif/chnl_net.c 13.1 KB
af873fcec   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
cc36a070b   Sjur Braendeland   net-caif: add CAI...
2
3
  /*
   * Copyright (C) ST-Ericsson AB 2010
26ee65e68   sjur.brandeland@stericsson.com   caif: Remove my b...
4
   * Authors:	Sjur Brendeland
c2cd0a560   sjur.brandeland@stericsson.com   caif: Remove boun...
5
   *		Daniel Martensson
cc36a070b   Sjur Braendeland   net-caif: add CAI...
6
   */
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
7
  #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
cc36a070b   Sjur Braendeland   net-caif: add CAI...
8
9
10
11
12
  #include <linux/fs.h>
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/netdevice.h>
  #include <linux/if_ether.h>
cc36a070b   Sjur Braendeland   net-caif: add CAI...
13
14
15
16
17
18
  #include <linux/ip.h>
  #include <linux/sched.h>
  #include <linux/sockios.h>
  #include <linux/caif/if_caif.h>
  #include <net/rtnetlink.h>
  #include <net/caif/caif_layer.h>
cc36a070b   Sjur Braendeland   net-caif: add CAI...
19
20
  #include <net/caif/cfpkt.h>
  #include <net/caif/caif_dev.h>
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
21
  /* GPRS PDP connection has MTU to 1500 */
2aa40aef9   Sjur Braendeland   caif: Use link la...
22
  #define GPRS_PDP_MTU 1500
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
23
24
  /* 5 sec. connect timeout */
  #define CONNECT_TIMEOUT (5 * HZ)
cc36a070b   Sjur Braendeland   net-caif: add CAI...
25
  #define CAIF_NET_DEFAULT_QUEUE_LEN 500
e3abcc2a8   sjur.brandeland@stericsson.com   caif: make zero a...
26
  #define UNDEF_CONNID 0xffffffff
cc36a070b   Sjur Braendeland   net-caif: add CAI...
27

cc36a070b   Sjur Braendeland   net-caif: add CAI...
28
29
30
31
32
  /*This list is protected by the rtnl lock. */
  static LIST_HEAD(chnl_net_list);
  
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_RTNL_LINK("caif");
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
33
34
35
36
37
38
  enum caif_states {
  	CAIF_CONNECTED		= 1,
  	CAIF_CONNECTING,
  	CAIF_DISCONNECTED,
  	CAIF_SHUTDOWN
  };
cc36a070b   Sjur Braendeland   net-caif: add CAI...
39
40
  struct chnl_net {
  	struct cflayer chnl;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
41
42
43
44
45
46
47
  	struct caif_connect_request conn_req;
  	struct list_head list_field;
  	struct net_device *netdev;
  	char name[256];
  	wait_queue_head_t netmgmt_wq;
  	/* Flow status to remember and control the transmission. */
  	bool flowenabled;
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
48
  	enum caif_states state;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
49
50
51
52
53
54
55
56
57
58
  };
  
  static void robust_list_del(struct list_head *delete_node)
  {
  	struct list_head *list_node;
  	struct list_head *n;
  	ASSERT_RTNL();
  	list_for_each_safe(list_node, n, &chnl_net_list) {
  		if (list_node == delete_node) {
  			list_del(list_node);
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
59
  			return;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
60
61
  		}
  	}
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
62
  	WARN_ON(1);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
63
64
65
66
67
  }
  
  static int chnl_recv_cb(struct cflayer *layr, struct cfpkt *pkt)
  {
  	struct sk_buff *skb;
af2ce213f   Dan Carpenter   caif: remove dupl...
68
  	struct chnl_net *priv;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
69
  	int pktlen;
d7b92affb   Kumar Sanghvi   CAIF: Fix IPv6 su...
70
71
  	const u8 *ip_version;
  	u8 buf;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
72
73
  
  	priv = container_of(layr, struct chnl_net, chnl);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
74
75
  	if (!priv)
  		return -EINVAL;
3f874adc4   sjur.brandeland@stericsson.com   caif: remove unes...
76
  	skb = (struct sk_buff *) cfpkt_tonative(pkt);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
77
  	/* Get length of CAIF packet. */
3f874adc4   sjur.brandeland@stericsson.com   caif: remove unes...
78
  	pktlen = skb->len;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
79

cc36a070b   Sjur Braendeland   net-caif: add CAI...
80
81
82
83
  	/* Pass some minimum information and
  	 * send the packet to the net stack.
  	 */
  	skb->dev = priv->netdev;
d7b92affb   Kumar Sanghvi   CAIF: Fix IPv6 su...
84
85
86
  
  	/* check the version of IP */
  	ip_version = skb_header_pointer(skb, 0, 1, &buf);
d92c7f8aa   Jesper Juhl   caif: Do not dere...
87
88
89
90
  	if (!ip_version) {
  		kfree_skb(skb);
  		return -EINVAL;
  	}
576f3cc7f   sjur.brandeland@stericsson.com   caif: Add drop co...
91

d7b92affb   Kumar Sanghvi   CAIF: Fix IPv6 su...
92
93
94
95
96
97
98
99
  	switch (*ip_version >> 4) {
  	case 4:
  		skb->protocol = htons(ETH_P_IP);
  		break;
  	case 6:
  		skb->protocol = htons(ETH_P_IPV6);
  		break;
  	default:
5c699fb7d   Tomasz Gregorek   caif: Fix memory ...
100
  		kfree_skb(skb);
576f3cc7f   sjur.brandeland@stericsson.com   caif: Add drop co...
101
  		priv->netdev->stats.rx_errors++;
d7b92affb   Kumar Sanghvi   CAIF: Fix IPv6 su...
102
103
  		return -EINVAL;
  	}
cc36a070b   Sjur Braendeland   net-caif: add CAI...
104
105
106
107
108
109
  
  	/* If we change the header in loop mode, the checksum is corrupted. */
  	if (priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP)
  		skb->ip_summed = CHECKSUM_UNNECESSARY;
  	else
  		skb->ip_summed = CHECKSUM_NONE;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
110
111
112
113
114
115
116
117
  	if (in_interrupt())
  		netif_rx(skb);
  	else
  		netif_rx_ni(skb);
  
  	/* Update statistics. */
  	priv->netdev->stats.rx_packets++;
  	priv->netdev->stats.rx_bytes += pktlen;
576f3cc7f   sjur.brandeland@stericsson.com   caif: Add drop co...
118
  	return 0;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  }
  
  static int delete_device(struct chnl_net *dev)
  {
  	ASSERT_RTNL();
  	if (dev->netdev)
  		unregister_netdevice(dev->netdev);
  	return 0;
  }
  
  static void close_work(struct work_struct *work)
  {
  	struct chnl_net *dev = NULL;
  	struct list_head *list_node;
  	struct list_head *_tmp;
41be5a4a3   sjur.brandeland@stericsson.com   caif: Fix race wh...
134
135
  
  	rtnl_lock();
cc36a070b   Sjur Braendeland   net-caif: add CAI...
136
137
  	list_for_each_safe(list_node, _tmp, &chnl_net_list) {
  		dev = list_entry(list_node, struct chnl_net, list_field);
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
138
139
  		if (dev->state == CAIF_SHUTDOWN)
  			dev_close(dev->netdev);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
140
  	}
41be5a4a3   sjur.brandeland@stericsson.com   caif: Fix race wh...
141
  	rtnl_unlock();
cc36a070b   Sjur Braendeland   net-caif: add CAI...
142
143
  }
  static DECLARE_WORK(close_worker, close_work);
b3ccfbe40   sjur.brandeland@stericsson.com   caif: Protected i...
144
145
146
147
148
149
150
151
152
153
154
  static void chnl_hold(struct cflayer *lyr)
  {
  	struct chnl_net *priv = container_of(lyr, struct chnl_net, chnl);
  	dev_hold(priv->netdev);
  }
  
  static void chnl_put(struct cflayer *lyr)
  {
  	struct chnl_net *priv = container_of(lyr, struct chnl_net, chnl);
  	dev_put(priv->netdev);
  }
cc36a070b   Sjur Braendeland   net-caif: add CAI...
155
  static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow,
3bffc475f   Silviu-Mihai Popescu   CAIF: fix indenta...
156
  			     int phyid)
cc36a070b   Sjur Braendeland   net-caif: add CAI...
157
  {
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
158
  	struct chnl_net *priv = container_of(layr, struct chnl_net, chnl);
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
159
160
  	pr_debug("NET flowctrl func called flow: %s
  ",
cc36a070b   Sjur Braendeland   net-caif: add CAI...
161
162
163
164
165
166
  		flow == CAIF_CTRLCMD_FLOW_ON_IND ? "ON" :
  		flow == CAIF_CTRLCMD_INIT_RSP ? "INIT" :
  		flow == CAIF_CTRLCMD_FLOW_OFF_IND ? "OFF" :
  		flow == CAIF_CTRLCMD_DEINIT_RSP ? "CLOSE/DEINIT" :
  		flow == CAIF_CTRLCMD_INIT_FAIL_RSP ? "OPEN_FAIL" :
  		flow == CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND ?
5e84b38b0   Colin Ian King   net: caif: fix sp...
167
  		 "REMOTE_SHUTDOWN" : "UNKNOWN CTRL COMMAND");
cc36a070b   Sjur Braendeland   net-caif: add CAI...
168

8391c4aab   Sjur Braendeland   caif: Bugfixes in...
169

cc36a070b   Sjur Braendeland   net-caif: add CAI...
170
171
172
  
  	switch (flow) {
  	case CAIF_CTRLCMD_FLOW_OFF_IND:
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
173
174
175
  		priv->flowenabled = false;
  		netif_stop_queue(priv->netdev);
  		break;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
176
  	case CAIF_CTRLCMD_DEINIT_RSP:
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
177
178
  		priv->state = CAIF_DISCONNECTED;
  		break;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
179
  	case CAIF_CTRLCMD_INIT_FAIL_RSP:
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
180
181
182
  		priv->state = CAIF_DISCONNECTED;
  		wake_up_interruptible(&priv->netmgmt_wq);
  		break;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
183
  	case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
184
  		priv->state = CAIF_SHUTDOWN;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
185
  		netif_tx_disable(priv->netdev);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
186
187
188
  		schedule_work(&close_worker);
  		break;
  	case CAIF_CTRLCMD_FLOW_ON_IND:
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
189
190
191
  		priv->flowenabled = true;
  		netif_wake_queue(priv->netdev);
  		break;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
192
  	case CAIF_CTRLCMD_INIT_RSP:
b3ccfbe40   sjur.brandeland@stericsson.com   caif: Protected i...
193
  		caif_client_register_refcnt(&priv->chnl, chnl_hold, chnl_put);
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
194
  		priv->state = CAIF_CONNECTED;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
195
196
197
198
199
200
201
202
  		priv->flowenabled = true;
  		netif_wake_queue(priv->netdev);
  		wake_up_interruptible(&priv->netmgmt_wq);
  		break;
  	default:
  		break;
  	}
  }
99b2292ba   Yunjian Wang   net: caif: Fix us...
203
204
  static netdev_tx_t chnl_net_start_xmit(struct sk_buff *skb,
  				       struct net_device *dev)
cc36a070b   Sjur Braendeland   net-caif: add CAI...
205
206
207
208
209
210
211
212
213
  {
  	struct chnl_net *priv;
  	struct cfpkt *pkt = NULL;
  	int len;
  	int result = -1;
  	/* Get our private data. */
  	priv = netdev_priv(dev);
  
  	if (skb->len > priv->netdev->mtu) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
214
215
  		pr_warn("Size of skb exceeded MTU
  ");
5c699fb7d   Tomasz Gregorek   caif: Fix memory ...
216
  		kfree_skb(skb);
576f3cc7f   sjur.brandeland@stericsson.com   caif: Add drop co...
217
  		dev->stats.tx_errors++;
5c699fb7d   Tomasz Gregorek   caif: Fix memory ...
218
  		return NETDEV_TX_OK;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
219
220
221
  	}
  
  	if (!priv->flowenabled) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
222
223
  		pr_debug("dropping packets flow off
  ");
5c699fb7d   Tomasz Gregorek   caif: Fix memory ...
224
  		kfree_skb(skb);
576f3cc7f   sjur.brandeland@stericsson.com   caif: Add drop co...
225
  		dev->stats.tx_dropped++;
5c699fb7d   Tomasz Gregorek   caif: Fix memory ...
226
  		return NETDEV_TX_OK;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
227
228
229
230
231
232
233
234
235
  	}
  
  	if (priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP)
  		swap(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
  
  	/* Store original SKB length. */
  	len = skb->len;
  
  	pkt = cfpkt_fromnative(CAIF_DIR_OUT, (void *) skb);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
236
237
238
  	/* Send the packet down the stack. */
  	result = priv->chnl.dn->transmit(priv->chnl.dn, pkt);
  	if (result) {
576f3cc7f   sjur.brandeland@stericsson.com   caif: Add drop co...
239
  		dev->stats.tx_dropped++;
5c699fb7d   Tomasz Gregorek   caif: Fix memory ...
240
  		return NETDEV_TX_OK;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
241
242
243
244
245
246
247
248
249
250
251
252
253
  	}
  
  	/* Update statistics. */
  	dev->stats.tx_packets++;
  	dev->stats.tx_bytes += len;
  
  	return NETDEV_TX_OK;
  }
  
  static int chnl_net_open(struct net_device *dev)
  {
  	struct chnl_net *priv = NULL;
  	int result = -1;
2aa40aef9   Sjur Braendeland   caif: Use link la...
254
255
  	int llifindex, headroom, tailroom, mtu;
  	struct net_device *lldev;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
256
  	ASSERT_RTNL();
cc36a070b   Sjur Braendeland   net-caif: add CAI...
257
  	priv = netdev_priv(dev);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
258
  	if (!priv) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
259
260
  		pr_debug("chnl_net_open: no priv
  ");
cc36a070b   Sjur Braendeland   net-caif: add CAI...
261
262
  		return -ENODEV;
  	}
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
263
264
265
  
  	if (priv->state != CAIF_CONNECTING) {
  		priv->state = CAIF_CONNECTING;
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
266
267
268
  		result = caif_connect_client(dev_net(dev), &priv->conn_req,
  						&priv->chnl, &llifindex,
  						&headroom, &tailroom);
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
269
  		if (result != 0) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
270
271
272
273
274
  				pr_debug("err: "
  					 "Unable to register and open device,"
  					 " Err:%d
  ",
  					 result);
2aa40aef9   Sjur Braendeland   caif: Use link la...
275
276
  				goto error;
  		}
a74e94269   Ying Xue   caif: __dev_get_b...
277
  		lldev = __dev_get_by_index(dev_net(dev), llifindex);
2aa40aef9   Sjur Braendeland   caif: Use link la...
278
279
  
  		if (lldev == NULL) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
280
281
  			pr_debug("no interface?
  ");
2aa40aef9   Sjur Braendeland   caif: Use link la...
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
  			result = -ENODEV;
  			goto error;
  		}
  
  		dev->needed_tailroom = tailroom + lldev->needed_tailroom;
  		dev->hard_header_len = headroom + lldev->hard_header_len +
  			lldev->needed_tailroom;
  
  		/*
  		 * MTU, head-room etc is not know before we have a
  		 * CAIF link layer device available. MTU calculation may
  		 * override initial RTNL configuration.
  		 * MTU is minimum of current mtu, link layer mtu pluss
  		 * CAIF head and tail, and PDP GPRS contexts max MTU.
  		 */
  		mtu = min_t(int, dev->mtu, lldev->mtu - (headroom + tailroom));
  		mtu = min_t(int, GPRS_PDP_MTU, mtu);
  		dev_set_mtu(dev, mtu);
2aa40aef9   Sjur Braendeland   caif: Use link la...
300
301
  
  		if (mtu < 100) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
302
303
  			pr_warn("CAIF Interface MTU too small (%d)
  ", mtu);
2aa40aef9   Sjur Braendeland   caif: Use link la...
304
305
  			result = -ENODEV;
  			goto error;
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
306
  		}
cc36a070b   Sjur Braendeland   net-caif: add CAI...
307
  	}
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
308

2aa40aef9   Sjur Braendeland   caif: Use link la...
309
  	rtnl_unlock();  /* Release RTNL lock during connect wait */
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
310
311
312
  	result = wait_event_interruptible_timeout(priv->netmgmt_wq,
  						priv->state != CAIF_CONNECTING,
  						CONNECT_TIMEOUT);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
313

2aa40aef9   Sjur Braendeland   caif: Use link la...
314
  	rtnl_lock();
cc36a070b   Sjur Braendeland   net-caif: add CAI...
315
  	if (result == -ERESTARTSYS) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
316
317
  		pr_debug("wait_event_interruptible woken by a signal
  ");
2aa40aef9   Sjur Braendeland   caif: Use link la...
318
319
  		result = -ERESTARTSYS;
  		goto error;
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
320
  	}
2aa40aef9   Sjur Braendeland   caif: Use link la...
321

8391c4aab   Sjur Braendeland   caif: Bugfixes in...
322
  	if (result == 0) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
323
324
  		pr_debug("connect timeout
  ");
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
325
  		caif_disconnect_client(dev_net(dev), &priv->chnl);
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
326
  		priv->state = CAIF_DISCONNECTED;
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
327
328
  		pr_debug("state disconnected
  ");
2aa40aef9   Sjur Braendeland   caif: Use link la...
329
330
  		result = -ETIMEDOUT;
  		goto error;
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
331
  	}
cc36a070b   Sjur Braendeland   net-caif: add CAI...
332

8391c4aab   Sjur Braendeland   caif: Bugfixes in...
333
  	if (priv->state != CAIF_CONNECTED) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
334
335
  		pr_debug("connect failed
  ");
2aa40aef9   Sjur Braendeland   caif: Use link la...
336
337
  		result = -ECONNREFUSED;
  		goto error;
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
338
  	}
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
339
340
  	pr_debug("CAIF Netdevice connected
  ");
cc36a070b   Sjur Braendeland   net-caif: add CAI...
341
  	return 0;
2aa40aef9   Sjur Braendeland   caif: Use link la...
342
343
  
  error:
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
344
  	caif_disconnect_client(dev_net(dev), &priv->chnl);
2aa40aef9   Sjur Braendeland   caif: Use link la...
345
  	priv->state = CAIF_DISCONNECTED;
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
346
347
  	pr_debug("state disconnected
  ");
2aa40aef9   Sjur Braendeland   caif: Use link la...
348
  	return result;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
349
350
351
352
353
  }
  
  static int chnl_net_stop(struct net_device *dev)
  {
  	struct chnl_net *priv;
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
354

cc36a070b   Sjur Braendeland   net-caif: add CAI...
355
356
  	ASSERT_RTNL();
  	priv = netdev_priv(dev);
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
357
  	priv->state = CAIF_DISCONNECTED;
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
358
  	caif_disconnect_client(dev_net(dev), &priv->chnl);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
  	return 0;
  }
  
  static int chnl_net_init(struct net_device *dev)
  {
  	struct chnl_net *priv;
  	ASSERT_RTNL();
  	priv = netdev_priv(dev);
  	strncpy(priv->name, dev->name, sizeof(priv->name));
  	return 0;
  }
  
  static void chnl_net_uninit(struct net_device *dev)
  {
  	struct chnl_net *priv;
  	ASSERT_RTNL();
  	priv = netdev_priv(dev);
  	robust_list_del(&priv->list_field);
  }
  
  static const struct net_device_ops netdev_ops = {
  	.ndo_open = chnl_net_open,
  	.ndo_stop = chnl_net_stop,
  	.ndo_init = chnl_net_init,
  	.ndo_uninit = chnl_net_uninit,
  	.ndo_start_xmit = chnl_net_start_xmit,
  };
b3ccfbe40   sjur.brandeland@stericsson.com   caif: Protected i...
386
387
388
389
  static void chnl_net_destructor(struct net_device *dev)
  {
  	struct chnl_net *priv = netdev_priv(dev);
  	caif_free_client(&priv->chnl);
b3ccfbe40   sjur.brandeland@stericsson.com   caif: Protected i...
390
  }
cc36a070b   Sjur Braendeland   net-caif: add CAI...
391
392
393
394
  static void ipcaif_net_setup(struct net_device *dev)
  {
  	struct chnl_net *priv;
  	dev->netdev_ops = &netdev_ops;
cf124db56   David S. Miller   net: Fix inconsis...
395
396
  	dev->needs_free_netdev = true;
  	dev->priv_destructor = chnl_net_destructor;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
397
398
  	dev->flags |= IFF_NOARP;
  	dev->flags |= IFF_POINTOPOINT;
2aa40aef9   Sjur Braendeland   caif: Use link la...
399
  	dev->mtu = GPRS_PDP_MTU;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
400
401
402
403
404
405
406
407
408
409
  	dev->tx_queue_len = CAIF_NET_DEFAULT_QUEUE_LEN;
  
  	priv = netdev_priv(dev);
  	priv->chnl.receive = chnl_recv_cb;
  	priv->chnl.ctrlcmd = chnl_flowctrl_cb;
  	priv->netdev = dev;
  	priv->conn_req.protocol = CAIFPROTO_DATAGRAM;
  	priv->conn_req.link_selector = CAIF_LINK_HIGH_BANDW;
  	priv->conn_req.priority = CAIF_PRIO_LOW;
  	/* Insert illegal value */
e3abcc2a8   sjur.brandeland@stericsson.com   caif: make zero a...
410
  	priv->conn_req.sockaddr.u.dgm.connection_id = UNDEF_CONNID;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
411
  	priv->flowenabled = false;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
412
  	init_waitqueue_head(&priv->netmgmt_wq);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
413
414
415
416
417
418
419
420
  }
  
  
  static int ipcaif_fill_info(struct sk_buff *skb, const struct net_device *dev)
  {
  	struct chnl_net *priv;
  	u8 loop;
  	priv = netdev_priv(dev);
2809cec5b   David S. Miller   caif: Stop using ...
421
422
423
424
425
  	if (nla_put_u32(skb, IFLA_CAIF_IPV4_CONNID,
  			priv->conn_req.sockaddr.u.dgm.connection_id) ||
  	    nla_put_u32(skb, IFLA_CAIF_IPV6_CONNID,
  			priv->conn_req.sockaddr.u.dgm.connection_id))
  		goto nla_put_failure;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
426
  	loop = priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP;
2809cec5b   David S. Miller   caif: Stop using ...
427
428
  	if (nla_put_u8(skb, IFLA_CAIF_LOOPBACK, loop))
  		goto nla_put_failure;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
429
430
431
432
433
434
435
  	return 0;
  nla_put_failure:
  	return -EMSGSIZE;
  
  }
  
  static void caif_netlink_parms(struct nlattr *data[],
3bffc475f   Silviu-Mihai Popescu   CAIF: fix indenta...
436
  			       struct caif_connect_request *conn_req)
cc36a070b   Sjur Braendeland   net-caif: add CAI...
437
438
  {
  	if (!data) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
439
440
  		pr_warn("no params data found
  ");
cc36a070b   Sjur Braendeland   net-caif: add CAI...
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
  		return;
  	}
  	if (data[IFLA_CAIF_IPV4_CONNID])
  		conn_req->sockaddr.u.dgm.connection_id =
  			nla_get_u32(data[IFLA_CAIF_IPV4_CONNID]);
  	if (data[IFLA_CAIF_IPV6_CONNID])
  		conn_req->sockaddr.u.dgm.connection_id =
  			nla_get_u32(data[IFLA_CAIF_IPV6_CONNID]);
  	if (data[IFLA_CAIF_LOOPBACK]) {
  		if (nla_get_u8(data[IFLA_CAIF_LOOPBACK]))
  			conn_req->protocol = CAIFPROTO_DATAGRAM_LOOP;
  		else
  			conn_req->protocol = CAIFPROTO_DATAGRAM;
  	}
  }
  
  static int ipcaif_newlink(struct net *src_net, struct net_device *dev,
7a3f4a185   Matthias Schiffer   net: add netlink_...
458
459
  			  struct nlattr *tb[], struct nlattr *data[],
  			  struct netlink_ext_ack *extack)
cc36a070b   Sjur Braendeland   net-caif: add CAI...
460
461
462
463
464
465
  {
  	int ret;
  	struct chnl_net *caifdev;
  	ASSERT_RTNL();
  	caifdev = netdev_priv(dev);
  	caif_netlink_parms(data, &caifdev->conn_req);
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
466

cc36a070b   Sjur Braendeland   net-caif: add CAI...
467
468
  	ret = register_netdevice(dev);
  	if (ret)
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
469
470
  		pr_warn("device rtml registration failed
  ");
b2df5a844   David S. Miller   net/caif: Fix dan...
471
472
  	else
  		list_add(&caifdev->list_field, &chnl_net_list);
b3ccfbe40   sjur.brandeland@stericsson.com   caif: Protected i...
473

e3abcc2a8   sjur.brandeland@stericsson.com   caif: make zero a...
474
475
  	/* Use ifindex as connection id, and use loopback channel default. */
  	if (caifdev->conn_req.sockaddr.u.dgm.connection_id == UNDEF_CONNID) {
b3ccfbe40   sjur.brandeland@stericsson.com   caif: Protected i...
476
  		caifdev->conn_req.sockaddr.u.dgm.connection_id = dev->ifindex;
e3abcc2a8   sjur.brandeland@stericsson.com   caif: make zero a...
477
478
  		caifdev->conn_req.protocol = CAIFPROTO_DATAGRAM_LOOP;
  	}
cc36a070b   Sjur Braendeland   net-caif: add CAI...
479
480
481
482
  	return ret;
  }
  
  static int ipcaif_changelink(struct net_device *dev, struct nlattr *tb[],
ad744b223   Matthias Schiffer   net: add netlink_...
483
484
  			     struct nlattr *data[],
  			     struct netlink_ext_ack *extack)
cc36a070b   Sjur Braendeland   net-caif: add CAI...
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
  {
  	struct chnl_net *caifdev;
  	ASSERT_RTNL();
  	caifdev = netdev_priv(dev);
  	caif_netlink_parms(data, &caifdev->conn_req);
  	netdev_state_change(dev);
  	return 0;
  }
  
  static size_t ipcaif_get_size(const struct net_device *dev)
  {
  	return
  		/* IFLA_CAIF_IPV4_CONNID */
  		nla_total_size(4) +
  		/* IFLA_CAIF_IPV6_CONNID */
  		nla_total_size(4) +
  		/* IFLA_CAIF_LOOPBACK */
  		nla_total_size(2) +
  		0;
  }
  
  static const struct nla_policy ipcaif_policy[IFLA_CAIF_MAX + 1] = {
  	[IFLA_CAIF_IPV4_CONNID]	      = { .type = NLA_U32 },
  	[IFLA_CAIF_IPV6_CONNID]	      = { .type = NLA_U32 },
  	[IFLA_CAIF_LOOPBACK]	      = { .type = NLA_U8 }
  };
  
  
  static struct rtnl_link_ops ipcaif_link_ops __read_mostly = {
  	.kind		= "caif",
  	.priv_size	= sizeof(struct chnl_net),
  	.setup		= ipcaif_net_setup,
  	.maxtype	= IFLA_CAIF_MAX,
  	.policy		= ipcaif_policy,
  	.newlink	= ipcaif_newlink,
  	.changelink	= ipcaif_changelink,
  	.get_size	= ipcaif_get_size,
  	.fill_info	= ipcaif_fill_info,
  
  };
  
  static int __init chnl_init_module(void)
  {
  	return rtnl_link_register(&ipcaif_link_ops);
  }
  
  static void __exit chnl_exit_module(void)
  {
  	struct chnl_net *dev = NULL;
  	struct list_head *list_node;
  	struct list_head *_tmp;
  	rtnl_link_unregister(&ipcaif_link_ops);
  	rtnl_lock();
  	list_for_each_safe(list_node, _tmp, &chnl_net_list) {
  		dev = list_entry(list_node, struct chnl_net, list_field);
  		list_del(list_node);
  		delete_device(dev);
  	}
  	rtnl_unlock();
  }
  
  module_init(chnl_init_module);
  module_exit(chnl_exit_module);