Blame view

net/caif/caif_dev.c 9.42 KB
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
1
2
3
4
5
6
7
8
9
10
  /*
   * CAIF Interface registration.
   * Copyright (C) ST-Ericsson AB 2010
   * Author:	Sjur Brendeland/sjur.brandeland@stericsson.com
   * License terms: GNU General Public License (GPL) version 2
   *
   * Borrowed heavily from file: pn_dev.c. Thanks to
   *  Remi Denis-Courmont <remi.denis-courmont@nokia.com>
   *  and Sakari Ailus <sakari.ailus@nokia.com>
   */
b31fa5bad   Joe Perches   net/caif: Use pr_fmt
11
  #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
12
13
14
15
  #include <linux/kernel.h>
  #include <linux/if_arp.h>
  #include <linux/net.h>
  #include <linux/netdevice.h>
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
16
  #include <linux/mutex.h>
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
17
18
19
20
  #include <net/netns/generic.h>
  #include <net/net_namespace.h>
  #include <net/pkt_sched.h>
  #include <net/caif/caif_device.h>
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
21
22
23
24
25
  #include <net/caif/caif_layer.h>
  #include <net/caif/cfpkt.h>
  #include <net/caif/cfcnfg.h>
  
  MODULE_LICENSE("GPL");
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
26
27
28
29
30
  
  /* Used for local tracking of the CAIF net devices */
  struct caif_device_entry {
  	struct cflayer layer;
  	struct list_head list;
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
31
  	struct net_device *netdev;
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
32
  	int __percpu *pcpu_refcnt;
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
33
34
35
36
37
  };
  
  struct caif_device_entry_list {
  	struct list_head list;
  	/* Protects simulanous deletes in list */
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
38
  	struct mutex lock;
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
39
40
41
  };
  
  struct caif_net {
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
42
  	struct cfcnfg *cfg;
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
43
44
45
46
  	struct caif_device_entry_list caifdevs;
  };
  
  static int caif_net_id;
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
47
48
49
50
51
52
53
54
55
56
  
  struct cfcnfg *get_cfcnfg(struct net *net)
  {
  	struct caif_net *caifn;
  	BUG_ON(!net);
  	caifn = net_generic(net, caif_net_id);
  	BUG_ON(!caifn);
  	return caifn->cfg;
  }
  EXPORT_SYMBOL(get_cfcnfg);
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
57
58
59
60
61
62
63
64
65
  
  static struct caif_device_entry_list *caif_device_list(struct net *net)
  {
  	struct caif_net *caifn;
  	BUG_ON(!net);
  	caifn = net_generic(net, caif_net_id);
  	BUG_ON(!caifn);
  	return &caifn->caifdevs;
  }
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
  static void caifd_put(struct caif_device_entry *e)
  {
  	irqsafe_cpu_dec(*e->pcpu_refcnt);
  }
  
  static void caifd_hold(struct caif_device_entry *e)
  {
  	irqsafe_cpu_inc(*e->pcpu_refcnt);
  }
  
  static int caifd_refcnt_read(struct caif_device_entry *e)
  {
  	int i, refcnt = 0;
  	for_each_possible_cpu(i)
  		refcnt += *per_cpu_ptr(e->pcpu_refcnt, i);
  	return refcnt;
  }
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
83
84
85
86
87
  /* Allocate new CAIF device. */
  static struct caif_device_entry *caif_device_alloc(struct net_device *dev)
  {
  	struct caif_device_entry_list *caifdevs;
  	struct caif_device_entry *caifd;
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
88

c72dfae2f   Sjur Braendeland   net-caif: add CAI...
89
90
  	caifdevs = caif_device_list(dev_net(dev));
  	BUG_ON(!caifdevs);
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
91

4fb66b821   Eric Dumazet   caif: fix a poten...
92
  	caifd = kzalloc(sizeof(*caifd), GFP_KERNEL);
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
93
94
  	if (!caifd)
  		return NULL;
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
95
  	caifd->pcpu_refcnt = alloc_percpu(int);
4fb66b821   Eric Dumazet   caif: fix a poten...
96
97
98
99
  	if (!caifd->pcpu_refcnt) {
  		kfree(caifd);
  		return NULL;
  	}
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
100
  	caifd->netdev = dev;
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
101
  	dev_hold(dev);
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
102
103
104
105
106
107
108
109
110
  	return caifd;
  }
  
  static struct caif_device_entry *caif_get(struct net_device *dev)
  {
  	struct caif_device_entry_list *caifdevs =
  	    caif_device_list(dev_net(dev));
  	struct caif_device_entry *caifd;
  	BUG_ON(!caifdevs);
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
111
  	list_for_each_entry_rcu(caifd, &caifdevs->list, list) {
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
112
113
114
115
116
  		if (caifd->netdev == dev)
  			return caifd;
  	}
  	return NULL;
  }
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
117
118
  static int transmit(struct cflayer *layer, struct cfpkt *pkt)
  {
c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
119
  	int err;
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
120
121
  	struct caif_device_entry *caifd =
  	    container_of(layer, struct caif_device_entry, layer);
4dd820c08   Sjur Brændeland   caif: Don't resen...
122
  	struct sk_buff *skb;
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
123
124
  	skb = cfpkt_tonative(pkt);
  	skb->dev = caifd->netdev;
4dd820c08   Sjur Brændeland   caif: Don't resen...
125

c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
126
127
128
  	err = dev_queue_xmit(skb);
  	if (err > 0)
  		err = -EIO;
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
129

c85c2951d   sjur.brandeland@stericsson.com   caif: Handle dev_...
130
  	return err;
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
131
  }
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
132
  /*
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
133
   * Stuff received packets into the CAIF stack.
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
134
135
136
137
138
   * On error, returns non-zero and releases the skb.
   */
  static int receive(struct sk_buff *skb, struct net_device *dev,
  		   struct packet_type *pkttype, struct net_device *orig_dev)
  {
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
139
140
  	struct cfpkt *pkt;
  	struct caif_device_entry *caifd;
69c867c90   sjur.brandeland@stericsson.com   caif: Plug memory...
141
  	int err;
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
142

c72dfae2f   Sjur Braendeland   net-caif: add CAI...
143
  	pkt = cfpkt_fromnative(CAIF_DIR_IN, skb);
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
144
145
  
  	rcu_read_lock();
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
146
  	caifd = caif_get(dev);
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
147

bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
148
149
150
151
  	if (!caifd || !caifd->layer.up || !caifd->layer.up->receive ||
  			!netif_oper_up(caifd->netdev)) {
  		rcu_read_unlock();
  		kfree_skb(skb);
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
152
  		return NET_RX_DROP;
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
153
154
155
156
157
  	}
  
  	/* Hold reference to netdevice while using CAIF stack */
  	caifd_hold(caifd);
  	rcu_read_unlock();
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
158

69c867c90   sjur.brandeland@stericsson.com   caif: Plug memory...
159
160
161
162
163
  	err = caifd->layer.up->receive(caifd->layer.up, pkt);
  
  	/* For -EILSEQ the packet is not freed so so it now */
  	if (err == -EILSEQ)
  		cfpkt_destroy(pkt);
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
164
165
166
  
  	/* Release reference to stack upwards */
  	caifd_put(caifd);
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
167
168
169
170
171
172
173
174
175
176
  	return 0;
  }
  
  static struct packet_type caif_packet_type __read_mostly = {
  	.type = cpu_to_be16(ETH_P_CAIF),
  	.func = receive,
  };
  
  static void dev_flowctrl(struct net_device *dev, int on)
  {
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
177
178
179
180
181
182
183
  	struct caif_device_entry *caifd;
  
  	rcu_read_lock();
  
  	caifd = caif_get(dev);
  	if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd) {
  		rcu_read_unlock();
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
184
  		return;
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
185
186
187
188
  	}
  
  	caifd_hold(caifd);
  	rcu_read_unlock();
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
189
190
191
192
193
194
  
  	caifd->layer.up->ctrlcmd(caifd->layer.up,
  				 on ?
  				 _CAIF_CTRLCMD_PHYIF_FLOW_ON_IND :
  				 _CAIF_CTRLCMD_PHYIF_FLOW_OFF_IND,
  				 caifd->layer.id);
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
195
  	caifd_put(caifd);
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
196
197
198
199
200
201
202
203
204
205
  }
  
  /* notify Caif of device events */
  static int caif_device_notify(struct notifier_block *me, unsigned long what,
  			      void *arg)
  {
  	struct net_device *dev = arg;
  	struct caif_device_entry *caifd = NULL;
  	struct caif_dev_common *caifdev;
  	enum cfcnfg_phy_preference pref;
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
206
  	enum cfcnfg_phy_type phy_type;
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
207
  	struct cfcnfg *cfg;
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
208
209
  	struct caif_device_entry_list *caifdevs =
  	    caif_device_list(dev_net(dev));
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
210
211
212
  
  	if (dev->type != ARPHRD_CAIF)
  		return 0;
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
213
214
215
  	cfg = get_cfcnfg(dev_net(dev));
  	if (cfg == NULL)
  		return 0;
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
216
217
  	switch (what) {
  	case NETDEV_REGISTER:
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
218
  		caifd = caif_device_alloc(dev);
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
219
220
  		if (!caifd)
  			return 0;
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
221
222
  		caifdev = netdev_priv(dev);
  		caifdev->flowctrl = dev_flowctrl;
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
223

c72dfae2f   Sjur Braendeland   net-caif: add CAI...
224
  		caifd->layer.transmit = transmit;
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
225
226
227
228
229
230
231
232
  
  		if (caifdev->use_frag)
  			phy_type = CFPHYTYPE_FRAG;
  		else
  			phy_type = CFPHYTYPE_CAIF;
  
  		switch (caifdev->link_select) {
  		case CAIF_LINK_HIGH_BANDW:
2c485209a   Sjur Braendeland   Bugfix: Link sele...
233
  			pref = CFPHYPREF_HIGH_BW;
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
234
235
  			break;
  		case CAIF_LINK_LOW_LATENCY:
2c485209a   Sjur Braendeland   Bugfix: Link sele...
236
  			pref = CFPHYPREF_LOW_LAT;
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
237
238
239
240
241
  			break;
  		default:
  			pref = CFPHYPREF_HIGH_BW;
  			break;
  		}
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
242
243
244
245
246
247
  		strncpy(caifd->layer.name, dev->name,
  			sizeof(caifd->layer.name) - 1);
  		caifd->layer.name[sizeof(caifd->layer.name) - 1] = 0;
  
  		mutex_lock(&caifdevs->lock);
  		list_add_rcu(&caifd->list, &caifdevs->list);
73d6ac633   Stephen Hemminger   caif: code cleanup
248
  		cfcnfg_add_phy_layer(cfg,
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
249
250
251
  				     phy_type,
  				     dev,
  				     &caifd->layer,
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
252
253
254
  				     pref,
  				     caifdev->use_fcs,
  				     caifdev->use_stx);
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
255
  		mutex_unlock(&caifdevs->lock);
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
256
  		break;
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
257
258
  	case NETDEV_UP:
  		rcu_read_lock();
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
259
  		caifd = caif_get(dev);
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
260
261
  		if (caifd == NULL) {
  			rcu_read_unlock();
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
262
  			break;
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
263
  		}
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
264

bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
265
266
  		cfcnfg_set_phy_state(cfg, &caifd->layer, true);
  		rcu_read_unlock();
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
267

c72dfae2f   Sjur Braendeland   net-caif: add CAI...
268
269
270
  		break;
  
  	case NETDEV_DOWN:
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
271
  		rcu_read_lock();
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
272
  		caifd = caif_get(dev);
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
273
274
275
276
277
278
279
280
281
282
283
284
285
  		if (!caifd || !caifd->layer.up || !caifd->layer.up->ctrlcmd) {
  			rcu_read_unlock();
  			return -EINVAL;
  		}
  
  		cfcnfg_set_phy_state(cfg, &caifd->layer, false);
  		caifd_hold(caifd);
  		rcu_read_unlock();
  
  		caifd->layer.up->ctrlcmd(caifd->layer.up,
  					 _CAIF_CTRLCMD_PHYIF_DOWN_IND,
  					 caifd->layer.id);
  		caifd_put(caifd);
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
286
287
288
  		break;
  
  	case NETDEV_UNREGISTER:
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
289
  		mutex_lock(&caifdevs->lock);
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
290
  		caifd = caif_get(dev);
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
291
292
  		if (caifd == NULL) {
  			mutex_unlock(&caifdevs->lock);
f2527ec43   André Carvalho de Matos   caif: Bugfix for ...
293
  			break;
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
  		}
  		list_del_rcu(&caifd->list);
  
  		/*
  		 * NETDEV_UNREGISTER is called repeatedly until all reference
  		 * counts for the net-device are released. If references to
  		 * caifd is taken, simply ignore NETDEV_UNREGISTER and wait for
  		 * the next call to NETDEV_UNREGISTER.
  		 *
  		 * If any packets are in flight down the CAIF Stack,
  		 * cfcnfg_del_phy_layer will return nonzero.
  		 * If no packets are in flight, the CAIF Stack associated
  		 * with the net-device un-registering is freed.
  		 */
  
  		if (caifd_refcnt_read(caifd) != 0 ||
  			cfcnfg_del_phy_layer(cfg, &caifd->layer) != 0) {
  
  			pr_info("Wait for device inuse
  ");
  			/* Enrole device if CAIF Stack is still in use */
  			list_add_rcu(&caifd->list, &caifdevs->list);
  			mutex_unlock(&caifdevs->lock);
  			break;
  		}
  
  		synchronize_rcu();
  		dev_put(caifd->netdev);
  		free_percpu(caifd->pcpu_refcnt);
  		kfree(caifd);
  
  		mutex_unlock(&caifdevs->lock);
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
326
327
328
329
330
331
332
333
334
  		break;
  	}
  	return 0;
  }
  
  static struct notifier_block caif_device_notifier = {
  	.notifier_call = caif_device_notify,
  	.priority = 0,
  };
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
335
336
337
338
  /* Per-namespace Caif devices handling */
  static int caif_init_net(struct net *net)
  {
  	struct caif_net *caifn = net_generic(net, caif_net_id);
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
339
  	BUG_ON(!caifn);
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
340
  	INIT_LIST_HEAD(&caifn->caifdevs.list);
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
341
  	mutex_init(&caifn->caifdevs.lock);
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
342
343
344
345
346
347
348
  
  	caifn->cfg = cfcnfg_create();
  	if (!caifn->cfg) {
  		pr_warn("can't create cfcnfg
  ");
  		return -ENOMEM;
  	}
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
349
350
351
352
353
  	return 0;
  }
  
  static void caif_exit_net(struct net *net)
  {
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
354
355
356
  	struct caif_device_entry *caifd, *tmp;
  	struct caif_device_entry_list *caifdevs =
  	    caif_device_list(net);
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
357
  	struct cfcnfg *cfg;
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
358

c72dfae2f   Sjur Braendeland   net-caif: add CAI...
359
  	rtnl_lock();
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
360
  	mutex_lock(&caifdevs->lock);
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
361
362
363
364
365
  	cfg = get_cfcnfg(net);
  	if (cfg == NULL) {
  		mutex_unlock(&caifdevs->lock);
  		return;
  	}
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
  	list_for_each_entry_safe(caifd, tmp, &caifdevs->list, list) {
  		int i = 0;
  		list_del_rcu(&caifd->list);
  		cfcnfg_set_phy_state(cfg, &caifd->layer, false);
  
  		while (i < 10 &&
  			(caifd_refcnt_read(caifd) != 0 ||
  			cfcnfg_del_phy_layer(cfg, &caifd->layer) != 0)) {
  
  			pr_info("Wait for device inuse
  ");
  			msleep(250);
  			i++;
  		}
  		synchronize_rcu();
  		dev_put(caifd->netdev);
  		free_percpu(caifd->pcpu_refcnt);
  		kfree(caifd);
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
384
  	}
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
385
  	cfcnfg_remove(cfg);
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
386
387
  
  	mutex_unlock(&caifdevs->lock);
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
388
389
390
391
392
393
394
395
396
397
398
399
400
401
  	rtnl_unlock();
  }
  
  static struct pernet_operations caif_net_ops = {
  	.init = caif_init_net,
  	.exit = caif_exit_net,
  	.id   = &caif_net_id,
  	.size = sizeof(struct caif_net),
  };
  
  /* Initialize Caif devices list */
  static int __init caif_device_init(void)
  {
  	int result;
bd30ce4bc   sjur.brandeland@stericsson.com   caif: Use RCU ins...
402

c72dfae2f   Sjur Braendeland   net-caif: add CAI...
403
  	result = register_pernet_device(&caif_net_ops);
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
404
  	if (result)
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
405
  		return result;
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
406

c72dfae2f   Sjur Braendeland   net-caif: add CAI...
407
  	register_netdevice_notifier(&caif_device_notifier);
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
408
  	dev_add_pack(&caif_packet_type);
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
409
410
  
  	return result;
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
411
412
413
414
  }
  
  static void __exit caif_device_exit(void)
  {
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
415
416
  	unregister_pernet_device(&caif_net_ops);
  	unregister_netdevice_notifier(&caif_device_notifier);
bee925db9   sjur.brandeland@stericsson.com   caif: prepare sup...
417
  	dev_remove_pack(&caif_packet_type);
c72dfae2f   Sjur Braendeland   net-caif: add CAI...
418
419
420
421
  }
  
  module_init(caif_device_init);
  module_exit(caif_device_exit);