Phonet: common socket glue
[linux-2.6.git] / net / phonet / af_phonet.c
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
36 static struct net_proto_family phonet_proto_family;
37 static struct phonet_protocol *phonet_proto_get(int protocol);
38 static inline void phonet_proto_put(struct phonet_protocol *pp);
39
40 /* protocol family functions */
41
42 static 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                 default:
62                         return -EPROTONOSUPPORT;
63                 }
64         }
65
66         pnp = phonet_proto_get(protocol);
67         if (pnp == NULL)
68                 return -EPROTONOSUPPORT;
69         if (sock->type != pnp->sock_type) {
70                 err = -EPROTONOSUPPORT;
71                 goto out;
72         }
73
74         sk = sk_alloc(net, PF_PHONET, GFP_KERNEL, pnp->prot);
75         if (sk == NULL) {
76                 err = -ENOMEM;
77                 goto out;
78         }
79
80         sock_init_data(sock, sk);
81         sock->state = SS_UNCONNECTED;
82         sock->ops = pnp->ops;
83         sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
84         sk->sk_protocol = protocol;
85         pn = pn_sk(sk);
86         pn->sobject = 0;
87         pn->resource = 0;
88         sk->sk_prot->init(sk);
89         err = 0;
90
91 out:
92         phonet_proto_put(pnp);
93         return err;
94 }
95
96 static struct net_proto_family phonet_proto_family = {
97         .family = AF_PHONET,
98         .create = pn_socket_create,
99         .owner = THIS_MODULE,
100 };
101
102 /* packet type functions */
103
104 /*
105  * Stuff received packets to associated sockets.
106  * On error, returns non-zero and releases the skb.
107  */
108 static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
109                         struct packet_type *pkttype,
110                         struct net_device *orig_dev)
111 {
112         struct phonethdr *ph;
113         struct sock *sk;
114         struct sockaddr_pn sa;
115         u16 len;
116
117         if (dev_net(dev) != &init_net)
118                 goto out;
119
120         /* check we have at least a full Phonet header */
121         if (!pskb_pull(skb, sizeof(struct phonethdr)))
122                 goto out;
123
124         /* check that the advertised length is correct */
125         ph = pn_hdr(skb);
126         len = get_unaligned_be16(&ph->pn_length);
127         if (len < 2)
128                 goto out;
129         len -= 2;
130         if ((len > skb->len) || pskb_trim(skb, len))
131                 goto out;
132         skb_reset_transport_header(skb);
133
134         pn_skb_get_dst_sockaddr(skb, &sa);
135         if (pn_sockaddr_get_addr(&sa) == 0)
136                 goto out; /* currently, we cannot be device 0 */
137
138         sk = pn_find_sock_by_sa(&sa);
139         if (sk == NULL)
140                 goto out;
141
142         /* Push data to the socket (or other sockets connected to it). */
143         return sk_receive_skb(sk, skb, 0);
144
145 out:
146         kfree_skb(skb);
147         return NET_RX_DROP;
148 }
149
150 static struct packet_type phonet_packet_type = {
151         .type = __constant_htons(ETH_P_PHONET),
152         .dev = NULL,
153         .func = phonet_rcv,
154 };
155
156 /* Transport protocol registration */
157 static struct phonet_protocol *proto_tab[PHONET_NPROTO] __read_mostly;
158 static DEFINE_SPINLOCK(proto_tab_lock);
159
160 int __init_or_module phonet_proto_register(int protocol,
161                                                 struct phonet_protocol *pp)
162 {
163         int err = 0;
164
165         if (protocol >= PHONET_NPROTO)
166                 return -EINVAL;
167
168         err = proto_register(pp->prot, 1);
169         if (err)
170                 return err;
171
172         spin_lock(&proto_tab_lock);
173         if (proto_tab[protocol])
174                 err = -EBUSY;
175         else
176                 proto_tab[protocol] = pp;
177         spin_unlock(&proto_tab_lock);
178
179         return err;
180 }
181 EXPORT_SYMBOL(phonet_proto_register);
182
183 void phonet_proto_unregister(int protocol, struct phonet_protocol *pp)
184 {
185         spin_lock(&proto_tab_lock);
186         BUG_ON(proto_tab[protocol] != pp);
187         proto_tab[protocol] = NULL;
188         spin_unlock(&proto_tab_lock);
189         proto_unregister(pp->prot);
190 }
191 EXPORT_SYMBOL(phonet_proto_unregister);
192
193 static struct phonet_protocol *phonet_proto_get(int protocol)
194 {
195         struct phonet_protocol *pp;
196
197         if (protocol >= PHONET_NPROTO)
198                 return NULL;
199
200         spin_lock(&proto_tab_lock);
201         pp = proto_tab[protocol];
202         if (pp && !try_module_get(pp->prot->owner))
203                 pp = NULL;
204         spin_unlock(&proto_tab_lock);
205
206         return pp;
207 }
208
209 static inline void phonet_proto_put(struct phonet_protocol *pp)
210 {
211         module_put(pp->prot->owner);
212 }
213
214 /* Module registration */
215 static int __init phonet_init(void)
216 {
217         int err;
218
219         err = sock_register(&phonet_proto_family);
220         if (err) {
221                 printk(KERN_ALERT
222                         "phonet protocol family initialization failed\n");
223                 return err;
224         }
225
226         phonet_device_init();
227         dev_add_pack(&phonet_packet_type);
228         phonet_netlink_register();
229         return 0;
230 }
231
232 static void __exit phonet_exit(void)
233 {
234         sock_unregister(AF_PHONET);
235         dev_remove_pack(&phonet_packet_type);
236         phonet_device_exit();
237 }
238
239 module_init(phonet_init);
240 module_exit(phonet_exit);
241 MODULE_DESCRIPTION("Phonet protocol stack for Linux");
242 MODULE_LICENSE("GPL");