aboutsummaryrefslogtreecommitdiffstats
path: root/net/phonet
diff options
context:
space:
mode:
Diffstat (limited to 'net/phonet')
-rw-r--r--net/phonet/Kconfig16
-rw-r--r--net/phonet/Makefile11
-rw-r--r--net/phonet/af_phonet.c476
-rw-r--r--net/phonet/datagram.c197
-rw-r--r--net/phonet/pep-gprs.c347
-rw-r--r--net/phonet/pep.c1076
-rw-r--r--net/phonet/pn_dev.c208
-rw-r--r--net/phonet/pn_netlink.c165
-rw-r--r--net/phonet/socket.c411
-rw-r--r--net/phonet/sysctl.c113
10 files changed, 3020 insertions, 0 deletions
diff --git a/net/phonet/Kconfig b/net/phonet/Kconfig
new file mode 100644
index 000000000000..51a5669573f2
--- /dev/null
+++ b/net/phonet/Kconfig
@@ -0,0 +1,16 @@
1#
2# Phonet protocol
3#
4
5config PHONET
6 tristate "Phonet protocols family"
7 help
8 The Phone Network protocol (PhoNet) is a packet-oriented
9 communication protocol developped by Nokia for use with its modems.
10
11 This is required for Maemo to use cellular data connectivity (if
12 supported). It can also be used to control Nokia phones
13 from a Linux computer, although AT commands may be easier to use.
14
15 To compile this driver as a module, choose M here: the module
16 will be called phonet. If unsure, say N.
diff --git a/net/phonet/Makefile b/net/phonet/Makefile
new file mode 100644
index 000000000000..d62bbba649b3
--- /dev/null
+++ b/net/phonet/Makefile
@@ -0,0 +1,11 @@
1obj-$(CONFIG_PHONET) += phonet.o pn_pep.o
2
3phonet-objs := \
4 pn_dev.o \
5 pn_netlink.o \
6 socket.o \
7 datagram.o \
8 sysctl.o \
9 af_phonet.o
10
11pn_pep-objs := pep.o pep-gprs.o
diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c
new file mode 100644
index 000000000000..b9d97effebe3
--- /dev/null
+++ b/net/phonet/af_phonet.c
@@ -0,0 +1,476 @@
1/*
2 * File: af_phonet.c
3 *
4 * Phonet protocols family
5 *
6 * Copyright (C) 2008 Nokia Corporation.
7 *
8 * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
9 * Original author: Sakari Ailus <sakari.ailus@nokia.com>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * version 2 as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301 USA
24 */
25
26#include <linux/kernel.h>
27#include <linux/module.h>
28#include <asm/unaligned.h>
29#include <net/sock.h>
30
31#include <linux/if_phonet.h>
32#include <linux/phonet.h>
33#include <net/phonet/phonet.h>
34#include <net/phonet/pn_dev.h>
35
36static struct net_proto_family phonet_proto_family;
37static struct phonet_protocol *phonet_proto_get(int protocol);
38static inline void phonet_proto_put(struct phonet_protocol *pp);
39
40/* protocol family functions */
41
42static int pn_socket_create(struct net *net, struct socket *sock, int protocol)
43{
44 struct sock *sk;
45 struct pn_sock *pn;
46 struct phonet_protocol *pnp;
47 int err;
48
49 if (net != &init_net)
50 return -EAFNOSUPPORT;
51
52 if (!capable(CAP_SYS_ADMIN))
53 return -EPERM;
54
55 if (protocol == 0) {
56 /* Default protocol selection */
57 switch (sock->type) {
58 case SOCK_DGRAM:
59 protocol = PN_PROTO_PHONET;
60 break;
61 case SOCK_SEQPACKET:
62 protocol = PN_PROTO_PIPE;
63 break;
64 default:
65 return -EPROTONOSUPPORT;
66 }
67 }
68
69 pnp = phonet_proto_get(protocol);
70 if (pnp == NULL &&
71 request_module("net-pf-%d-proto-%d", PF_PHONET, protocol) == 0)
72 pnp = phonet_proto_get(protocol);
73
74 if (pnp == NULL)
75 return -EPROTONOSUPPORT;
76 if (sock->type != pnp->sock_type) {
77 err = -EPROTONOSUPPORT;
78 goto out;
79 }
80
81 sk = sk_alloc(net, PF_PHONET, GFP_KERNEL, pnp->prot);
82 if (sk == NULL) {
83 err = -ENOMEM;
84 goto out;
85 }
86
87 sock_init_data(sock, sk);
88 sock->state = SS_UNCONNECTED;
89 sock->ops = pnp->ops;
90 sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
91 sk->sk_protocol = protocol;
92 pn = pn_sk(sk);
93 pn->sobject = 0;
94 pn->resource = 0;
95 sk->sk_prot->init(sk);
96 err = 0;
97
98out:
99 phonet_proto_put(pnp);
100 return err;
101}
102
103static struct net_proto_family phonet_proto_family = {
104 .family = PF_PHONET,
105 .create = pn_socket_create,
106 .owner = THIS_MODULE,
107};
108
109/* Phonet device header operations */
110static int pn_header_create(struct sk_buff *skb, struct net_device *dev,
111 unsigned short type, const void *daddr,
112 const void *saddr, unsigned len)
113{
114 u8 *media = skb_push(skb, 1);
115
116 if (type != ETH_P_PHONET)
117 return -1;
118
119 if (!saddr)
120 saddr = dev->dev_addr;
121 *media = *(const u8 *)saddr;
122 return 1;
123}
124
125static int pn_header_parse(const struct sk_buff *skb, unsigned char *haddr)
126{
127 const u8 *media = skb_mac_header(skb);
128 *haddr = *media;
129 return 1;
130}
131
132struct header_ops phonet_header_ops = {
133 .create = pn_header_create,
134 .parse = pn_header_parse,
135};
136EXPORT_SYMBOL(phonet_header_ops);
137
138/*
139 * Prepends an ISI header and sends a datagram.
140 */
141static int pn_send(struct sk_buff *skb, struct net_device *dev,
142 u16 dst, u16 src, u8 res, u8 irq)
143{
144 struct phonethdr *ph;
145 int err;
146
147 if (skb->len + 2 > 0xffff) {
148 /* Phonet length field would overflow */
149 err = -EMSGSIZE;
150 goto drop;
151 }
152
153 skb_reset_transport_header(skb);
154 WARN_ON(skb_headroom(skb) & 1); /* HW assumes word alignment */
155 skb_push(skb, sizeof(struct phonethdr));
156 skb_reset_network_header(skb);
157 ph = pn_hdr(skb);
158 ph->pn_rdev = pn_dev(dst);
159 ph->pn_sdev = pn_dev(src);
160 ph->pn_res = res;
161 ph->pn_length = __cpu_to_be16(skb->len + 2 - sizeof(*ph));
162 ph->pn_robj = pn_obj(dst);
163 ph->pn_sobj = pn_obj(src);
164
165 skb->protocol = htons(ETH_P_PHONET);
166 skb->priority = 0;
167 skb->dev = dev;
168
169 if (pn_addr(src) == pn_addr(dst)) {
170 skb_reset_mac_header(skb);
171 skb->pkt_type = PACKET_LOOPBACK;
172 skb_orphan(skb);
173 if (irq)
174 netif_rx(skb);
175 else
176 netif_rx_ni(skb);
177 err = 0;
178 } else {
179 err = dev_hard_header(skb, dev, ntohs(skb->protocol),
180 NULL, NULL, skb->len);
181 if (err < 0) {
182 err = -EHOSTUNREACH;
183 goto drop;
184 }
185 err = dev_queue_xmit(skb);
186 }
187
188 return err;
189drop:
190 kfree_skb(skb);
191 return err;
192}
193
194static int pn_raw_send(const void *data, int len, struct net_device *dev,
195 u16 dst, u16 src, u8 res)
196{
197 struct sk_buff *skb = alloc_skb(MAX_PHONET_HEADER + len, GFP_ATOMIC);
198 if (skb == NULL)
199 return -ENOMEM;
200
201 skb_reserve(skb, MAX_PHONET_HEADER);
202 __skb_put(skb, len);
203 skb_copy_to_linear_data(skb, data, len);
204 return pn_send(skb, dev, dst, src, res, 1);
205}
206
207/*
208 * Create a Phonet header for the skb and send it out. Returns
209 * non-zero error code if failed. The skb is freed then.
210 */
211int pn_skb_send(struct sock *sk, struct sk_buff *skb,
212 const struct sockaddr_pn *target)
213{
214 struct net_device *dev;
215 struct pn_sock *pn = pn_sk(sk);
216 int err;
217 u16 src;
218 u8 daddr = pn_sockaddr_get_addr(target), saddr = PN_NO_ADDR;
219
220 err = -EHOSTUNREACH;
221 if (sk->sk_bound_dev_if)
222 dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if);
223 else
224 dev = phonet_device_get(sock_net(sk));
225 if (!dev || !(dev->flags & IFF_UP))
226 goto drop;
227
228 saddr = phonet_address_get(dev, daddr);
229 if (saddr == PN_NO_ADDR)
230 goto drop;
231
232 src = pn->sobject;
233 if (!pn_addr(src))
234 src = pn_object(saddr, pn_obj(src));
235
236 err = pn_send(skb, dev, pn_sockaddr_get_object(target),
237 src, pn_sockaddr_get_resource(target), 0);
238 dev_put(dev);
239 return err;
240
241drop:
242 kfree_skb(skb);
243 if (dev)
244 dev_put(dev);
245 return err;
246}
247EXPORT_SYMBOL(pn_skb_send);
248
249/* Do not send an error message in response to an error message */
250static inline int can_respond(struct sk_buff *skb)
251{
252 const struct phonethdr *ph;
253 const struct phonetmsg *pm;
254 u8 submsg_id;
255
256 if (!pskb_may_pull(skb, 3))
257 return 0;
258
259 ph = pn_hdr(skb);
260 if (phonet_address_get(skb->dev, ph->pn_rdev) != ph->pn_rdev)
261 return 0; /* we are not the destination */
262 if (ph->pn_res == PN_PREFIX && !pskb_may_pull(skb, 5))
263 return 0;
264
265 ph = pn_hdr(skb); /* re-acquires the pointer */
266 pm = pn_msg(skb);
267 if (pm->pn_msg_id != PN_COMMON_MESSAGE)
268 return 1;
269 submsg_id = (ph->pn_res == PN_PREFIX)
270 ? pm->pn_e_submsg_id : pm->pn_submsg_id;
271 if (submsg_id != PN_COMM_ISA_ENTITY_NOT_REACHABLE_RESP &&
272 pm->pn_e_submsg_id != PN_COMM_SERVICE_NOT_IDENTIFIED_RESP)
273 return 1;
274 return 0;
275}
276
277static int send_obj_unreachable(struct sk_buff *rskb)
278{
279 const struct phonethdr *oph = pn_hdr(rskb);
280 const struct phonetmsg *opm = pn_msg(rskb);
281 struct phonetmsg resp;
282
283 memset(&resp, 0, sizeof(resp));
284 resp.pn_trans_id = opm->pn_trans_id;
285 resp.pn_msg_id = PN_COMMON_MESSAGE;
286 if (oph->pn_res == PN_PREFIX) {
287 resp.pn_e_res_id = opm->pn_e_res_id;
288 resp.pn_e_submsg_id = PN_COMM_ISA_ENTITY_NOT_REACHABLE_RESP;
289 resp.pn_e_orig_msg_id = opm->pn_msg_id;
290 resp.pn_e_status = 0;
291 } else {
292 resp.pn_submsg_id = PN_COMM_ISA_ENTITY_NOT_REACHABLE_RESP;
293 resp.pn_orig_msg_id = opm->pn_msg_id;
294 resp.pn_status = 0;
295 }
296 return pn_raw_send(&resp, sizeof(resp), rskb->dev,
297 pn_object(oph->pn_sdev, oph->pn_sobj),
298 pn_object(oph->pn_rdev, oph->pn_robj),
299 oph->pn_res);
300}
301
302static int send_reset_indications(struct sk_buff *rskb)
303{
304 struct phonethdr *oph = pn_hdr(rskb);
305 static const u8 data[4] = {
306 0x00 /* trans ID */, 0x10 /* subscribe msg */,
307 0x00 /* subscription count */, 0x00 /* dummy */
308 };
309
310 return pn_raw_send(data, sizeof(data), rskb->dev,
311 pn_object(oph->pn_sdev, 0x00),
312 pn_object(oph->pn_rdev, oph->pn_robj), 0x10);
313}
314
315
316/* packet type functions */
317
318/*
319 * Stuff received packets to associated sockets.
320 * On error, returns non-zero and releases the skb.
321 */
322static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
323 struct packet_type *pkttype,
324 struct net_device *orig_dev)
325{
326 struct phonethdr *ph;
327 struct sock *sk;
328 struct sockaddr_pn sa;
329 u16 len;
330
331 if (dev_net(dev) != &init_net)
332 goto out;
333
334 /* check we have at least a full Phonet header */
335 if (!pskb_pull(skb, sizeof(struct phonethdr)))
336 goto out;
337
338 /* check that the advertised length is correct */
339 ph = pn_hdr(skb);
340 len = get_unaligned_be16(&ph->pn_length);
341 if (len < 2)
342 goto out;
343 len -= 2;
344 if ((len > skb->len) || pskb_trim(skb, len))
345 goto out;
346 skb_reset_transport_header(skb);
347
348 pn_skb_get_dst_sockaddr(skb, &sa);
349 if (pn_sockaddr_get_addr(&sa) == 0)
350 goto out; /* currently, we cannot be device 0 */
351
352 sk = pn_find_sock_by_sa(&sa);
353 if (sk == NULL) {
354 if (can_respond(skb)) {
355 send_obj_unreachable(skb);
356 send_reset_indications(skb);
357 }
358 goto out;
359 }
360
361 /* Push data to the socket (or other sockets connected to it). */
362 return sk_receive_skb(sk, skb, 0);
363
364out:
365 kfree_skb(skb);
366 return NET_RX_DROP;
367}
368
369static struct packet_type phonet_packet_type = {
370 .type = __constant_htons(ETH_P_PHONET),
371 .dev = NULL,
372 .func = phonet_rcv,
373};
374
375/* Transport protocol registration */
376static struct phonet_protocol *proto_tab[PHONET_NPROTO] __read_mostly;
377static DEFINE_SPINLOCK(proto_tab_lock);
378
379int __init_or_module phonet_proto_register(int protocol,
380 struct phonet_protocol *pp)
381{
382 int err = 0;
383
384 if (protocol >= PHONET_NPROTO)
385 return -EINVAL;
386
387 err = proto_register(pp->prot, 1);
388 if (err)
389 return err;
390
391 spin_lock(&proto_tab_lock);
392 if (proto_tab[protocol])
393 err = -EBUSY;
394 else
395 proto_tab[protocol] = pp;
396 spin_unlock(&proto_tab_lock);
397
398 return err;
399}
400EXPORT_SYMBOL(phonet_proto_register);
401
402void phonet_proto_unregister(int protocol, struct phonet_protocol *pp)
403{
404 spin_lock(&proto_tab_lock);
405 BUG_ON(proto_tab[protocol] != pp);
406 proto_tab[protocol] = NULL;
407 spin_unlock(&proto_tab_lock);
408 proto_unregister(pp->prot);
409}
410EXPORT_SYMBOL(phonet_proto_unregister);
411
412static struct phonet_protocol *phonet_proto_get(int protocol)
413{
414 struct phonet_protocol *pp;
415
416 if (protocol >= PHONET_NPROTO)
417 return NULL;
418
419 spin_lock(&proto_tab_lock);
420 pp = proto_tab[protocol];
421 if (pp && !try_module_get(pp->prot->owner))
422 pp = NULL;
423 spin_unlock(&proto_tab_lock);
424
425 return pp;
426}
427
428static inline void phonet_proto_put(struct phonet_protocol *pp)
429{
430 module_put(pp->prot->owner);
431}
432
433/* Module registration */
434static int __init phonet_init(void)
435{
436 int err;
437
438 err = sock_register(&phonet_proto_family);
439 if (err) {
440 printk(KERN_ALERT
441 "phonet protocol family initialization failed\n");
442 return err;
443 }
444
445 phonet_device_init();
446 dev_add_pack(&phonet_packet_type);
447 phonet_netlink_register();
448 phonet_sysctl_init();
449
450 err = isi_register();
451 if (err)
452 goto err;
453 return 0;
454
455err:
456 phonet_sysctl_exit();
457 sock_unregister(PF_PHONET);
458 dev_remove_pack(&phonet_packet_type);
459 phonet_device_exit();
460 return err;
461}
462
463static void __exit phonet_exit(void)
464{
465 isi_unregister();
466 phonet_sysctl_exit();
467 sock_unregister(PF_PHONET);
468 dev_remove_pack(&phonet_packet_type);
469 phonet_device_exit();
470}
471
472module_init(phonet_init);
473module_exit(phonet_exit);
474MODULE_DESCRIPTION("Phonet protocol stack for Linux");
475MODULE_LICENSE("GPL");
476MODULE_ALIAS_NETPROTO(PF_PHONET);
diff --git a/net/phonet/datagram.c b/net/phonet/datagram.c
new file mode 100644
index 000000000000..e087862ed7e4
--- /dev/null
+++ b/net/phonet/datagram.c
@@ -0,0 +1,197 @@
1/*
2 * File: datagram.c
3 *
4 * Datagram (ISI) Phonet sockets
5 *
6 * Copyright (C) 2008 Nokia Corporation.
7 *
8 * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
9 * Original author: Sakari Ailus <sakari.ailus@nokia.com>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * version 2 as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301 USA
24 */
25
26#include <linux/kernel.h>
27#include <linux/socket.h>
28#include <asm/ioctls.h>
29#include <net/sock.h>
30
31#include <linux/phonet.h>
32#include <net/phonet/phonet.h>
33
34static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb);
35
36/* associated socket ceases to exist */
37static void pn_sock_close(struct sock *sk, long timeout)
38{
39 sk_common_release(sk);
40}
41
42static int pn_ioctl(struct sock *sk, int cmd, unsigned long arg)
43{
44 struct sk_buff *skb;
45 int answ;
46
47 switch (cmd) {
48 case SIOCINQ:
49 lock_sock(sk);
50 skb = skb_peek(&sk->sk_receive_queue);
51 answ = skb ? skb->len : 0;
52 release_sock(sk);
53 return put_user(answ, (int __user *)arg);
54 }
55
56 return -ENOIOCTLCMD;
57}
58
59/* Destroy socket. All references are gone. */
60static void pn_destruct(struct sock *sk)
61{
62 skb_queue_purge(&sk->sk_receive_queue);
63}
64
65static int pn_init(struct sock *sk)
66{
67 sk->sk_destruct = pn_destruct;
68 return 0;
69}
70
71static int pn_sendmsg(struct kiocb *iocb, struct sock *sk,
72 struct msghdr *msg, size_t len)
73{
74 struct sockaddr_pn *target;
75 struct sk_buff *skb;
76 int err;
77
78 if (msg->msg_flags & MSG_OOB)
79 return -EOPNOTSUPP;
80
81 if (msg->msg_name == NULL)
82 return -EDESTADDRREQ;
83
84 if (msg->msg_namelen < sizeof(struct sockaddr_pn))
85 return -EINVAL;
86
87 target = (struct sockaddr_pn *)msg->msg_name;
88 if (target->spn_family != AF_PHONET)
89 return -EAFNOSUPPORT;
90
91 skb = sock_alloc_send_skb(sk, MAX_PHONET_HEADER + len,
92 msg->msg_flags & MSG_DONTWAIT, &err);
93 if (skb == NULL)
94 return err;
95 skb_reserve(skb, MAX_PHONET_HEADER);
96
97 err = memcpy_fromiovec((void *)skb_put(skb, len), msg->msg_iov, len);
98 if (err < 0) {
99 kfree_skb(skb);
100 return err;
101 }
102
103 /*
104 * Fill in the Phonet header and
105 * finally pass the packet forwards.
106 */
107 err = pn_skb_send(sk, skb, target);
108
109 /* If ok, return len. */
110 return (err >= 0) ? len : err;
111}
112
113static int pn_recvmsg(struct kiocb *iocb, struct sock *sk,
114 struct msghdr *msg, size_t len, int noblock,
115 int flags, int *addr_len)
116{
117 struct sk_buff *skb = NULL;
118 struct sockaddr_pn sa;
119 int rval = -EOPNOTSUPP;
120 int copylen;
121
122 if (flags & MSG_OOB)
123 goto out_nofree;
124
125 if (addr_len)
126 *addr_len = sizeof(sa);
127
128 skb = skb_recv_datagram(sk, flags, noblock, &rval);
129 if (skb == NULL)
130 goto out_nofree;
131
132 pn_skb_get_src_sockaddr(skb, &sa);
133
134 copylen = skb->len;
135 if (len < copylen) {
136 msg->msg_flags |= MSG_TRUNC;
137 copylen = len;
138 }
139
140 rval = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copylen);
141 if (rval) {
142 rval = -EFAULT;
143 goto out;
144 }
145
146 rval = (flags & MSG_TRUNC) ? skb->len : copylen;
147
148 if (msg->msg_name != NULL)
149 memcpy(msg->msg_name, &sa, sizeof(struct sockaddr_pn));
150
151out:
152 skb_free_datagram(sk, skb);
153
154out_nofree:
155 return rval;
156}
157
158/* Queue an skb for a sock. */
159static int pn_backlog_rcv(struct sock *sk, struct sk_buff *skb)
160{
161 int err = sock_queue_rcv_skb(sk, skb);
162 if (err < 0)
163 kfree_skb(skb);
164 return err ? NET_RX_DROP : NET_RX_SUCCESS;
165}
166
167/* Module registration */
168static struct proto pn_proto = {
169 .close = pn_sock_close,
170 .ioctl = pn_ioctl,
171 .init = pn_init,
172 .sendmsg = pn_sendmsg,
173 .recvmsg = pn_recvmsg,
174 .backlog_rcv = pn_backlog_rcv,
175 .hash = pn_sock_hash,
176 .unhash = pn_sock_unhash,
177 .get_port = pn_sock_get_port,
178 .obj_size = sizeof(struct pn_sock),
179 .owner = THIS_MODULE,
180 .name = "PHONET",
181};
182
183static struct phonet_protocol pn_dgram_proto = {
184 .ops = &phonet_dgram_ops,
185 .prot = &pn_proto,
186 .sock_type = SOCK_DGRAM,
187};
188
189int __init isi_register(void)
190{
191 return phonet_proto_register(PN_PROTO_PHONET, &pn_dgram_proto);
192}
193
194void __exit isi_unregister(void)
195{
196 phonet_proto_unregister(PN_PROTO_PHONET, &pn_dgram_proto);
197}
diff --git a/net/phonet/pep-gprs.c b/net/phonet/pep-gprs.c
new file mode 100644
index 000000000000..9978afbd9f2a
--- /dev/null
+++ b/net/phonet/pep-gprs.c
@@ -0,0 +1,347 @@
1/*
2 * File: pep-gprs.c
3 *
4 * GPRS over Phonet pipe end point socket
5 *
6 * Copyright (C) 2008 Nokia Corporation.
7 *
8 * Author: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * version 2 as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA
23 */
24
25#include <linux/kernel.h>
26#include <linux/netdevice.h>
27#include <linux/if_ether.h>
28#include <linux/if_arp.h>
29#include <net/sock.h>
30
31#include <linux/if_phonet.h>
32#include <net/tcp_states.h>
33#include <net/phonet/gprs.h>
34
35#define GPRS_DEFAULT_MTU 1400
36
37struct gprs_dev {
38 struct sock *sk;
39 void (*old_state_change)(struct sock *);
40 void (*old_data_ready)(struct sock *, int);
41 void (*old_write_space)(struct sock *);
42
43 struct net_device *net;
44 struct net_device_stats stats;
45
46 struct sk_buff_head tx_queue;
47 struct work_struct tx_work;
48 spinlock_t tx_lock;
49 unsigned tx_max;
50};
51
52static int gprs_type_trans(struct sk_buff *skb)
53{
54 const u8 *pvfc;
55 u8 buf;
56
57 pvfc = skb_header_pointer(skb, 0, 1, &buf);
58 if (!pvfc)
59 return 0;
60 /* Look at IP version field */
61 switch (*pvfc >> 4) {
62 case 4:
63 return htons(ETH_P_IP);
64 case 6:
65 return htons(ETH_P_IPV6);
66 }
67 return 0;
68}
69
70/*
71 * Socket callbacks
72 */
73
74static void gprs_state_change(struct sock *sk)
75{
76 struct gprs_dev *dev = sk->sk_user_data;
77
78 if (sk->sk_state == TCP_CLOSE_WAIT) {
79 netif_stop_queue(dev->net);
80 netif_carrier_off(dev->net);
81 }
82}
83
84static int gprs_recv(struct gprs_dev *dev, struct sk_buff *skb)
85{
86 int err = 0;
87 u16 protocol = gprs_type_trans(skb);
88
89 if (!protocol) {
90 err = -EINVAL;
91 goto drop;
92 }
93
94 if (likely(skb_headroom(skb) & 3)) {
95 struct sk_buff *rskb, *fs;
96 int flen = 0;
97
98 /* Phonet Pipe data header is misaligned (3 bytes),
99 * so wrap the IP packet as a single fragment of an head-less
100 * socket buffer. The network stack will pull what it needs,
101 * but at least, the whole IP payload is not memcpy'd. */
102 rskb = netdev_alloc_skb(dev->net, 0);
103 if (!rskb) {
104 err = -ENOBUFS;
105 goto drop;
106 }
107 skb_shinfo(rskb)->frag_list = skb;
108 rskb->len += skb->len;
109 rskb->data_len += rskb->len;
110 rskb->truesize += rskb->len;
111
112 /* Avoid nested fragments */
113 for (fs = skb_shinfo(skb)->frag_list; fs; fs = fs->next)
114 flen += fs->len;
115 skb->next = skb_shinfo(skb)->frag_list;
116 skb_shinfo(skb)->frag_list = NULL;
117 skb->len -= flen;
118 skb->data_len -= flen;
119 skb->truesize -= flen;
120
121 skb = rskb;
122 }
123
124 skb->protocol = protocol;
125 skb_reset_mac_header(skb);
126 skb->dev = dev->net;
127
128 if (likely(dev->net->flags & IFF_UP)) {
129 dev->stats.rx_packets++;
130 dev->stats.rx_bytes += skb->len;
131 netif_rx(skb);
132 skb = NULL;
133 } else
134 err = -ENODEV;
135
136drop:
137 if (skb) {
138 dev_kfree_skb(skb);
139 dev->stats.rx_dropped++;
140 }
141 return err;
142}
143
144static void gprs_data_ready(struct sock *sk, int len)
145{
146 struct gprs_dev *dev = sk->sk_user_data;
147 struct sk_buff *skb;
148
149 while ((skb = pep_read(sk)) != NULL) {
150 skb_orphan(skb);
151 gprs_recv(dev, skb);
152 }
153}
154
155static void gprs_write_space(struct sock *sk)
156{
157 struct gprs_dev *dev = sk->sk_user_data;
158 unsigned credits = pep_writeable(sk);
159
160 spin_lock_bh(&dev->tx_lock);
161 dev->tx_max = credits;
162 if (credits > skb_queue_len(&dev->tx_queue))
163 netif_wake_queue(dev->net);
164 spin_unlock_bh(&dev->tx_lock);
165}
166
167/*
168 * Network device callbacks
169 */
170
171static int gprs_xmit(struct sk_buff *skb, struct net_device *net)
172{
173 struct gprs_dev *dev = netdev_priv(net);
174
175 switch (skb->protocol) {
176 case htons(ETH_P_IP):
177 case htons(ETH_P_IPV6):
178 break;
179 default:
180 dev_kfree_skb(skb);
181 return 0;
182 }
183
184 spin_lock(&dev->tx_lock);
185 if (likely(skb_queue_len(&dev->tx_queue) < dev->tx_max)) {
186 skb_queue_tail(&dev->tx_queue, skb);
187 skb = NULL;
188 }
189 if (skb_queue_len(&dev->tx_queue) >= dev->tx_max)
190 netif_stop_queue(net);
191 spin_unlock(&dev->tx_lock);
192
193 schedule_work(&dev->tx_work);
194 if (unlikely(skb))
195 dev_kfree_skb(skb);
196 return 0;
197}
198
199static void gprs_tx(struct work_struct *work)
200{
201 struct gprs_dev *dev = container_of(work, struct gprs_dev, tx_work);
202 struct sock *sk = dev->sk;
203 struct sk_buff *skb;
204
205 while ((skb = skb_dequeue(&dev->tx_queue)) != NULL) {
206 int err;
207
208 dev->stats.tx_bytes += skb->len;
209 dev->stats.tx_packets++;
210
211 skb_orphan(skb);
212 skb_set_owner_w(skb, sk);
213
214 lock_sock(sk);
215 err = pep_write(sk, skb);
216 if (err) {
217 LIMIT_NETDEBUG(KERN_WARNING"%s: TX error (%d)\n",
218 dev->net->name, err);
219 dev->stats.tx_aborted_errors++;
220 dev->stats.tx_errors++;
221 }
222 release_sock(sk);
223 }
224
225 lock_sock(sk);
226 gprs_write_space(sk);
227 release_sock(sk);
228}
229
230static int gprs_set_mtu(struct net_device *net, int new_mtu)
231{
232 if ((new_mtu < 576) || (new_mtu > (PHONET_MAX_MTU - 11)))
233 return -EINVAL;
234
235 net->mtu = new_mtu;
236 return 0;
237}
238
239static struct net_device_stats *gprs_get_stats(struct net_device *net)
240{
241 struct gprs_dev *dev = netdev_priv(net);
242
243 return &dev->stats;
244}
245
246static void gprs_setup(struct net_device *net)
247{
248 net->features = NETIF_F_FRAGLIST;
249 net->type = ARPHRD_NONE;
250 net->flags = IFF_POINTOPOINT | IFF_NOARP;
251 net->mtu = GPRS_DEFAULT_MTU;
252 net->hard_header_len = 0;
253 net->addr_len = 0;
254 net->tx_queue_len = 10;
255
256 net->destructor = free_netdev;
257 net->hard_start_xmit = gprs_xmit; /* mandatory */
258 net->change_mtu = gprs_set_mtu;
259 net->get_stats = gprs_get_stats;
260}
261
262/*
263 * External interface
264 */
265
266/*
267 * Attach a GPRS interface to a datagram socket.
268 * Returns the interface index on success, negative error code on error.
269 */
270int gprs_attach(struct sock *sk)
271{
272 static const char ifname[] = "gprs%d";
273 struct gprs_dev *dev;
274 struct net_device *net;
275 int err;
276
277 if (unlikely(sk->sk_type == SOCK_STREAM))
278 return -EINVAL; /* need packet boundaries */
279
280 /* Create net device */
281 net = alloc_netdev(sizeof(*dev), ifname, gprs_setup);
282 if (!net)
283 return -ENOMEM;
284 dev = netdev_priv(net);
285 dev->net = net;
286 dev->tx_max = 0;
287 spin_lock_init(&dev->tx_lock);
288 skb_queue_head_init(&dev->tx_queue);
289 INIT_WORK(&dev->tx_work, gprs_tx);
290
291 netif_stop_queue(net);
292 err = register_netdev(net);
293 if (err) {
294 free_netdev(net);
295 return err;
296 }
297
298 lock_sock(sk);
299 if (unlikely(sk->sk_user_data)) {
300 err = -EBUSY;
301 goto out_rel;
302 }
303 if (unlikely((1 << sk->sk_state & (TCPF_CLOSE|TCPF_LISTEN)) ||
304 sock_flag(sk, SOCK_DEAD))) {
305 err = -EINVAL;
306 goto out_rel;
307 }
308 sk->sk_user_data = dev;
309 dev->old_state_change = sk->sk_state_change;
310 dev->old_data_ready = sk->sk_data_ready;
311 dev->old_write_space = sk->sk_write_space;
312 sk->sk_state_change = gprs_state_change;
313 sk->sk_data_ready = gprs_data_ready;
314 sk->sk_write_space = gprs_write_space;
315 release_sock(sk);
316
317 sock_hold(sk);
318 dev->sk = sk;
319
320 printk(KERN_DEBUG"%s: attached\n", net->name);
321 gprs_write_space(sk); /* kick off TX */
322 return net->ifindex;
323
324out_rel:
325 release_sock(sk);
326 unregister_netdev(net);
327 return err;
328}
329
330void gprs_detach(struct sock *sk)
331{
332 struct gprs_dev *dev = sk->sk_user_data;
333 struct net_device *net = dev->net;
334
335 lock_sock(sk);
336 sk->sk_user_data = NULL;
337 sk->sk_state_change = dev->old_state_change;
338 sk->sk_data_ready = dev->old_data_ready;
339 sk->sk_write_space = dev->old_write_space;
340 release_sock(sk);
341
342 printk(KERN_DEBUG"%s: detached\n", net->name);
343 unregister_netdev(net);
344 flush_scheduled_work();
345 sock_put(sk);
346 skb_queue_purge(&dev->tx_queue);
347}
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
new file mode 100644
index 000000000000..bc6d50f83249
--- /dev/null
+++ b/net/phonet/pep.c
@@ -0,0 +1,1076 @@
1/*
2 * File: pep.c
3 *
4 * Phonet pipe protocol end point socket
5 *
6 * Copyright (C) 2008 Nokia Corporation.
7 *
8 * Author: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * version 2 as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA
23 */
24
25#include <linux/kernel.h>
26#include <linux/socket.h>
27#include <net/sock.h>
28#include <net/tcp_states.h>
29#include <asm/ioctls.h>
30
31#include <linux/phonet.h>
32#include <net/phonet/phonet.h>
33#include <net/phonet/pep.h>
34#include <net/phonet/gprs.h>
35
36/* sk_state values:
37 * TCP_CLOSE sock not in use yet
38 * TCP_CLOSE_WAIT disconnected pipe
39 * TCP_LISTEN listening pipe endpoint
40 * TCP_SYN_RECV connected pipe in disabled state
41 * TCP_ESTABLISHED connected pipe in enabled state
42 *
43 * pep_sock locking:
44 * - sk_state, ackq, hlist: sock lock needed
45 * - listener: read only
46 * - pipe_handle: read only
47 */
48
49#define CREDITS_MAX 10
50#define CREDITS_THR 7
51
52static const struct sockaddr_pn pipe_srv = {
53 .spn_family = AF_PHONET,
54 .spn_resource = 0xD9, /* pipe service */
55};
56
57#define pep_sb_size(s) (((s) + 5) & ~3) /* 2-bytes head, 32-bits aligned */
58
59/* Get the next TLV sub-block. */
60static unsigned char *pep_get_sb(struct sk_buff *skb, u8 *ptype, u8 *plen,
61 void *buf)
62{
63 void *data = NULL;
64 struct {
65 u8 sb_type;
66 u8 sb_len;
67 } *ph, h;
68 int buflen = *plen;
69
70 ph = skb_header_pointer(skb, 0, 2, &h);
71 if (ph == NULL || ph->sb_len < 2 || !pskb_may_pull(skb, ph->sb_len))
72 return NULL;
73 ph->sb_len -= 2;
74 *ptype = ph->sb_type;
75 *plen = ph->sb_len;
76
77 if (buflen > ph->sb_len)
78 buflen = ph->sb_len;
79 data = skb_header_pointer(skb, 2, buflen, buf);
80 __skb_pull(skb, 2 + ph->sb_len);
81 return data;
82}
83
84static int pep_reply(struct sock *sk, struct sk_buff *oskb,
85 u8 code, const void *data, int len, gfp_t priority)
86{
87 const struct pnpipehdr *oph = pnp_hdr(oskb);
88 struct pnpipehdr *ph;
89 struct sk_buff *skb;
90
91 skb = alloc_skb(MAX_PNPIPE_HEADER + len, priority);
92 if (!skb)
93 return -ENOMEM;
94 skb_set_owner_w(skb, sk);
95
96 skb_reserve(skb, MAX_PNPIPE_HEADER);
97 __skb_put(skb, len);
98 skb_copy_to_linear_data(skb, data, len);
99 __skb_push(skb, sizeof(*ph));
100 skb_reset_transport_header(skb);
101 ph = pnp_hdr(skb);
102 ph->utid = oph->utid;
103 ph->message_id = oph->message_id + 1; /* REQ -> RESP */
104 ph->pipe_handle = oph->pipe_handle;
105 ph->error_code = code;
106
107 return pn_skb_send(sk, skb, &pipe_srv);
108}
109
110#define PAD 0x00
111static int pep_accept_conn(struct sock *sk, struct sk_buff *skb)
112{
113 static const u8 data[20] = {
114 PAD, PAD, PAD, 2 /* sub-blocks */,
115 PN_PIPE_SB_REQUIRED_FC_TX, pep_sb_size(5), 3, PAD,
116 PN_MULTI_CREDIT_FLOW_CONTROL,
117 PN_ONE_CREDIT_FLOW_CONTROL,
118 PN_LEGACY_FLOW_CONTROL,
119 PAD,
120 PN_PIPE_SB_PREFERRED_FC_RX, pep_sb_size(5), 3, PAD,
121 PN_MULTI_CREDIT_FLOW_CONTROL,
122 PN_ONE_CREDIT_FLOW_CONTROL,
123 PN_LEGACY_FLOW_CONTROL,
124 PAD,
125 };
126
127 might_sleep();
128 return pep_reply(sk, skb, PN_PIPE_NO_ERROR, data, sizeof(data),
129 GFP_KERNEL);
130}
131
132static int pep_reject_conn(struct sock *sk, struct sk_buff *skb, u8 code)
133{
134 static const u8 data[4] = { PAD, PAD, PAD, 0 /* sub-blocks */ };
135 WARN_ON(code == PN_PIPE_NO_ERROR);
136 return pep_reply(sk, skb, code, data, sizeof(data), GFP_ATOMIC);
137}
138
139/* Control requests are not sent by the pipe service and have a specific
140 * message format. */
141static int pep_ctrlreq_error(struct sock *sk, struct sk_buff *oskb, u8 code,
142 gfp_t priority)
143{
144 const struct pnpipehdr *oph = pnp_hdr(oskb);
145 struct sk_buff *skb;
146 struct pnpipehdr *ph;
147 struct sockaddr_pn dst;
148
149 skb = alloc_skb(MAX_PNPIPE_HEADER + 4, priority);
150 if (!skb)
151 return -ENOMEM;
152 skb_set_owner_w(skb, sk);
153
154 skb_reserve(skb, MAX_PHONET_HEADER);
155 ph = (struct pnpipehdr *)skb_put(skb, sizeof(*ph) + 4);
156
157 ph->utid = oph->utid;
158 ph->message_id = PNS_PEP_CTRL_RESP;
159 ph->pipe_handle = oph->pipe_handle;
160 ph->data[0] = oph->data[1]; /* CTRL id */
161 ph->data[1] = oph->data[0]; /* PEP type */
162 ph->data[2] = code; /* error code, at an usual offset */
163 ph->data[3] = PAD;
164 ph->data[4] = PAD;
165
166 pn_skb_get_src_sockaddr(oskb, &dst);
167 return pn_skb_send(sk, skb, &dst);
168}
169
170static int pipe_snd_status(struct sock *sk, u8 type, u8 status, gfp_t priority)
171{
172 struct pep_sock *pn = pep_sk(sk);
173 struct pnpipehdr *ph;
174 struct sk_buff *skb;
175
176 skb = alloc_skb(MAX_PNPIPE_HEADER + 4, priority);
177 if (!skb)
178 return -ENOMEM;
179 skb_set_owner_w(skb, sk);
180
181 skb_reserve(skb, MAX_PNPIPE_HEADER + 4);
182 __skb_push(skb, sizeof(*ph) + 4);
183 skb_reset_transport_header(skb);
184 ph = pnp_hdr(skb);
185 ph->utid = 0;
186 ph->message_id = PNS_PEP_STATUS_IND;
187 ph->pipe_handle = pn->pipe_handle;
188 ph->pep_type = PN_PEP_TYPE_COMMON;
189 ph->data[1] = type;
190 ph->data[2] = PAD;
191 ph->data[3] = PAD;
192 ph->data[4] = status;
193
194 return pn_skb_send(sk, skb, &pipe_srv);
195}
196
197/* Send our RX flow control information to the sender.
198 * Socket must be locked. */
199static void pipe_grant_credits(struct sock *sk)
200{
201 struct pep_sock *pn = pep_sk(sk);
202
203 BUG_ON(sk->sk_state != TCP_ESTABLISHED);
204
205 switch (pn->rx_fc) {
206 case PN_LEGACY_FLOW_CONTROL: /* TODO */
207 break;
208 case PN_ONE_CREDIT_FLOW_CONTROL:
209 pipe_snd_status(sk, PN_PEP_IND_FLOW_CONTROL,
210 PEP_IND_READY, GFP_ATOMIC);
211 pn->rx_credits = 1;
212 break;
213 case PN_MULTI_CREDIT_FLOW_CONTROL:
214 if ((pn->rx_credits + CREDITS_THR) > CREDITS_MAX)
215 break;
216 if (pipe_snd_status(sk, PN_PEP_IND_ID_MCFC_GRANT_CREDITS,
217 CREDITS_MAX - pn->rx_credits,
218 GFP_ATOMIC) == 0)
219 pn->rx_credits = CREDITS_MAX;
220 break;
221 }
222}
223
224static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb)
225{
226 struct pep_sock *pn = pep_sk(sk);
227 struct pnpipehdr *hdr = pnp_hdr(skb);
228
229 if (!pskb_may_pull(skb, sizeof(*hdr) + 4))
230 return -EINVAL;
231
232 if (hdr->data[0] != PN_PEP_TYPE_COMMON) {
233 LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP type: %u\n",
234 (unsigned)hdr->data[0]);
235 return -EOPNOTSUPP;
236 }
237
238 switch (hdr->data[1]) {
239 case PN_PEP_IND_FLOW_CONTROL:
240 switch (pn->tx_fc) {
241 case PN_LEGACY_FLOW_CONTROL:
242 switch (hdr->data[4]) {
243 case PEP_IND_BUSY:
244 pn->tx_credits = 0;
245 break;
246 case PEP_IND_READY:
247 pn->tx_credits = 1;
248 break;
249 }
250 break;
251 case PN_ONE_CREDIT_FLOW_CONTROL:
252 if (hdr->data[4] == PEP_IND_READY)
253 pn->tx_credits = 1;
254 break;
255 }
256 break;
257
258 case PN_PEP_IND_ID_MCFC_GRANT_CREDITS:
259 if (pn->tx_fc != PN_MULTI_CREDIT_FLOW_CONTROL)
260 break;
261 if (pn->tx_credits + hdr->data[4] > 0xff)
262 pn->tx_credits = 0xff;
263 else
264 pn->tx_credits += hdr->data[4];
265 break;
266
267 default:
268 LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP indication: %u\n",
269 (unsigned)hdr->data[1]);
270 return -EOPNOTSUPP;
271 }
272 if (pn->tx_credits)
273 sk->sk_write_space(sk);
274 return 0;
275}
276
277static int pipe_rcv_created(struct sock *sk, struct sk_buff *skb)
278{
279 struct pep_sock *pn = pep_sk(sk);
280 struct pnpipehdr *hdr = pnp_hdr(skb);
281 u8 n_sb = hdr->data[0];
282
283 pn->rx_fc = pn->tx_fc = PN_LEGACY_FLOW_CONTROL;
284 __skb_pull(skb, sizeof(*hdr));
285 while (n_sb > 0) {
286 u8 type, buf[2], len = sizeof(buf);
287 u8 *data = pep_get_sb(skb, &type, &len, buf);
288
289 if (data == NULL)
290 return -EINVAL;
291 switch (type) {
292 case PN_PIPE_SB_NEGOTIATED_FC:
293 if (len < 2 || (data[0] | data[1]) > 3)
294 break;
295 pn->tx_fc = data[0] & 3;
296 pn->rx_fc = data[1] & 3;
297 break;
298 }
299 n_sb--;
300 }
301 return 0;
302}
303
304/* Queue an skb to a connected sock.
305 * Socket lock must be held. */
306static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb)
307{
308 struct pep_sock *pn = pep_sk(sk);
309 struct pnpipehdr *hdr = pnp_hdr(skb);
310 struct sk_buff_head *queue;
311 int err = 0;
312
313 BUG_ON(sk->sk_state == TCP_CLOSE_WAIT);
314
315 switch (hdr->message_id) {
316 case PNS_PEP_CONNECT_REQ:
317 pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE);
318 break;
319
320 case PNS_PEP_DISCONNECT_REQ:
321 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
322 sk->sk_state = TCP_CLOSE_WAIT;
323 if (!sock_flag(sk, SOCK_DEAD))
324 sk->sk_state_change(sk);
325 break;
326
327 case PNS_PEP_ENABLE_REQ:
328 /* Wait for PNS_PIPE_(ENABLED|REDIRECTED)_IND */
329 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
330 break;
331
332 case PNS_PEP_RESET_REQ:
333 switch (hdr->state_after_reset) {
334 case PN_PIPE_DISABLE:
335 pn->init_enable = 0;
336 break;
337 case PN_PIPE_ENABLE:
338 pn->init_enable = 1;
339 break;
340 default: /* not allowed to send an error here!? */
341 err = -EINVAL;
342 goto out;
343 }
344 /* fall through */
345 case PNS_PEP_DISABLE_REQ:
346 pn->tx_credits = 0;
347 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
348 break;
349
350 case PNS_PEP_CTRL_REQ:
351 if (skb_queue_len(&pn->ctrlreq_queue) >= PNPIPE_CTRLREQ_MAX)
352 break;
353 __skb_pull(skb, 4);
354 queue = &pn->ctrlreq_queue;
355 goto queue;
356
357 case PNS_PIPE_DATA:
358 __skb_pull(skb, 3); /* Pipe data header */
359 if (!pn_flow_safe(pn->rx_fc)) {
360 err = sock_queue_rcv_skb(sk, skb);
361 if (!err)
362 return 0;
363 break;
364 }
365
366 if (pn->rx_credits == 0) {
367 err = -ENOBUFS;
368 break;
369 }
370 pn->rx_credits--;
371 queue = &sk->sk_receive_queue;
372 goto queue;
373
374 case PNS_PEP_STATUS_IND:
375 pipe_rcv_status(sk, skb);
376 break;
377
378 case PNS_PIPE_REDIRECTED_IND:
379 err = pipe_rcv_created(sk, skb);
380 break;
381
382 case PNS_PIPE_CREATED_IND:
383 err = pipe_rcv_created(sk, skb);
384 if (err)
385 break;
386 /* fall through */
387 case PNS_PIPE_RESET_IND:
388 if (!pn->init_enable)
389 break;
390 /* fall through */
391 case PNS_PIPE_ENABLED_IND:
392 if (!pn_flow_safe(pn->tx_fc)) {
393 pn->tx_credits = 1;
394 sk->sk_write_space(sk);
395 }
396 if (sk->sk_state == TCP_ESTABLISHED)
397 break; /* Nothing to do */
398 sk->sk_state = TCP_ESTABLISHED;
399 pipe_grant_credits(sk);
400 break;
401
402 case PNS_PIPE_DISABLED_IND:
403 sk->sk_state = TCP_SYN_RECV;
404 pn->rx_credits = 0;
405 break;
406
407 default:
408 LIMIT_NETDEBUG(KERN_DEBUG"Phonet unknown PEP message: %u\n",
409 hdr->message_id);
410 err = -EINVAL;
411 }
412out:
413 kfree_skb(skb);
414 return err;
415
416queue:
417 skb->dev = NULL;
418 skb_set_owner_r(skb, sk);
419 err = skb->len;
420 skb_queue_tail(queue, skb);
421 if (!sock_flag(sk, SOCK_DEAD))
422 sk->sk_data_ready(sk, err);
423 return 0;
424}
425
426/* Destroy connected sock. */
427static void pipe_destruct(struct sock *sk)
428{
429 struct pep_sock *pn = pep_sk(sk);
430
431 skb_queue_purge(&sk->sk_receive_queue);
432 skb_queue_purge(&pn->ctrlreq_queue);
433}
434
435static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb)
436{
437 struct sock *newsk;
438 struct pep_sock *newpn, *pn = pep_sk(sk);
439 struct pnpipehdr *hdr;
440 struct sockaddr_pn dst;
441 u16 peer_type;
442 u8 pipe_handle, enabled, n_sb;
443
444 if (!pskb_pull(skb, sizeof(*hdr) + 4))
445 return -EINVAL;
446
447 hdr = pnp_hdr(skb);
448 pipe_handle = hdr->pipe_handle;
449 switch (hdr->state_after_connect) {
450 case PN_PIPE_DISABLE:
451 enabled = 0;
452 break;
453 case PN_PIPE_ENABLE:
454 enabled = 1;
455 break;
456 default:
457 pep_reject_conn(sk, skb, PN_PIPE_ERR_INVALID_PARAM);
458 return -EINVAL;
459 }
460 peer_type = hdr->other_pep_type << 8;
461
462 if (unlikely(sk->sk_state != TCP_LISTEN) || sk_acceptq_is_full(sk)) {
463 pep_reject_conn(sk, skb, PN_PIPE_ERR_PEP_IN_USE);
464 return -ENOBUFS;
465 }
466
467 /* Parse sub-blocks (options) */
468 n_sb = hdr->data[4];
469 while (n_sb > 0) {
470 u8 type, buf[1], len = sizeof(buf);
471 const u8 *data = pep_get_sb(skb, &type, &len, buf);
472
473 if (data == NULL)
474 return -EINVAL;
475 switch (type) {
476 case PN_PIPE_SB_CONNECT_REQ_PEP_SUB_TYPE:
477 if (len < 1)
478 return -EINVAL;
479 peer_type = (peer_type & 0xff00) | data[0];
480 break;
481 }
482 n_sb--;
483 }
484
485 skb = skb_clone(skb, GFP_ATOMIC);
486 if (!skb)
487 return -ENOMEM;
488
489 /* Create a new to-be-accepted sock */
490 newsk = sk_alloc(sock_net(sk), PF_PHONET, GFP_ATOMIC, sk->sk_prot);
491 if (!newsk) {
492 kfree_skb(skb);
493 return -ENOMEM;
494 }
495 sock_init_data(NULL, newsk);
496 newsk->sk_state = TCP_SYN_RECV;
497 newsk->sk_backlog_rcv = pipe_do_rcv;
498 newsk->sk_protocol = sk->sk_protocol;
499 newsk->sk_destruct = pipe_destruct;
500
501 newpn = pep_sk(newsk);
502 pn_skb_get_dst_sockaddr(skb, &dst);
503 newpn->pn_sk.sobject = pn_sockaddr_get_object(&dst);
504 newpn->pn_sk.resource = pn->pn_sk.resource;
505 skb_queue_head_init(&newpn->ctrlreq_queue);
506 newpn->pipe_handle = pipe_handle;
507 newpn->peer_type = peer_type;
508 newpn->rx_credits = newpn->tx_credits = 0;
509 newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL;
510 newpn->init_enable = enabled;
511
512 BUG_ON(!skb_queue_empty(&newsk->sk_receive_queue));
513 skb_queue_head(&newsk->sk_receive_queue, skb);
514 if (!sock_flag(sk, SOCK_DEAD))
515 sk->sk_data_ready(sk, 0);
516
517 sk_acceptq_added(sk);
518 sk_add_node(newsk, &pn->ackq);
519 return 0;
520}
521
522/* Listening sock must be locked */
523static struct sock *pep_find_pipe(const struct hlist_head *hlist,
524 const struct sockaddr_pn *dst,
525 u8 pipe_handle)
526{
527 struct hlist_node *node;
528 struct sock *sknode;
529 u16 dobj = pn_sockaddr_get_object(dst);
530
531 sk_for_each(sknode, node, hlist) {
532 struct pep_sock *pnnode = pep_sk(sknode);
533
534 /* Ports match, but addresses might not: */
535 if (pnnode->pn_sk.sobject != dobj)
536 continue;
537 if (pnnode->pipe_handle != pipe_handle)
538 continue;
539 if (sknode->sk_state == TCP_CLOSE_WAIT)
540 continue;
541
542 sock_hold(sknode);
543 return sknode;
544 }
545 return NULL;
546}
547
548/*
549 * Deliver an skb to a listening sock.
550 * Socket lock must be held.
551 * We then queue the skb to the right connected sock (if any).
552 */
553static int pep_do_rcv(struct sock *sk, struct sk_buff *skb)
554{
555 struct pep_sock *pn = pep_sk(sk);
556 struct sock *sknode;
557 struct pnpipehdr *hdr = pnp_hdr(skb);
558 struct sockaddr_pn dst;
559 int err = NET_RX_SUCCESS;
560 u8 pipe_handle;
561
562 if (!pskb_may_pull(skb, sizeof(*hdr)))
563 goto drop;
564
565 hdr = pnp_hdr(skb);
566 pipe_handle = hdr->pipe_handle;
567 if (pipe_handle == PN_PIPE_INVALID_HANDLE)
568 goto drop;
569
570 pn_skb_get_dst_sockaddr(skb, &dst);
571
572 /* Look for an existing pipe handle */
573 sknode = pep_find_pipe(&pn->hlist, &dst, pipe_handle);
574 if (sknode)
575 return sk_receive_skb(sknode, skb, 1);
576
577 /* Look for a pipe handle pending accept */
578 sknode = pep_find_pipe(&pn->ackq, &dst, pipe_handle);
579 if (sknode) {
580 sock_put(sknode);
581 if (net_ratelimit())
582 printk(KERN_WARNING"Phonet unconnected PEP ignored");
583 err = NET_RX_DROP;
584 goto drop;
585 }
586
587 switch (hdr->message_id) {
588 case PNS_PEP_CONNECT_REQ:
589 err = pep_connreq_rcv(sk, skb);
590 break;
591
592 case PNS_PEP_DISCONNECT_REQ:
593 pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC);
594 break;
595
596 case PNS_PEP_CTRL_REQ:
597 pep_ctrlreq_error(sk, skb, PN_PIPE_INVALID_HANDLE, GFP_ATOMIC);
598 break;
599
600 case PNS_PEP_RESET_REQ:
601 case PNS_PEP_ENABLE_REQ:
602 case PNS_PEP_DISABLE_REQ:
603 /* invalid handle is not even allowed here! */
604 default:
605 err = NET_RX_DROP;
606 }
607drop:
608 kfree_skb(skb);
609 return err;
610}
611
612/* associated socket ceases to exist */
613static void pep_sock_close(struct sock *sk, long timeout)
614{
615 struct pep_sock *pn = pep_sk(sk);
616 int ifindex = 0;
617
618 sk_common_release(sk);
619
620 lock_sock(sk);
621 if (sk->sk_state == TCP_LISTEN) {
622 /* Destroy the listen queue */
623 struct sock *sknode;
624 struct hlist_node *p, *n;
625
626 sk_for_each_safe(sknode, p, n, &pn->ackq)
627 sk_del_node_init(sknode);
628 sk->sk_state = TCP_CLOSE;
629 }
630 ifindex = pn->ifindex;
631 pn->ifindex = 0;
632 release_sock(sk);
633
634 if (ifindex)
635 gprs_detach(sk);
636}
637
638static int pep_wait_connreq(struct sock *sk, int noblock)
639{
640 struct task_struct *tsk = current;
641 struct pep_sock *pn = pep_sk(sk);
642 long timeo = sock_rcvtimeo(sk, noblock);
643
644 for (;;) {
645 DEFINE_WAIT(wait);
646
647 if (sk->sk_state != TCP_LISTEN)
648 return -EINVAL;
649 if (!hlist_empty(&pn->ackq))
650 break;
651 if (!timeo)
652 return -EWOULDBLOCK;
653 if (signal_pending(tsk))
654 return sock_intr_errno(timeo);
655
656 prepare_to_wait_exclusive(&sk->sk_socket->wait, &wait,
657 TASK_INTERRUPTIBLE);
658 release_sock(sk);
659 timeo = schedule_timeout(timeo);
660 lock_sock(sk);
661 finish_wait(&sk->sk_socket->wait, &wait);
662 }
663
664 return 0;
665}
666
667static struct sock *pep_sock_accept(struct sock *sk, int flags, int *errp)
668{
669 struct pep_sock *pn = pep_sk(sk);
670 struct sock *newsk = NULL;
671 struct sk_buff *oskb;
672 int err;
673
674 lock_sock(sk);
675 err = pep_wait_connreq(sk, flags & O_NONBLOCK);
676 if (err)
677 goto out;
678
679 newsk = __sk_head(&pn->ackq);
680
681 oskb = skb_dequeue(&newsk->sk_receive_queue);
682 err = pep_accept_conn(newsk, oskb);
683 if (err) {
684 skb_queue_head(&newsk->sk_receive_queue, oskb);
685 newsk = NULL;
686 goto out;
687 }
688
689 sock_hold(sk);
690 pep_sk(newsk)->listener = sk;
691
692 sock_hold(newsk);
693 sk_del_node_init(newsk);
694 sk_acceptq_removed(sk);
695 sk_add_node(newsk, &pn->hlist);
696 __sock_put(newsk);
697
698out:
699 release_sock(sk);
700 *errp = err;
701 return newsk;
702}
703
704static int pep_ioctl(struct sock *sk, int cmd, unsigned long arg)
705{
706 struct pep_sock *pn = pep_sk(sk);
707 int answ;
708
709 switch (cmd) {
710 case SIOCINQ:
711 if (sk->sk_state == TCP_LISTEN)
712 return -EINVAL;
713
714 lock_sock(sk);
715 if (sock_flag(sk, SOCK_URGINLINE)
716 && !skb_queue_empty(&pn->ctrlreq_queue))
717 answ = skb_peek(&pn->ctrlreq_queue)->len;
718 else if (!skb_queue_empty(&sk->sk_receive_queue))
719 answ = skb_peek(&sk->sk_receive_queue)->len;
720 else
721 answ = 0;
722 release_sock(sk);
723 return put_user(answ, (int __user *)arg);
724 }
725
726 return -ENOIOCTLCMD;
727}
728
729static int pep_init(struct sock *sk)
730{
731 struct pep_sock *pn = pep_sk(sk);
732
733 INIT_HLIST_HEAD(&pn->ackq);
734 INIT_HLIST_HEAD(&pn->hlist);
735 skb_queue_head_init(&pn->ctrlreq_queue);
736 pn->pipe_handle = PN_PIPE_INVALID_HANDLE;
737 return 0;
738}
739
740static int pep_setsockopt(struct sock *sk, int level, int optname,
741 char __user *optval, int optlen)
742{
743 struct pep_sock *pn = pep_sk(sk);
744 int val = 0, err = 0;
745
746 if (level != SOL_PNPIPE)
747 return -ENOPROTOOPT;
748 if (optlen >= sizeof(int)) {
749 if (get_user(val, (int __user *) optval))
750 return -EFAULT;
751 }
752
753 lock_sock(sk);
754 switch (optname) {
755 case PNPIPE_ENCAP:
756 if (val && val != PNPIPE_ENCAP_IP) {
757 err = -EINVAL;
758 break;
759 }
760 if (!pn->ifindex == !val)
761 break; /* Nothing to do! */
762 if (!capable(CAP_NET_ADMIN)) {
763 err = -EPERM;
764 break;
765 }
766 if (val) {
767 release_sock(sk);
768 err = gprs_attach(sk);
769 if (err > 0) {
770 pn->ifindex = err;
771 err = 0;
772 }
773 } else {
774 pn->ifindex = 0;
775 release_sock(sk);
776 gprs_detach(sk);
777 err = 0;
778 }
779 goto out_norel;
780 default:
781 err = -ENOPROTOOPT;
782 }
783 release_sock(sk);
784
785out_norel:
786 return err;
787}
788
789static int pep_getsockopt(struct sock *sk, int level, int optname,
790 char __user *optval, int __user *optlen)
791{
792 struct pep_sock *pn = pep_sk(sk);
793 int len, val;
794
795 if (level != SOL_PNPIPE)
796 return -ENOPROTOOPT;
797 if (get_user(len, optlen))
798 return -EFAULT;
799
800 switch (optname) {
801 case PNPIPE_ENCAP:
802 val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE;
803 break;
804 case PNPIPE_IFINDEX:
805 val = pn->ifindex;
806 break;
807 default:
808 return -ENOPROTOOPT;
809 }
810
811 len = min_t(unsigned int, sizeof(int), len);
812 if (put_user(len, optlen))
813 return -EFAULT;
814 if (put_user(val, (int __user *) optval))
815 return -EFAULT;
816 return 0;
817}
818
819static int pipe_skb_send(struct sock *sk, struct sk_buff *skb)
820{
821 struct pep_sock *pn = pep_sk(sk);
822 struct pnpipehdr *ph;
823
824 skb_push(skb, 3);
825 skb_reset_transport_header(skb);
826 ph = pnp_hdr(skb);
827 ph->utid = 0;
828 ph->message_id = PNS_PIPE_DATA;
829 ph->pipe_handle = pn->pipe_handle;
830 if (pn_flow_safe(pn->tx_fc) && pn->tx_credits)
831 pn->tx_credits--;
832
833 return pn_skb_send(sk, skb, &pipe_srv);
834}
835
836static int pep_sendmsg(struct kiocb *iocb, struct sock *sk,
837 struct msghdr *msg, size_t len)
838{
839 struct pep_sock *pn = pep_sk(sk);
840 struct sk_buff *skb = NULL;
841 long timeo;
842 int flags = msg->msg_flags;
843 int err, done;
844
845 if (msg->msg_flags & MSG_OOB || !(msg->msg_flags & MSG_EOR))
846 return -EOPNOTSUPP;
847
848 lock_sock(sk);
849 timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
850 if ((1 << sk->sk_state) & (TCPF_LISTEN|TCPF_CLOSE)) {
851 err = -ENOTCONN;
852 goto out;
853 }
854 if (sk->sk_state != TCP_ESTABLISHED) {
855 /* Wait until the pipe gets to enabled state */
856disabled:
857 err = sk_stream_wait_connect(sk, &timeo);
858 if (err)
859 goto out;
860
861 if (sk->sk_state == TCP_CLOSE_WAIT) {
862 err = -ECONNRESET;
863 goto out;
864 }
865 }
866 BUG_ON(sk->sk_state != TCP_ESTABLISHED);
867
868 /* Wait until flow control allows TX */
869 done = pn->tx_credits > 0;
870 while (!done) {
871 DEFINE_WAIT(wait);
872
873 if (!timeo) {
874 err = -EAGAIN;
875 goto out;
876 }
877 if (signal_pending(current)) {
878 err = sock_intr_errno(timeo);
879 goto out;
880 }
881
882 prepare_to_wait(&sk->sk_socket->wait, &wait,
883 TASK_INTERRUPTIBLE);
884 done = sk_wait_event(sk, &timeo, pn->tx_credits > 0);
885 finish_wait(&sk->sk_socket->wait, &wait);
886
887 if (sk->sk_state != TCP_ESTABLISHED)
888 goto disabled;
889 }
890
891 if (!skb) {
892 skb = sock_alloc_send_skb(sk, MAX_PNPIPE_HEADER + len,
893 flags & MSG_DONTWAIT, &err);
894 if (skb == NULL)
895 goto out;
896 skb_reserve(skb, MAX_PHONET_HEADER + 3);
897
898 if (sk->sk_state != TCP_ESTABLISHED || !pn->tx_credits)
899 goto disabled; /* sock_alloc_send_skb might sleep */
900 }
901
902 err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
903 if (err < 0)
904 goto out;
905
906 err = pipe_skb_send(sk, skb);
907 if (err >= 0)
908 err = len; /* success! */
909 skb = NULL;
910out:
911 release_sock(sk);
912 kfree_skb(skb);
913 return err;
914}
915
916int pep_writeable(struct sock *sk)
917{
918 struct pep_sock *pn = pep_sk(sk);
919
920 return (sk->sk_state == TCP_ESTABLISHED) ? pn->tx_credits : 0;
921}
922
923int pep_write(struct sock *sk, struct sk_buff *skb)
924{
925 struct sk_buff *rskb, *fs;
926 int flen = 0;
927
928 rskb = alloc_skb(MAX_PNPIPE_HEADER, GFP_ATOMIC);
929 if (!rskb) {
930 kfree_skb(skb);
931 return -ENOMEM;
932 }
933 skb_shinfo(rskb)->frag_list = skb;
934 rskb->len += skb->len;
935 rskb->data_len += rskb->len;
936 rskb->truesize += rskb->len;
937
938 /* Avoid nested fragments */
939 for (fs = skb_shinfo(skb)->frag_list; fs; fs = fs->next)
940 flen += fs->len;
941 skb->next = skb_shinfo(skb)->frag_list;
942 skb_shinfo(skb)->frag_list = NULL;
943 skb->len -= flen;
944 skb->data_len -= flen;
945 skb->truesize -= flen;
946
947 skb_reserve(rskb, MAX_PHONET_HEADER + 3);
948 return pipe_skb_send(sk, rskb);
949}
950
951struct sk_buff *pep_read(struct sock *sk)
952{
953 struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue);
954
955 if (sk->sk_state == TCP_ESTABLISHED)
956 pipe_grant_credits(sk);
957 return skb;
958}
959
960static int pep_recvmsg(struct kiocb *iocb, struct sock *sk,
961 struct msghdr *msg, size_t len, int noblock,
962 int flags, int *addr_len)
963{
964 struct sk_buff *skb;
965 int err;
966
967 if (unlikely(1 << sk->sk_state & (TCPF_LISTEN | TCPF_CLOSE)))
968 return -ENOTCONN;
969
970 if ((flags & MSG_OOB) || sock_flag(sk, SOCK_URGINLINE)) {
971 /* Dequeue and acknowledge control request */
972 struct pep_sock *pn = pep_sk(sk);
973
974 skb = skb_dequeue(&pn->ctrlreq_queue);
975 if (skb) {
976 pep_ctrlreq_error(sk, skb, PN_PIPE_NO_ERROR,
977 GFP_KERNEL);
978 msg->msg_flags |= MSG_OOB;
979 goto copy;
980 }
981 if (flags & MSG_OOB)
982 return -EINVAL;
983 }
984
985 skb = skb_recv_datagram(sk, flags, noblock, &err);
986 lock_sock(sk);
987 if (skb == NULL) {
988 if (err == -ENOTCONN && sk->sk_state == TCP_CLOSE_WAIT)
989 err = -ECONNRESET;
990 release_sock(sk);
991 return err;
992 }
993
994 if (sk->sk_state == TCP_ESTABLISHED)
995 pipe_grant_credits(sk);
996 release_sock(sk);
997copy:
998 msg->msg_flags |= MSG_EOR;
999 if (skb->len > len)
1000 msg->msg_flags |= MSG_TRUNC;
1001 else
1002 len = skb->len;
1003
1004 err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len);
1005 if (!err)
1006 err = (flags & MSG_TRUNC) ? skb->len : len;
1007
1008 skb_free_datagram(sk, skb);
1009 return err;
1010}
1011
1012static void pep_sock_unhash(struct sock *sk)
1013{
1014 struct pep_sock *pn = pep_sk(sk);
1015 struct sock *skparent = NULL;
1016
1017 lock_sock(sk);
1018 if ((1 << sk->sk_state) & ~(TCPF_CLOSE|TCPF_LISTEN)) {
1019 skparent = pn->listener;
1020 sk_del_node_init(sk);
1021 release_sock(sk);
1022
1023 sk = skparent;
1024 pn = pep_sk(skparent);
1025 lock_sock(sk);
1026 }
1027 /* Unhash a listening sock only when it is closed
1028 * and all of its active connected pipes are closed. */
1029 if (hlist_empty(&pn->hlist))
1030 pn_sock_unhash(&pn->pn_sk.sk);
1031 release_sock(sk);
1032
1033 if (skparent)
1034 sock_put(skparent);
1035}
1036
1037static struct proto pep_proto = {
1038 .close = pep_sock_close,
1039 .accept = pep_sock_accept,
1040 .ioctl = pep_ioctl,
1041 .init = pep_init,
1042 .setsockopt = pep_setsockopt,
1043 .getsockopt = pep_getsockopt,
1044 .sendmsg = pep_sendmsg,
1045 .recvmsg = pep_recvmsg,
1046 .backlog_rcv = pep_do_rcv,
1047 .hash = pn_sock_hash,
1048 .unhash = pep_sock_unhash,
1049 .get_port = pn_sock_get_port,
1050 .obj_size = sizeof(struct pep_sock),
1051 .owner = THIS_MODULE,
1052 .name = "PNPIPE",
1053};
1054
1055static struct phonet_protocol pep_pn_proto = {
1056 .ops = &phonet_stream_ops,
1057 .prot = &pep_proto,
1058 .sock_type = SOCK_SEQPACKET,
1059};
1060
1061static int __init pep_register(void)
1062{
1063 return phonet_proto_register(PN_PROTO_PIPE, &pep_pn_proto);
1064}
1065
1066static void __exit pep_unregister(void)
1067{
1068 phonet_proto_unregister(PN_PROTO_PIPE, &pep_pn_proto);
1069}
1070
1071module_init(pep_register);
1072module_exit(pep_unregister);
1073MODULE_AUTHOR("Remi Denis-Courmont, Nokia");
1074MODULE_DESCRIPTION("Phonet pipe protocol");
1075MODULE_LICENSE("GPL");
1076MODULE_ALIAS_NET_PF_PROTO(PF_PHONET, PN_PROTO_PIPE);
diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c
new file mode 100644
index 000000000000..53be9fc82aaa
--- /dev/null
+++ b/net/phonet/pn_dev.c
@@ -0,0 +1,208 @@
1/*
2 * File: pn_dev.c
3 *
4 * Phonet network device
5 *
6 * Copyright (C) 2008 Nokia Corporation.
7 *
8 * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
9 * Original author: Sakari Ailus <sakari.ailus@nokia.com>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * version 2 as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301 USA
24 */
25
26#include <linux/kernel.h>
27#include <linux/net.h>
28#include <linux/netdevice.h>
29#include <linux/phonet.h>
30#include <net/sock.h>
31#include <net/phonet/pn_dev.h>
32
33/* when accessing, remember to lock with spin_lock(&pndevs.lock); */
34struct phonet_device_list pndevs = {
35 .list = LIST_HEAD_INIT(pndevs.list),
36 .lock = __SPIN_LOCK_UNLOCKED(pndevs.lock),
37};
38
39/* Allocate new Phonet device. */
40static struct phonet_device *__phonet_device_alloc(struct net_device *dev)
41{
42 struct phonet_device *pnd = kmalloc(sizeof(*pnd), GFP_ATOMIC);
43 if (pnd == NULL)
44 return NULL;
45 pnd->netdev = dev;
46 bitmap_zero(pnd->addrs, 64);
47
48 list_add(&pnd->list, &pndevs.list);
49 return pnd;
50}
51
52static struct phonet_device *__phonet_get(struct net_device *dev)
53{
54 struct phonet_device *pnd;
55
56 list_for_each_entry(pnd, &pndevs.list, list) {
57 if (pnd->netdev == dev)
58 return pnd;
59 }
60 return NULL;
61}
62
63static void __phonet_device_free(struct phonet_device *pnd)
64{
65 list_del(&pnd->list);
66 kfree(pnd);
67}
68
69struct net_device *phonet_device_get(struct net *net)
70{
71 struct phonet_device *pnd;
72 struct net_device *dev;
73
74 spin_lock_bh(&pndevs.lock);
75 list_for_each_entry(pnd, &pndevs.list, list) {
76 dev = pnd->netdev;
77 BUG_ON(!dev);
78
79 if (dev_net(dev) == net &&
80 (dev->reg_state == NETREG_REGISTERED) &&
81 ((pnd->netdev->flags & IFF_UP)) == IFF_UP)
82 break;
83 dev = NULL;
84 }
85 if (dev)
86 dev_hold(dev);
87 spin_unlock_bh(&pndevs.lock);
88 return dev;
89}
90
91int phonet_address_add(struct net_device *dev, u8 addr)
92{
93 struct phonet_device *pnd;
94 int err = 0;
95
96 spin_lock_bh(&pndevs.lock);
97 /* Find or create Phonet-specific device data */
98 pnd = __phonet_get(dev);
99 if (pnd == NULL)
100 pnd = __phonet_device_alloc(dev);
101 if (unlikely(pnd == NULL))
102 err = -ENOMEM;
103 else if (test_and_set_bit(addr >> 2, pnd->addrs))
104 err = -EEXIST;
105 spin_unlock_bh(&pndevs.lock);
106 return err;
107}
108
109int phonet_address_del(struct net_device *dev, u8 addr)
110{
111 struct phonet_device *pnd;
112 int err = 0;
113
114 spin_lock_bh(&pndevs.lock);
115 pnd = __phonet_get(dev);
116 if (!pnd || !test_and_clear_bit(addr >> 2, pnd->addrs))
117 err = -EADDRNOTAVAIL;
118 if (bitmap_empty(pnd->addrs, 64))
119 __phonet_device_free(pnd);
120 spin_unlock_bh(&pndevs.lock);
121 return err;
122}
123
124/* Gets a source address toward a destination, through a interface. */
125u8 phonet_address_get(struct net_device *dev, u8 addr)
126{
127 struct phonet_device *pnd;
128
129 spin_lock_bh(&pndevs.lock);
130 pnd = __phonet_get(dev);
131 if (pnd) {
132 BUG_ON(bitmap_empty(pnd->addrs, 64));
133
134 /* Use same source address as destination, if possible */
135 if (!test_bit(addr >> 2, pnd->addrs))
136 addr = find_first_bit(pnd->addrs, 64) << 2;
137 } else
138 addr = PN_NO_ADDR;
139 spin_unlock_bh(&pndevs.lock);
140 return addr;
141}
142
143int phonet_address_lookup(u8 addr)
144{
145 struct phonet_device *pnd;
146
147 spin_lock_bh(&pndevs.lock);
148 list_for_each_entry(pnd, &pndevs.list, list) {
149 /* Don't allow unregistering devices! */
150 if ((pnd->netdev->reg_state != NETREG_REGISTERED) ||
151 ((pnd->netdev->flags & IFF_UP)) != IFF_UP)
152 continue;
153
154 if (test_bit(addr >> 2, pnd->addrs)) {
155 spin_unlock_bh(&pndevs.lock);
156 return 0;
157 }
158 }
159 spin_unlock_bh(&pndevs.lock);
160 return -EADDRNOTAVAIL;
161}
162
163/* notify Phonet of device events */
164static int phonet_device_notify(struct notifier_block *me, unsigned long what,
165 void *arg)
166{
167 struct net_device *dev = arg;
168
169 if (what == NETDEV_UNREGISTER) {
170 struct phonet_device *pnd;
171
172 /* Destroy phonet-specific device data */
173 spin_lock_bh(&pndevs.lock);
174 pnd = __phonet_get(dev);
175 if (pnd)
176 __phonet_device_free(pnd);
177 spin_unlock_bh(&pndevs.lock);
178 }
179 return 0;
180
181}
182
183static struct notifier_block phonet_device_notifier = {
184 .notifier_call = phonet_device_notify,
185 .priority = 0,
186};
187
188/* Initialize Phonet devices list */
189void phonet_device_init(void)
190{
191 register_netdevice_notifier(&phonet_device_notifier);
192}
193
194void phonet_device_exit(void)
195{
196 struct phonet_device *pnd, *n;
197
198 rtnl_unregister_all(PF_PHONET);
199 rtnl_lock();
200 spin_lock_bh(&pndevs.lock);
201
202 list_for_each_entry_safe(pnd, n, &pndevs.list, list)
203 __phonet_device_free(pnd);
204
205 spin_unlock_bh(&pndevs.lock);
206 rtnl_unlock();
207 unregister_netdevice_notifier(&phonet_device_notifier);
208}
diff --git a/net/phonet/pn_netlink.c b/net/phonet/pn_netlink.c
new file mode 100644
index 000000000000..b1770d66bc8d
--- /dev/null
+++ b/net/phonet/pn_netlink.c
@@ -0,0 +1,165 @@
1/*
2 * File: pn_netlink.c
3 *
4 * Phonet netlink interface
5 *
6 * Copyright (C) 2008 Nokia Corporation.
7 *
8 * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
9 * Original author: Sakari Ailus <sakari.ailus@nokia.com>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * version 2 as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301 USA
24 */
25
26#include <linux/kernel.h>
27#include <linux/netlink.h>
28#include <linux/phonet.h>
29#include <net/sock.h>
30#include <net/phonet/pn_dev.h>
31
32static int fill_addr(struct sk_buff *skb, struct net_device *dev, u8 addr,
33 u32 pid, u32 seq, int event);
34
35static void rtmsg_notify(int event, struct net_device *dev, u8 addr)
36{
37 struct sk_buff *skb;
38 int err = -ENOBUFS;
39
40 skb = nlmsg_new(NLMSG_ALIGN(sizeof(struct ifaddrmsg)) +
41 nla_total_size(1), GFP_KERNEL);
42 if (skb == NULL)
43 goto errout;
44 err = fill_addr(skb, dev, addr, 0, 0, event);
45 if (err < 0) {
46 WARN_ON(err == -EMSGSIZE);
47 kfree_skb(skb);
48 goto errout;
49 }
50 err = rtnl_notify(skb, dev_net(dev), 0,
51 RTNLGRP_PHONET_IFADDR, NULL, GFP_KERNEL);
52errout:
53 if (err < 0)
54 rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_IFADDR, err);
55}
56
57static const struct nla_policy ifa_phonet_policy[IFA_MAX+1] = {
58 [IFA_LOCAL] = { .type = NLA_U8 },
59};
60
61static int addr_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *attr)
62{
63 struct net *net = sock_net(skb->sk);
64 struct nlattr *tb[IFA_MAX+1];
65 struct net_device *dev;
66 struct ifaddrmsg *ifm;
67 int err;
68 u8 pnaddr;
69
70 if (!capable(CAP_SYS_ADMIN))
71 return -EPERM;
72
73 ASSERT_RTNL();
74
75 err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_phonet_policy);
76 if (err < 0)
77 return err;
78
79 ifm = nlmsg_data(nlh);
80 if (tb[IFA_LOCAL] == NULL)
81 return -EINVAL;
82 pnaddr = nla_get_u8(tb[IFA_LOCAL]);
83 if (pnaddr & 3)
84 /* Phonet addresses only have 6 high-order bits */
85 return -EINVAL;
86
87 dev = __dev_get_by_index(net, ifm->ifa_index);
88 if (dev == NULL)
89 return -ENODEV;
90
91 if (nlh->nlmsg_type == RTM_NEWADDR)
92 err = phonet_address_add(dev, pnaddr);
93 else
94 err = phonet_address_del(dev, pnaddr);
95 if (!err)
96 rtmsg_notify(nlh->nlmsg_type, dev, pnaddr);
97 return err;
98}
99
100static int fill_addr(struct sk_buff *skb, struct net_device *dev, u8 addr,
101 u32 pid, u32 seq, int event)
102{
103 struct ifaddrmsg *ifm;
104 struct nlmsghdr *nlh;
105
106 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*ifm), 0);
107 if (nlh == NULL)
108 return -EMSGSIZE;
109
110 ifm = nlmsg_data(nlh);
111 ifm->ifa_family = AF_PHONET;
112 ifm->ifa_prefixlen = 0;
113 ifm->ifa_flags = IFA_F_PERMANENT;
114 ifm->ifa_scope = RT_SCOPE_LINK;
115 ifm->ifa_index = dev->ifindex;
116 NLA_PUT_U8(skb, IFA_LOCAL, addr);
117 return nlmsg_end(skb, nlh);
118
119nla_put_failure:
120 nlmsg_cancel(skb, nlh);
121 return -EMSGSIZE;
122}
123
124static int getaddr_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
125{
126 struct phonet_device *pnd;
127 int dev_idx = 0, dev_start_idx = cb->args[0];
128 int addr_idx = 0, addr_start_idx = cb->args[1];
129
130 spin_lock_bh(&pndevs.lock);
131 list_for_each_entry(pnd, &pndevs.list, list) {
132 u8 addr;
133
134 if (dev_idx > dev_start_idx)
135 addr_start_idx = 0;
136 if (dev_idx++ < dev_start_idx)
137 continue;
138
139 addr_idx = 0;
140 for (addr = find_first_bit(pnd->addrs, 64); addr < 64;
141 addr = find_next_bit(pnd->addrs, 64, 1+addr)) {
142 if (addr_idx++ < addr_start_idx)
143 continue;
144
145 if (fill_addr(skb, pnd->netdev, addr << 2,
146 NETLINK_CB(cb->skb).pid,
147 cb->nlh->nlmsg_seq, RTM_NEWADDR))
148 goto out;
149 }
150 }
151
152out:
153 spin_unlock_bh(&pndevs.lock);
154 cb->args[0] = dev_idx;
155 cb->args[1] = addr_idx;
156
157 return skb->len;
158}
159
160void __init phonet_netlink_register(void)
161{
162 rtnl_register(PF_PHONET, RTM_NEWADDR, addr_doit, NULL);
163 rtnl_register(PF_PHONET, RTM_DELADDR, addr_doit, NULL);
164 rtnl_register(PF_PHONET, RTM_GETADDR, NULL, getaddr_dumpit);
165}
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
new file mode 100644
index 000000000000..d81740187fb4
--- /dev/null
+++ b/net/phonet/socket.c
@@ -0,0 +1,411 @@
1/*
2 * File: socket.c
3 *
4 * Phonet sockets
5 *
6 * Copyright (C) 2008 Nokia Corporation.
7 *
8 * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
9 * Original author: Sakari Ailus <sakari.ailus@nokia.com>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * version 2 as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301 USA
24 */
25
26#include <linux/kernel.h>
27#include <linux/net.h>
28#include <linux/poll.h>
29#include <net/sock.h>
30#include <net/tcp_states.h>
31
32#include <linux/phonet.h>
33#include <net/phonet/phonet.h>
34#include <net/phonet/pep.h>
35#include <net/phonet/pn_dev.h>
36
37static int pn_socket_release(struct socket *sock)
38{
39 struct sock *sk = sock->sk;
40
41 if (sk) {
42 sock->sk = NULL;
43 sk->sk_prot->close(sk, 0);
44 }
45 return 0;
46}
47
48static struct {
49 struct hlist_head hlist;
50 spinlock_t lock;
51} pnsocks = {
52 .hlist = HLIST_HEAD_INIT,
53 .lock = __SPIN_LOCK_UNLOCKED(pnsocks.lock),
54};
55
56/*
57 * Find address based on socket address, match only certain fields.
58 * Also grab sock if it was found. Remember to sock_put it later.
59 */
60struct sock *pn_find_sock_by_sa(const struct sockaddr_pn *spn)
61{
62 struct hlist_node *node;
63 struct sock *sknode;
64 struct sock *rval = NULL;
65 u16 obj = pn_sockaddr_get_object(spn);
66 u8 res = spn->spn_resource;
67
68 spin_lock_bh(&pnsocks.lock);
69
70 sk_for_each(sknode, node, &pnsocks.hlist) {
71 struct pn_sock *pn = pn_sk(sknode);
72 BUG_ON(!pn->sobject); /* unbound socket */
73
74 if (pn_port(obj)) {
75 /* Look up socket by port */
76 if (pn_port(pn->sobject) != pn_port(obj))
77 continue;
78 } else {
79 /* If port is zero, look up by resource */
80 if (pn->resource != res)
81 continue;
82 }
83 if (pn_addr(pn->sobject)
84 && pn_addr(pn->sobject) != pn_addr(obj))
85 continue;
86
87 rval = sknode;
88 sock_hold(sknode);
89 break;
90 }
91
92 spin_unlock_bh(&pnsocks.lock);
93
94 return rval;
95
96}
97
98void pn_sock_hash(struct sock *sk)
99{
100 spin_lock_bh(&pnsocks.lock);
101 sk_add_node(sk, &pnsocks.hlist);
102 spin_unlock_bh(&pnsocks.lock);
103}
104EXPORT_SYMBOL(pn_sock_hash);
105
106void pn_sock_unhash(struct sock *sk)
107{
108 spin_lock_bh(&pnsocks.lock);
109 sk_del_node_init(sk);
110 spin_unlock_bh(&pnsocks.lock);
111}
112EXPORT_SYMBOL(pn_sock_unhash);
113
114static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len)
115{
116 struct sock *sk = sock->sk;
117 struct pn_sock *pn = pn_sk(sk);
118 struct sockaddr_pn *spn = (struct sockaddr_pn *)addr;
119 int err;
120 u16 handle;
121 u8 saddr;
122
123 if (sk->sk_prot->bind)
124 return sk->sk_prot->bind(sk, addr, len);
125
126 if (len < sizeof(struct sockaddr_pn))
127 return -EINVAL;
128 if (spn->spn_family != AF_PHONET)
129 return -EAFNOSUPPORT;
130
131 handle = pn_sockaddr_get_object((struct sockaddr_pn *)addr);
132 saddr = pn_addr(handle);
133 if (saddr && phonet_address_lookup(saddr))
134 return -EADDRNOTAVAIL;
135
136 lock_sock(sk);
137 if (sk->sk_state != TCP_CLOSE || pn_port(pn->sobject)) {
138 err = -EINVAL; /* attempt to rebind */
139 goto out;
140 }
141 err = sk->sk_prot->get_port(sk, pn_port(handle));
142 if (err)
143 goto out;
144
145 /* get_port() sets the port, bind() sets the address if applicable */
146 pn->sobject = pn_object(saddr, pn_port(pn->sobject));
147 pn->resource = spn->spn_resource;
148
149 /* Enable RX on the socket */
150 sk->sk_prot->hash(sk);
151out:
152 release_sock(sk);
153 return err;
154}
155
156static int pn_socket_autobind(struct socket *sock)
157{
158 struct sockaddr_pn sa;
159 int err;
160
161 memset(&sa, 0, sizeof(sa));
162 sa.spn_family = AF_PHONET;
163 err = pn_socket_bind(sock, (struct sockaddr *)&sa,
164 sizeof(struct sockaddr_pn));
165 if (err != -EINVAL)
166 return err;
167 BUG_ON(!pn_port(pn_sk(sock->sk)->sobject));
168 return 0; /* socket was already bound */
169}
170
171static int pn_socket_accept(struct socket *sock, struct socket *newsock,
172 int flags)
173{
174 struct sock *sk = sock->sk;
175 struct sock *newsk;
176 int err;
177
178 newsk = sk->sk_prot->accept(sk, flags, &err);
179 if (!newsk)
180 return err;
181
182 lock_sock(newsk);
183 sock_graft(newsk, newsock);
184 newsock->state = SS_CONNECTED;
185 release_sock(newsk);
186 return 0;
187}
188
189static int pn_socket_getname(struct socket *sock, struct sockaddr *addr,
190 int *sockaddr_len, int peer)
191{
192 struct sock *sk = sock->sk;
193 struct pn_sock *pn = pn_sk(sk);
194
195 memset(addr, 0, sizeof(struct sockaddr_pn));
196 addr->sa_family = AF_PHONET;
197 if (!peer) /* Race with bind() here is userland's problem. */
198 pn_sockaddr_set_object((struct sockaddr_pn *)addr,
199 pn->sobject);
200
201 *sockaddr_len = sizeof(struct sockaddr_pn);
202 return 0;
203}
204
205static unsigned int pn_socket_poll(struct file *file, struct socket *sock,
206 poll_table *wait)
207{
208 struct sock *sk = sock->sk;
209 struct pep_sock *pn = pep_sk(sk);
210 unsigned int mask = 0;
211
212 poll_wait(file, &sock->wait, wait);
213
214 switch (sk->sk_state) {
215 case TCP_LISTEN:
216 return hlist_empty(&pn->ackq) ? 0 : POLLIN;
217 case TCP_CLOSE:
218 return POLLERR;
219 }
220
221 if (!skb_queue_empty(&sk->sk_receive_queue))
222 mask |= POLLIN | POLLRDNORM;
223 if (!skb_queue_empty(&pn->ctrlreq_queue))
224 mask |= POLLPRI;
225 if (!mask && sk->sk_state == TCP_CLOSE_WAIT)
226 return POLLHUP;
227
228 if (sk->sk_state == TCP_ESTABLISHED && pn->tx_credits)
229 mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
230
231 return mask;
232}
233
234static int pn_socket_ioctl(struct socket *sock, unsigned int cmd,
235 unsigned long arg)
236{
237 struct sock *sk = sock->sk;
238 struct pn_sock *pn = pn_sk(sk);
239
240 if (cmd == SIOCPNGETOBJECT) {
241 struct net_device *dev;
242 u16 handle;
243 u8 saddr;
244
245 if (get_user(handle, (__u16 __user *)arg))
246 return -EFAULT;
247
248 lock_sock(sk);
249 if (sk->sk_bound_dev_if)
250 dev = dev_get_by_index(sock_net(sk),
251 sk->sk_bound_dev_if);
252 else
253 dev = phonet_device_get(sock_net(sk));
254 if (dev && (dev->flags & IFF_UP))
255 saddr = phonet_address_get(dev, pn_addr(handle));
256 else
257 saddr = PN_NO_ADDR;
258 release_sock(sk);
259
260 if (dev)
261 dev_put(dev);
262 if (saddr == PN_NO_ADDR)
263 return -EHOSTUNREACH;
264
265 handle = pn_object(saddr, pn_port(pn->sobject));
266 return put_user(handle, (__u16 __user *)arg);
267 }
268
269 return sk->sk_prot->ioctl(sk, cmd, arg);
270}
271
272static int pn_socket_listen(struct socket *sock, int backlog)
273{
274 struct sock *sk = sock->sk;
275 int err = 0;
276
277 if (sock->state != SS_UNCONNECTED)
278 return -EINVAL;
279 if (pn_socket_autobind(sock))
280 return -ENOBUFS;
281
282 lock_sock(sk);
283 if (sk->sk_state != TCP_CLOSE) {
284 err = -EINVAL;
285 goto out;
286 }
287
288 sk->sk_state = TCP_LISTEN;
289 sk->sk_ack_backlog = 0;
290 sk->sk_max_ack_backlog = backlog;
291out:
292 release_sock(sk);
293 return err;
294}
295
296static int pn_socket_sendmsg(struct kiocb *iocb, struct socket *sock,
297 struct msghdr *m, size_t total_len)
298{
299 struct sock *sk = sock->sk;
300
301 if (pn_socket_autobind(sock))
302 return -EAGAIN;
303
304 return sk->sk_prot->sendmsg(iocb, sk, m, total_len);
305}
306
307const struct proto_ops phonet_dgram_ops = {
308 .family = AF_PHONET,
309 .owner = THIS_MODULE,
310 .release = pn_socket_release,
311 .bind = pn_socket_bind,
312 .connect = sock_no_connect,
313 .socketpair = sock_no_socketpair,
314 .accept = sock_no_accept,
315 .getname = pn_socket_getname,
316 .poll = datagram_poll,
317 .ioctl = pn_socket_ioctl,
318 .listen = sock_no_listen,
319 .shutdown = sock_no_shutdown,
320 .setsockopt = sock_no_setsockopt,
321 .getsockopt = sock_no_getsockopt,
322#ifdef CONFIG_COMPAT
323 .compat_setsockopt = sock_no_setsockopt,
324 .compat_getsockopt = sock_no_getsockopt,
325#endif
326 .sendmsg = pn_socket_sendmsg,
327 .recvmsg = sock_common_recvmsg,
328 .mmap = sock_no_mmap,
329 .sendpage = sock_no_sendpage,
330};
331
332const struct proto_ops phonet_stream_ops = {
333 .family = AF_PHONET,
334 .owner = THIS_MODULE,
335 .release = pn_socket_release,
336 .bind = pn_socket_bind,
337 .connect = sock_no_connect,
338 .socketpair = sock_no_socketpair,
339 .accept = pn_socket_accept,
340 .getname = pn_socket_getname,
341 .poll = pn_socket_poll,
342 .ioctl = pn_socket_ioctl,
343 .listen = pn_socket_listen,
344 .shutdown = sock_no_shutdown,
345 .setsockopt = sock_common_setsockopt,
346 .getsockopt = sock_common_getsockopt,
347#ifdef CONFIG_COMPAT
348 .compat_setsockopt = compat_sock_common_setsockopt,
349 .compat_getsockopt = compat_sock_common_getsockopt,
350#endif
351 .sendmsg = pn_socket_sendmsg,
352 .recvmsg = sock_common_recvmsg,
353 .mmap = sock_no_mmap,
354 .sendpage = sock_no_sendpage,
355};
356EXPORT_SYMBOL(phonet_stream_ops);
357
358static DEFINE_MUTEX(port_mutex);
359
360/* allocate port for a socket */
361int pn_sock_get_port(struct sock *sk, unsigned short sport)
362{
363 static int port_cur;
364 struct pn_sock *pn = pn_sk(sk);
365 struct sockaddr_pn try_sa;
366 struct sock *tmpsk;
367
368 memset(&try_sa, 0, sizeof(struct sockaddr_pn));
369 try_sa.spn_family = AF_PHONET;
370
371 mutex_lock(&port_mutex);
372
373 if (!sport) {
374 /* search free port */
375 int port, pmin, pmax;
376
377 phonet_get_local_port_range(&pmin, &pmax);
378 for (port = pmin; port <= pmax; port++) {
379 port_cur++;
380 if (port_cur < pmin || port_cur > pmax)
381 port_cur = pmin;
382
383 pn_sockaddr_set_port(&try_sa, port_cur);
384 tmpsk = pn_find_sock_by_sa(&try_sa);
385 if (tmpsk == NULL) {
386 sport = port_cur;
387 goto found;
388 } else
389 sock_put(tmpsk);
390 }
391 } else {
392 /* try to find specific port */
393 pn_sockaddr_set_port(&try_sa, sport);
394 tmpsk = pn_find_sock_by_sa(&try_sa);
395 if (tmpsk == NULL)
396 /* No sock there! We can use that port... */
397 goto found;
398 else
399 sock_put(tmpsk);
400 }
401 mutex_unlock(&port_mutex);
402
403 /* the port must be in use already */
404 return -EADDRINUSE;
405
406found:
407 mutex_unlock(&port_mutex);
408 pn->sobject = pn_object(pn_addr(pn->sobject), sport);
409 return 0;
410}
411EXPORT_SYMBOL(pn_sock_get_port);
diff --git a/net/phonet/sysctl.c b/net/phonet/sysctl.c
new file mode 100644
index 000000000000..600a4309b8c8
--- /dev/null
+++ b/net/phonet/sysctl.c
@@ -0,0 +1,113 @@
1/*
2 * File: sysctl.c
3 *
4 * Phonet /proc/sys/net/phonet interface implementation
5 *
6 * Copyright (C) 2008 Nokia Corporation.
7 *
8 * Contact: Remi Denis-Courmont <remi.denis-courmont@nokia.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * version 2 as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA
23 */
24
25#include <linux/seqlock.h>
26#include <linux/sysctl.h>
27#include <linux/errno.h>
28#include <linux/init.h>
29
30#define DYNAMIC_PORT_MIN 0x40
31#define DYNAMIC_PORT_MAX 0x7f
32
33static DEFINE_SEQLOCK(local_port_range_lock);
34static int local_port_range_min[2] = {0, 0};
35static int local_port_range_max[2] = {1023, 1023};
36static int local_port_range[2] = {DYNAMIC_PORT_MIN, DYNAMIC_PORT_MAX};
37static struct ctl_table_header *phonet_table_hrd;
38
39static void set_local_port_range(int range[2])
40{
41 write_seqlock(&local_port_range_lock);
42 local_port_range[0] = range[0];
43 local_port_range[1] = range[1];
44 write_sequnlock(&local_port_range_lock);
45}
46
47void phonet_get_local_port_range(int *min, int *max)
48{
49 unsigned seq;
50 do {
51 seq = read_seqbegin(&local_port_range_lock);
52 if (min)
53 *min = local_port_range[0];
54 if (max)
55 *max = local_port_range[1];
56 } while (read_seqretry(&local_port_range_lock, seq));
57}
58
59static int proc_local_port_range(ctl_table *table, int write, struct file *filp,
60 void __user *buffer,
61 size_t *lenp, loff_t *ppos)
62{
63 int ret;
64 int range[2] = {local_port_range[0], local_port_range[1]};
65 ctl_table tmp = {
66 .data = &range,
67 .maxlen = sizeof(range),
68 .mode = table->mode,
69 .extra1 = &local_port_range_min,
70 .extra2 = &local_port_range_max,
71 };
72
73 ret = proc_dointvec_minmax(&tmp, write, filp, buffer, lenp, ppos);
74
75 if (write && ret == 0) {
76 if (range[1] < range[0])
77 ret = -EINVAL;
78 else
79 set_local_port_range(range);
80 }
81
82 return ret;
83}
84
85static struct ctl_table phonet_table[] = {
86 {
87 .ctl_name = CTL_UNNUMBERED,
88 .procname = "local_port_range",
89 .data = &local_port_range,
90 .maxlen = sizeof(local_port_range),
91 .mode = 0644,
92 .proc_handler = &proc_local_port_range,
93 .strategy = NULL,
94 },
95 { .ctl_name = 0 }
96};
97
98struct ctl_path phonet_ctl_path[] = {
99 { .procname = "net", .ctl_name = CTL_NET, },
100 { .procname = "phonet", .ctl_name = CTL_UNNUMBERED, },
101 { },
102};
103
104int __init phonet_sysctl_init(void)
105{
106 phonet_table_hrd = register_sysctl_paths(phonet_ctl_path, phonet_table);
107 return phonet_table_hrd == NULL ? -ENOMEM : 0;
108}
109
110void phonet_sysctl_exit(void)
111{
112 unregister_sysctl_table(phonet_table_hrd);
113}