Blame view

net/caif/chnl_net.c 12.9 KB
cc36a070b   Sjur Braendeland   net-caif: add CAI...
1
2
3
4
5
6
  /*
   * Copyright (C) ST-Ericsson AB 2010
   * Authors:	Sjur Brendeland/sjur.brandeland@stericsson.com
   *		Daniel Martensson / Daniel.Martensson@stericsson.com
   * License terms: GNU General Public License (GPL) version 2
   */
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
  #include <linux/fs.h>
a6b7a4078   Alexey Dobriyan   net: remove inter...
9
  #include <linux/hardirq.h>
cc36a070b   Sjur Braendeland   net-caif: add CAI...
10
11
12
13
14
15
16
17
18
19
20
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/netdevice.h>
  #include <linux/if_ether.h>
  #include <linux/moduleparam.h>
  #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...
21
22
  #include <net/caif/cfpkt.h>
  #include <net/caif/caif_dev.h>
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
23
  /* GPRS PDP connection has MTU to 1500 */
2aa40aef9   Sjur Braendeland   caif: Use link la...
24
  #define GPRS_PDP_MTU 1500
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
25
26
  /* 5 sec. connect timeout */
  #define CONNECT_TIMEOUT (5 * HZ)
cc36a070b   Sjur Braendeland   net-caif: add CAI...
27
  #define CAIF_NET_DEFAULT_QUEUE_LEN 500
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
41
42
43
44
45
46
47
48
  struct chnl_net {
  	struct cflayer chnl;
  	struct net_device_stats stats;
  	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...
49
  	enum caif_states state;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
50
51
52
53
54
55
56
57
58
59
  };
  
  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...
60
  			return;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
61
62
  		}
  	}
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
63
  	WARN_ON(1);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
64
65
66
67
68
  }
  
  static int chnl_recv_cb(struct cflayer *layr, struct cfpkt *pkt)
  {
  	struct sk_buff *skb;
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
69
  	struct chnl_net *priv  = container_of(layr, struct chnl_net, chnl);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
70
71
  	int pktlen;
  	int err = 0;
d7b92affb   Kumar Sanghvi   CAIF: Fix IPv6 su...
72
73
  	const u8 *ip_version;
  	u8 buf;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
74
75
76
77
78
  
  	priv = container_of(layr, struct chnl_net, chnl);
  
  	if (!priv)
  		return -EINVAL;
3f874adc4   sjur.brandeland@stericsson.com   caif: remove unes...
79
  	skb = (struct sk_buff *) cfpkt_tonative(pkt);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
80
  	/* Get length of CAIF packet. */
3f874adc4   sjur.brandeland@stericsson.com   caif: remove unes...
81
  	pktlen = skb->len;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
82

cc36a070b   Sjur Braendeland   net-caif: add CAI...
83
84
85
86
  	/* Pass some minimum information and
  	 * send the packet to the net stack.
  	 */
  	skb->dev = priv->netdev;
d7b92affb   Kumar Sanghvi   CAIF: Fix IPv6 su...
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  
  	/* check the version of IP */
  	ip_version = skb_header_pointer(skb, 0, 1, &buf);
  	if (!ip_version)
  		return -EINVAL;
  	switch (*ip_version >> 4) {
  	case 4:
  		skb->protocol = htons(ETH_P_IP);
  		break;
  	case 6:
  		skb->protocol = htons(ETH_P_IPV6);
  		break;
  	default:
  		return -EINVAL;
  	}
cc36a070b   Sjur Braendeland   net-caif: add CAI...
102
103
104
105
106
107
  
  	/* 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...
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  	if (in_interrupt())
  		netif_rx(skb);
  	else
  		netif_rx_ni(skb);
  
  	/* Update statistics. */
  	priv->netdev->stats.rx_packets++;
  	priv->netdev->stats.rx_bytes += pktlen;
  
  	return err;
  }
  
  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...
133
134
  
  	rtnl_lock();
cc36a070b   Sjur Braendeland   net-caif: add CAI...
135
136
  	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...
137
138
  		if (dev->state == CAIF_SHUTDOWN)
  			dev_close(dev->netdev);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
139
  	}
41be5a4a3   sjur.brandeland@stericsson.com   caif: Fix race wh...
140
  	rtnl_unlock();
cc36a070b   Sjur Braendeland   net-caif: add CAI...
141
142
  }
  static DECLARE_WORK(close_worker, close_work);
b3ccfbe40   sjur.brandeland@stericsson.com   caif: Protected i...
143
144
145
146
147
148
149
150
151
152
153
  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...
154
155
156
  static void chnl_flowctrl_cb(struct cflayer *layr, enum caif_ctrlcmd flow,
  				int phyid)
  {
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
157
  	struct chnl_net *priv = container_of(layr, struct chnl_net, chnl);
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
158
159
  	pr_debug("NET flowctrl func called flow: %s
  ",
cc36a070b   Sjur Braendeland   net-caif: add CAI...
160
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 ?
  		 "REMOTE_SHUTDOWN" : "UKNOWN CTRL COMMAND");
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
167

cc36a070b   Sjur Braendeland   net-caif: add CAI...
168
169
170
  
  	switch (flow) {
  	case CAIF_CTRLCMD_FLOW_OFF_IND:
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
171
172
173
  		priv->flowenabled = false;
  		netif_stop_queue(priv->netdev);
  		break;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
174
  	case CAIF_CTRLCMD_DEINIT_RSP:
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
175
176
  		priv->state = CAIF_DISCONNECTED;
  		break;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
177
  	case CAIF_CTRLCMD_INIT_FAIL_RSP:
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
178
179
180
  		priv->state = CAIF_DISCONNECTED;
  		wake_up_interruptible(&priv->netmgmt_wq);
  		break;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
181
  	case CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND:
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
182
  		priv->state = CAIF_SHUTDOWN;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
183
  		netif_tx_disable(priv->netdev);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
184
185
186
  		schedule_work(&close_worker);
  		break;
  	case CAIF_CTRLCMD_FLOW_ON_IND:
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
187
188
189
  		priv->flowenabled = true;
  		netif_wake_queue(priv->netdev);
  		break;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
190
  	case CAIF_CTRLCMD_INIT_RSP:
b3ccfbe40   sjur.brandeland@stericsson.com   caif: Protected i...
191
  		caif_client_register_refcnt(&priv->chnl, chnl_hold, chnl_put);
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
192
  		priv->state = CAIF_CONNECTED;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
  		priv->flowenabled = true;
  		netif_wake_queue(priv->netdev);
  		wake_up_interruptible(&priv->netmgmt_wq);
  		break;
  	default:
  		break;
  	}
  }
  
  static int chnl_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
  {
  	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
212
213
  		pr_warn("Size of skb exceeded MTU
  ");
cc36a070b   Sjur Braendeland   net-caif: add CAI...
214
215
216
217
  		return -ENOSPC;
  	}
  
  	if (!priv->flowenabled) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
218
219
  		pr_debug("dropping packets flow off
  ");
cc36a070b   Sjur Braendeland   net-caif: add CAI...
220
221
222
223
224
225
226
227
228
229
  		return NETDEV_TX_BUSY;
  	}
  
  	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...
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
  	/* Send the packet down the stack. */
  	result = priv->chnl.dn->transmit(priv->chnl.dn, pkt);
  	if (result) {
  		if (result == -EAGAIN)
  			result = NETDEV_TX_BUSY;
  		return result;
  	}
  
  	/* 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...
249
250
  	int llifindex, headroom, tailroom, mtu;
  	struct net_device *lldev;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
251
  	ASSERT_RTNL();
cc36a070b   Sjur Braendeland   net-caif: add CAI...
252
  	priv = netdev_priv(dev);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
253
  	if (!priv) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
254
255
  		pr_debug("chnl_net_open: no priv
  ");
cc36a070b   Sjur Braendeland   net-caif: add CAI...
256
257
  		return -ENODEV;
  	}
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
258
259
260
  
  	if (priv->state != CAIF_CONNECTING) {
  		priv->state = CAIF_CONNECTING;
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
261
262
263
  		result = caif_connect_client(dev_net(dev), &priv->conn_req,
  						&priv->chnl, &llifindex,
  						&headroom, &tailroom);
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
264
  		if (result != 0) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
265
266
267
268
269
  				pr_debug("err: "
  					 "Unable to register and open device,"
  					 " Err:%d
  ",
  					 result);
2aa40aef9   Sjur Braendeland   caif: Use link la...
270
271
272
273
274
275
  				goto error;
  		}
  
  		lldev = dev_get_by_index(dev_net(dev), llifindex);
  
  		if (lldev == NULL) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
276
277
  			pr_debug("no interface?
  ");
2aa40aef9   Sjur Braendeland   caif: Use link la...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
  			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);
  		dev_put(lldev);
  
  		if (mtu < 100) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
299
300
  			pr_warn("CAIF Interface MTU too small (%d)
  ", mtu);
2aa40aef9   Sjur Braendeland   caif: Use link la...
301
302
  			result = -ENODEV;
  			goto error;
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
303
  		}
cc36a070b   Sjur Braendeland   net-caif: add CAI...
304
  	}
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
305

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

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

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

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

cc36a070b   Sjur Braendeland   net-caif: add CAI...
352
353
  	ASSERT_RTNL();
  	priv = netdev_priv(dev);
8391c4aab   Sjur Braendeland   caif: Bugfixes in...
354
  	priv->state = CAIF_DISCONNECTED;
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
355
  	caif_disconnect_client(dev_net(dev), &priv->chnl);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
  	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...
383
384
385
386
387
388
  static void chnl_net_destructor(struct net_device *dev)
  {
  	struct chnl_net *priv = netdev_priv(dev);
  	caif_free_client(&priv->chnl);
  	free_netdev(dev);
  }
cc36a070b   Sjur Braendeland   net-caif: add CAI...
389
390
391
392
  static void ipcaif_net_setup(struct net_device *dev)
  {
  	struct chnl_net *priv;
  	dev->netdev_ops = &netdev_ops;
b3ccfbe40   sjur.brandeland@stericsson.com   caif: Protected i...
393
  	dev->destructor = chnl_net_destructor;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
394
395
  	dev->flags |= IFF_NOARP;
  	dev->flags |= IFF_POINTOPOINT;
2aa40aef9   Sjur Braendeland   caif: Use link la...
396
  	dev->mtu = GPRS_PDP_MTU;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
397
398
399
400
401
402
403
404
405
406
  	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 */
b3ccfbe40   sjur.brandeland@stericsson.com   caif: Protected i...
407
  	priv->conn_req.sockaddr.u.dgm.connection_id = 0;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
408
  	priv->flowenabled = false;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
409
  	init_waitqueue_head(&priv->netmgmt_wq);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
  }
  
  
  static int ipcaif_fill_info(struct sk_buff *skb, const struct net_device *dev)
  {
  	struct chnl_net *priv;
  	u8 loop;
  	priv = netdev_priv(dev);
  	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);
  	loop = priv->conn_req.protocol == CAIFPROTO_DATAGRAM_LOOP;
  	NLA_PUT_U8(skb, IFLA_CAIF_LOOPBACK, loop);
  
  
  	return 0;
  nla_put_failure:
  	return -EMSGSIZE;
  
  }
  
  static void caif_netlink_parms(struct nlattr *data[],
  				struct caif_connect_request *conn_req)
  {
  	if (!data) {
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
436
437
  		pr_warn("no params data found
  ");
cc36a070b   Sjur Braendeland   net-caif: add CAI...
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
  		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,
  			  struct nlattr *tb[], struct nlattr *data[])
  {
  	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...
462
  	dev_net_set(caifdev->netdev, src_net);
cc36a070b   Sjur Braendeland   net-caif: add CAI...
463
464
  	ret = register_netdevice(dev);
  	if (ret)
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
465
466
  		pr_warn("device rtml registration failed
  ");
b2df5a844   David S. Miller   net/caif: Fix dan...
467
468
  	else
  		list_add(&caifdev->list_field, &chnl_net_list);
b3ccfbe40   sjur.brandeland@stericsson.com   caif: Protected i...
469
470
471
472
  
  	/* Take ifindex as connection-id if null */
  	if (caifdev->conn_req.sockaddr.u.dgm.connection_id == 0)
  		caifdev->conn_req.sockaddr.u.dgm.connection_id = dev->ifindex;
cc36a070b   Sjur Braendeland   net-caif: add CAI...
473
474
475
476
477
478
479
480
481
482
483
484
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
  	return ret;
  }
  
  static int ipcaif_changelink(struct net_device *dev, struct nlattr *tb[],
  				struct nlattr *data[])
  {
  	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);