Blame view

net/phonet/af_phonet.c 12.7 KB
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  /*
   * File: af_phonet.c
   *
   * Phonet protocols family
   *
   * Copyright (C) 2008 Nokia Corporation.
   *
   * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
   * Original author: Sakari Ailus <sakari.ailus@nokia.com>
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * version 2 as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   * 02110-1301 USA
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
28
  #include <linux/slab.h>
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
29
30
31
32
33
34
  #include <asm/unaligned.h>
  #include <net/sock.h>
  
  #include <linux/if_phonet.h>
  #include <linux/phonet.h>
  #include <net/phonet/phonet.h>
f8ff60283   Remi Denis-Courmont   Phonet: network d...
35
  #include <net/phonet/pn_dev.h>
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
36

566521d63   Alexey Dobriyan   phonet: fix compi...
37
38
  /* Transport protocol registration */
  static struct phonet_protocol *proto_tab[PHONET_NPROTO] __read_mostly;
566521d63   Alexey Dobriyan   phonet: fix compi...
39

facb4edc1   Dan Carpenter   phonet: some sign...
40
  static struct phonet_protocol *phonet_proto_get(unsigned int protocol)
566521d63   Alexey Dobriyan   phonet: fix compi...
41
42
43
44
45
  {
  	struct phonet_protocol *pp;
  
  	if (protocol >= PHONET_NPROTO)
  		return NULL;
7ed0132f2   Rémi Denis-Courmont   Phonet: put proto...
46
  	rcu_read_lock();
b2a5decdd   Rémi Denis-Courmont   Phonet: missing r...
47
  	pp = rcu_dereference(proto_tab[protocol]);
566521d63   Alexey Dobriyan   phonet: fix compi...
48
49
  	if (pp && !try_module_get(pp->prot->owner))
  		pp = NULL;
7ed0132f2   Rémi Denis-Courmont   Phonet: put proto...
50
  	rcu_read_unlock();
566521d63   Alexey Dobriyan   phonet: fix compi...
51
52
53
54
55
56
57
58
  
  	return pp;
  }
  
  static inline void phonet_proto_put(struct phonet_protocol *pp)
  {
  	module_put(pp->prot->owner);
  }
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
59
60
  
  /* protocol family functions */
3f378b684   Eric Paris   net: pass kern to...
61
62
  static int pn_socket_create(struct net *net, struct socket *sock, int protocol,
  			    int kern)
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
63
  {
ba113a94b   Remi Denis-Courmont   Phonet: common so...
64
65
  	struct sock *sk;
  	struct pn_sock *pn;
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
66
67
  	struct phonet_protocol *pnp;
  	int err;
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
68
69
70
71
72
73
74
75
76
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  
  	if (protocol == 0) {
  		/* Default protocol selection */
  		switch (sock->type) {
  		case SOCK_DGRAM:
  			protocol = PN_PROTO_PHONET;
  			break;
9641458d3   Rémi Denis-Courmont   Phonet: Pipe End ...
77
78
79
  		case SOCK_SEQPACKET:
  			protocol = PN_PROTO_PIPE;
  			break;
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
80
81
82
83
84
85
  		default:
  			return -EPROTONOSUPPORT;
  		}
  	}
  
  	pnp = phonet_proto_get(protocol);
25532824f   Rémi Denis-Courmont   Phonet: modules a...
86
87
88
  	if (pnp == NULL &&
  	    request_module("net-pf-%d-proto-%d", PF_PHONET, protocol) == 0)
  		pnp = phonet_proto_get(protocol);
95a5afca4   Johannes Berg   net: Remove CONFI...
89

4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
90
91
92
93
94
95
  	if (pnp == NULL)
  		return -EPROTONOSUPPORT;
  	if (sock->type != pnp->sock_type) {
  		err = -EPROTONOSUPPORT;
  		goto out;
  	}
ba113a94b   Remi Denis-Courmont   Phonet: common so...
96
97
98
99
100
101
102
103
104
105
106
107
108
  	sk = sk_alloc(net, PF_PHONET, GFP_KERNEL, pnp->prot);
  	if (sk == NULL) {
  		err = -ENOMEM;
  		goto out;
  	}
  
  	sock_init_data(sock, sk);
  	sock->state = SS_UNCONNECTED;
  	sock->ops = pnp->ops;
  	sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
  	sk->sk_protocol = protocol;
  	pn = pn_sk(sk);
  	pn->sobject = 0;
a8059512b   Rémi Denis-Courmont   Phonet: implement...
109
  	pn->dobject = 0;
ba113a94b   Remi Denis-Courmont   Phonet: common so...
110
111
112
  	pn->resource = 0;
  	sk->sk_prot->init(sk);
  	err = 0;
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
113
114
115
116
117
  
  out:
  	phonet_proto_put(pnp);
  	return err;
  }
ec1b4cf74   Stephen Hemminger   net: mark net_pro...
118
  static const struct net_proto_family phonet_proto_family = {
25532824f   Rémi Denis-Courmont   Phonet: modules a...
119
  	.family = PF_PHONET,
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
120
121
122
  	.create = pn_socket_create,
  	.owner = THIS_MODULE,
  };
5f77076d7   Remi Denis-Courmont   Phonet: provide M...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  /* Phonet device header operations */
  static int pn_header_create(struct sk_buff *skb, struct net_device *dev,
  				unsigned short type, const void *daddr,
  				const void *saddr, unsigned len)
  {
  	u8 *media = skb_push(skb, 1);
  
  	if (type != ETH_P_PHONET)
  		return -1;
  
  	if (!saddr)
  		saddr = dev->dev_addr;
  	*media = *(const u8 *)saddr;
  	return 1;
  }
  
  static int pn_header_parse(const struct sk_buff *skb, unsigned char *haddr)
  {
  	const u8 *media = skb_mac_header(skb);
  	*haddr = *media;
  	return 1;
  }
  
  struct header_ops phonet_header_ops = {
  	.create = pn_header_create,
  	.parse = pn_header_parse,
  };
  EXPORT_SYMBOL(phonet_header_ops);
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
151
152
153
154
  /*
   * Prepends an ISI header and sends a datagram.
   */
  static int pn_send(struct sk_buff *skb, struct net_device *dev,
be0c52bfe   Remi Denis-Courmont   Phonet: emit erro...
155
  			u16 dst, u16 src, u8 res, u8 irq)
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
156
157
158
  {
  	struct phonethdr *ph;
  	int err;
ebfe92ca6   Rémi Denis-Courmont   Phonet: refuse to...
159
160
  	if (skb->len + 2 > 0xffff /* Phonet length field limit */ ||
  	    skb->len + sizeof(struct phonethdr) > dev->mtu) {
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
161
162
163
  		err = -EMSGSIZE;
  		goto drop;
  	}
18a1166de   Rémi Denis-Courmont   Phonet: error on ...
164
165
166
167
168
  	/* Broadcast sending is not implemented */
  	if (pn_addr(dst) == PNADDR_BROADCAST) {
  		err = -EOPNOTSUPP;
  		goto drop;
  	}
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
  	skb_reset_transport_header(skb);
  	WARN_ON(skb_headroom(skb) & 1); /* HW assumes word alignment */
  	skb_push(skb, sizeof(struct phonethdr));
  	skb_reset_network_header(skb);
  	ph = pn_hdr(skb);
  	ph->pn_rdev = pn_dev(dst);
  	ph->pn_sdev = pn_dev(src);
  	ph->pn_res = res;
  	ph->pn_length = __cpu_to_be16(skb->len + 2 - sizeof(*ph));
  	ph->pn_robj = pn_obj(dst);
  	ph->pn_sobj = pn_obj(src);
  
  	skb->protocol = htons(ETH_P_PHONET);
  	skb->priority = 0;
  	skb->dev = dev;
aa6c45f32   Rémi Denis-Courmont   Phonet: route out...
184
  	if (skb->pkt_type == PACKET_LOOPBACK) {
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
185
  		skb_reset_mac_header(skb);
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
186
  		skb_orphan(skb);
b765e84f9   Rémi Denis-Courmont   Phonet: return an...
187
  		err = (irq ? netif_rx(skb) : netif_rx_ni(skb)) ? -ENOBUFS : 0;
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
188
189
190
191
192
193
194
195
  	} else {
  		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
  					NULL, NULL, skb->len);
  		if (err < 0) {
  			err = -EHOSTUNREACH;
  			goto drop;
  		}
  		err = dev_queue_xmit(skb);
b765e84f9   Rémi Denis-Courmont   Phonet: return an...
196
197
  		if (unlikely(err > 0))
  			err = net_xmit_errno(err);
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
198
199
200
201
202
203
204
  	}
  
  	return err;
  drop:
  	kfree_skb(skb);
  	return err;
  }
be0c52bfe   Remi Denis-Courmont   Phonet: emit erro...
205
206
207
208
209
210
  static int pn_raw_send(const void *data, int len, struct net_device *dev,
  			u16 dst, u16 src, u8 res)
  {
  	struct sk_buff *skb = alloc_skb(MAX_PHONET_HEADER + len, GFP_ATOMIC);
  	if (skb == NULL)
  		return -ENOMEM;
aa6c45f32   Rémi Denis-Courmont   Phonet: route out...
211
212
  	if (phonet_address_lookup(dev_net(dev), pn_addr(dst)) == 0)
  		skb->pkt_type = PACKET_LOOPBACK;
be0c52bfe   Remi Denis-Courmont   Phonet: emit erro...
213
214
215
216
217
  	skb_reserve(skb, MAX_PHONET_HEADER);
  	__skb_put(skb, len);
  	skb_copy_to_linear_data(skb, data, len);
  	return pn_send(skb, dev, dst, src, res, 1);
  }
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
218
219
220
221
222
223
224
  /*
   * Create a Phonet header for the skb and send it out. Returns
   * non-zero error code if failed. The skb is freed then.
   */
  int pn_skb_send(struct sock *sk, struct sk_buff *skb,
  		const struct sockaddr_pn *target)
  {
aa6c45f32   Rémi Denis-Courmont   Phonet: route out...
225
  	struct net *net = sock_net(sk);
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
226
227
228
  	struct net_device *dev;
  	struct pn_sock *pn = pn_sk(sk);
  	int err;
a8059512b   Rémi Denis-Courmont   Phonet: implement...
229
230
231
232
233
234
235
236
237
238
239
240
  	u16 src, dst;
  	u8 daddr, saddr, res;
  
  	src = pn->sobject;
  	if (target != NULL) {
  		dst = pn_sockaddr_get_object(target);
  		res = pn_sockaddr_get_resource(target);
  	} else {
  		dst = pn->dobject;
  		res = pn->resource;
  	}
  	daddr = pn_addr(dst);
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
241
242
243
  
  	err = -EHOSTUNREACH;
  	if (sk->sk_bound_dev_if)
aa6c45f32   Rémi Denis-Courmont   Phonet: route out...
244
245
246
247
  		dev = dev_get_by_index(net, sk->sk_bound_dev_if);
  	else if (phonet_address_lookup(net, daddr) == 0) {
  		dev = phonet_device_get(net);
  		skb->pkt_type = PACKET_LOOPBACK;
c69d4407d   Rémi Denis-Courmont   Phonet: fix NULL ...
248
  	} else if (dst == 0) {
b6a563b2a   Rémi Denis-Courmont   Phonet: look up t...
249
  		/* Resource routing (small race until phonet_rcv()) */
c69d4407d   Rémi Denis-Courmont   Phonet: fix NULL ...
250
  		struct sock *sk = pn_find_sock_by_res(net, res);
b6a563b2a   Rémi Denis-Courmont   Phonet: look up t...
251
252
253
254
255
256
  		if (sk)	{
  			sock_put(sk);
  			dev = phonet_device_get(net);
  			skb->pkt_type = PACKET_LOOPBACK;
  		} else
  			dev = phonet_route_output(net, daddr);
aa6c45f32   Rémi Denis-Courmont   Phonet: route out...
257
258
  	} else
  		dev = phonet_route_output(net, daddr);
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
259
260
261
262
263
264
  	if (!dev || !(dev->flags & IFF_UP))
  		goto drop;
  
  	saddr = phonet_address_get(dev, daddr);
  	if (saddr == PN_NO_ADDR)
  		goto drop;
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
265
266
  	if (!pn_addr(src))
  		src = pn_object(saddr, pn_obj(src));
a8059512b   Rémi Denis-Courmont   Phonet: implement...
267
  	err = pn_send(skb, dev, dst, src, res, 0);
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
268
269
270
271
272
273
274
275
276
277
  	dev_put(dev);
  	return err;
  
  drop:
  	kfree_skb(skb);
  	if (dev)
  		dev_put(dev);
  	return err;
  }
  EXPORT_SYMBOL(pn_skb_send);
be0c52bfe   Remi Denis-Courmont   Phonet: emit erro...
278
279
280
281
282
283
284
285
286
287
288
  /* Do not send an error message in response to an error message */
  static inline int can_respond(struct sk_buff *skb)
  {
  	const struct phonethdr *ph;
  	const struct phonetmsg *pm;
  	u8 submsg_id;
  
  	if (!pskb_may_pull(skb, 3))
  		return 0;
  
  	ph = pn_hdr(skb);
be0c52bfe   Remi Denis-Courmont   Phonet: emit erro...
289
290
  	if (ph->pn_res == PN_PREFIX && !pskb_may_pull(skb, 5))
  		return 0;
c3a90c788   Remi Denis-Courmont   Phonet: do not re...
291
292
  	if (ph->pn_res == PN_COMMGR) /* indications */
  		return 0;
be0c52bfe   Remi Denis-Courmont   Phonet: emit erro...
293
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
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
  
  	ph = pn_hdr(skb); /* re-acquires the pointer */
  	pm = pn_msg(skb);
  	if (pm->pn_msg_id != PN_COMMON_MESSAGE)
  		return 1;
  	submsg_id = (ph->pn_res == PN_PREFIX)
  		? pm->pn_e_submsg_id : pm->pn_submsg_id;
  	if (submsg_id != PN_COMM_ISA_ENTITY_NOT_REACHABLE_RESP &&
  		pm->pn_e_submsg_id != PN_COMM_SERVICE_NOT_IDENTIFIED_RESP)
  		return 1;
  	return 0;
  }
  
  static int send_obj_unreachable(struct sk_buff *rskb)
  {
  	const struct phonethdr *oph = pn_hdr(rskb);
  	const struct phonetmsg *opm = pn_msg(rskb);
  	struct phonetmsg resp;
  
  	memset(&resp, 0, sizeof(resp));
  	resp.pn_trans_id = opm->pn_trans_id;
  	resp.pn_msg_id = PN_COMMON_MESSAGE;
  	if (oph->pn_res == PN_PREFIX) {
  		resp.pn_e_res_id = opm->pn_e_res_id;
  		resp.pn_e_submsg_id = PN_COMM_ISA_ENTITY_NOT_REACHABLE_RESP;
  		resp.pn_e_orig_msg_id = opm->pn_msg_id;
  		resp.pn_e_status = 0;
  	} else {
  		resp.pn_submsg_id = PN_COMM_ISA_ENTITY_NOT_REACHABLE_RESP;
  		resp.pn_orig_msg_id = opm->pn_msg_id;
  		resp.pn_status = 0;
  	}
  	return pn_raw_send(&resp, sizeof(resp), rskb->dev,
  				pn_object(oph->pn_sdev, oph->pn_sobj),
  				pn_object(oph->pn_rdev, oph->pn_robj),
  				oph->pn_res);
  }
  
  static int send_reset_indications(struct sk_buff *rskb)
  {
  	struct phonethdr *oph = pn_hdr(rskb);
  	static const u8 data[4] = {
  		0x00 /* trans ID */, 0x10 /* subscribe msg */,
  		0x00 /* subscription count */, 0x00 /* dummy */
  	};
  
  	return pn_raw_send(data, sizeof(data), rskb->dev,
  				pn_object(oph->pn_sdev, 0x00),
c3a90c788   Remi Denis-Courmont   Phonet: do not re...
341
342
  				pn_object(oph->pn_rdev, oph->pn_robj),
  				PN_COMMGR);
be0c52bfe   Remi Denis-Courmont   Phonet: emit erro...
343
  }
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
344
345
346
347
348
349
350
351
352
353
  /* packet type functions */
  
  /*
   * Stuff received packets to associated sockets.
   * On error, returns non-zero and releases the skb.
   */
  static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
  			struct packet_type *pkttype,
  			struct net_device *orig_dev)
  {
4b8f704be   remi.denis-courmont@nokia   Phonet: check des...
354
  	struct net *net = dev_net(dev);
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
355
356
357
  	struct phonethdr *ph;
  	struct sockaddr_pn sa;
  	u16 len;
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
  	/* check we have at least a full Phonet header */
  	if (!pskb_pull(skb, sizeof(struct phonethdr)))
  		goto out;
  
  	/* check that the advertised length is correct */
  	ph = pn_hdr(skb);
  	len = get_unaligned_be16(&ph->pn_length);
  	if (len < 2)
  		goto out;
  	len -= 2;
  	if ((len > skb->len) || pskb_trim(skb, len))
  		goto out;
  	skb_reset_transport_header(skb);
  
  	pn_skb_get_dst_sockaddr(skb, &sa);
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
373

f14001fcd   Rémi Denis-Courmont   Phonet: deliver b...
374
375
376
377
378
  	/* check if this is broadcasted */
  	if (pn_sockaddr_get_addr(&sa) == PNADDR_BROADCAST) {
  		pn_deliver_sock_broadcast(net, skb);
  		goto out;
  	}
b6a563b2a   Rémi Denis-Courmont   Phonet: look up t...
379
380
381
382
383
384
  	/* resource routing */
  	if (pn_sockaddr_get_object(&sa) == 0) {
  		struct sock *sk = pn_find_sock_by_res(net, sa.spn_resource);
  		if (sk)
  			return sk_receive_skb(sk, skb, 0);
  	}
4b8f704be   remi.denis-courmont@nokia   Phonet: check des...
385
386
387
388
389
390
391
  	/* check if we are the destination */
  	if (phonet_address_lookup(net, pn_sockaddr_get_addr(&sa)) == 0) {
  		/* Phonet packet input */
  		struct sock *sk = pn_find_sock_by_sa(net, &sa);
  
  		if (sk)
  			return sk_receive_skb(sk, skb, 0);
be0c52bfe   Remi Denis-Courmont   Phonet: emit erro...
392
393
394
395
  		if (can_respond(skb)) {
  			send_obj_unreachable(skb);
  			send_reset_indications(skb);
  		}
86a0a1e52   Rémi Denis-Courmont   Phonet: forward i...
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
  	} else if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
  		goto out; /* Race between address deletion and loopback */
  	else {
  		/* Phonet packet routing */
  		struct net_device *out_dev;
  
  		out_dev = phonet_route_output(net, pn_sockaddr_get_addr(&sa));
  		if (!out_dev) {
  			LIMIT_NETDEBUG(KERN_WARNING"No Phonet route to %02X
  ",
  					pn_sockaddr_get_addr(&sa));
  			goto out;
  		}
  
  		__skb_push(skb, sizeof(struct phonethdr));
  		skb->dev = out_dev;
  		if (out_dev == dev) {
  			LIMIT_NETDEBUG(KERN_ERR"Phonet loop to %02X on %s
  ",
  					pn_sockaddr_get_addr(&sa), dev->name);
  			goto out_dev;
  		}
  		/* Some drivers (e.g. TUN) do not allocate HW header space */
  		if (skb_cow_head(skb, out_dev->hard_header_len))
  			goto out_dev;
  
  		if (dev_hard_header(skb, out_dev, ETH_P_PHONET, NULL, NULL,
  					skb->len) < 0)
  			goto out_dev;
  		dev_queue_xmit(skb);
  		dev_put(out_dev);
  		return NET_RX_SUCCESS;
  out_dev:
  		dev_put(out_dev);
be0c52bfe   Remi Denis-Courmont   Phonet: emit erro...
430
  	}
ba113a94b   Remi Denis-Courmont   Phonet: common so...
431

4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
432
433
434
435
  out:
  	kfree_skb(skb);
  	return NET_RX_DROP;
  }
7546dd97d   Stephen Hemminger   net: convert usag...
436
  static struct packet_type phonet_packet_type __read_mostly = {
09640e636   Harvey Harrison   net: replace uses...
437
  	.type = cpu_to_be16(ETH_P_PHONET),
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
438
439
  	.func = phonet_rcv,
  };
7ed0132f2   Rémi Denis-Courmont   Phonet: put proto...
440
  static DEFINE_MUTEX(proto_tab_lock);
facb4edc1   Dan Carpenter   phonet: some sign...
441
  int __init_or_module phonet_proto_register(unsigned int protocol,
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
442
443
444
445
446
447
448
449
450
451
  						struct phonet_protocol *pp)
  {
  	int err = 0;
  
  	if (protocol >= PHONET_NPROTO)
  		return -EINVAL;
  
  	err = proto_register(pp->prot, 1);
  	if (err)
  		return err;
7ed0132f2   Rémi Denis-Courmont   Phonet: put proto...
452
  	mutex_lock(&proto_tab_lock);
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
453
454
455
  	if (proto_tab[protocol])
  		err = -EBUSY;
  	else
cf778b00e   Eric Dumazet   net: reintroduce ...
456
  		rcu_assign_pointer(proto_tab[protocol], pp);
7ed0132f2   Rémi Denis-Courmont   Phonet: put proto...
457
  	mutex_unlock(&proto_tab_lock);
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
458
459
460
461
  
  	return err;
  }
  EXPORT_SYMBOL(phonet_proto_register);
facb4edc1   Dan Carpenter   phonet: some sign...
462
  void phonet_proto_unregister(unsigned int protocol, struct phonet_protocol *pp)
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
463
  {
7ed0132f2   Rémi Denis-Courmont   Phonet: put proto...
464
  	mutex_lock(&proto_tab_lock);
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
465
  	BUG_ON(proto_tab[protocol] != pp);
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
466
  	RCU_INIT_POINTER(proto_tab[protocol], NULL);
7ed0132f2   Rémi Denis-Courmont   Phonet: put proto...
467
468
  	mutex_unlock(&proto_tab_lock);
  	synchronize_rcu();
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
469
470
471
  	proto_unregister(pp->prot);
  }
  EXPORT_SYMBOL(phonet_proto_unregister);
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
472
473
474
475
  /* Module registration */
  static int __init phonet_init(void)
  {
  	int err;
76e02cf69   remi.denis-courmont@nokia   Phonet: allow pho...
476
477
478
  	err = phonet_device_init();
  	if (err)
  		return err;
6b0d07ba1   Rémi Denis-Courmont   Phonet: put socke...
479
  	pn_sock_init();
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
480
481
482
483
484
  	err = sock_register(&phonet_proto_family);
  	if (err) {
  		printk(KERN_ALERT
  			"phonet protocol family initialization failed
  ");
76e02cf69   remi.denis-courmont@nokia   Phonet: allow pho...
485
  		goto err_sock;
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
486
487
488
  	}
  
  	dev_add_pack(&phonet_packet_type);
87ab4e20b   Remi Denis-Courmont   Phonet: proc inte...
489
  	phonet_sysctl_init();
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
490
491
492
493
  
  	err = isi_register();
  	if (err)
  		goto err;
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
494
  	return 0;
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
495
496
  
  err:
87ab4e20b   Remi Denis-Courmont   Phonet: proc inte...
497
  	phonet_sysctl_exit();
25532824f   Rémi Denis-Courmont   Phonet: modules a...
498
  	sock_unregister(PF_PHONET);
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
499
  	dev_remove_pack(&phonet_packet_type);
76e02cf69   remi.denis-courmont@nokia   Phonet: allow pho...
500
  err_sock:
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
501
502
  	phonet_device_exit();
  	return err;
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
503
504
505
506
  }
  
  static void __exit phonet_exit(void)
  {
107d0d9b8   Remi Denis-Courmont   Phonet: Phonet da...
507
  	isi_unregister();
87ab4e20b   Remi Denis-Courmont   Phonet: proc inte...
508
  	phonet_sysctl_exit();
25532824f   Rémi Denis-Courmont   Phonet: modules a...
509
  	sock_unregister(PF_PHONET);
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
510
  	dev_remove_pack(&phonet_packet_type);
f8ff60283   Remi Denis-Courmont   Phonet: network d...
511
  	phonet_device_exit();
4b07b3f69   Remi Denis-Courmont   Phonet: PF_PHONET...
512
513
514
515
516
517
  }
  
  module_init(phonet_init);
  module_exit(phonet_exit);
  MODULE_DESCRIPTION("Phonet protocol stack for Linux");
  MODULE_LICENSE("GPL");
25532824f   Rémi Denis-Courmont   Phonet: modules a...
518
  MODULE_ALIAS_NETPROTO(PF_PHONET);