blob: d82ffe54cd55a4197ef593ab927bd5c5d7adc122 [file] [log] [blame]
Karthikeyan Ramasubramanian1df33cc2012-01-30 14:54:17 -07001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/module.h>
14#include <linux/types.h>
15#include <linux/net.h>
16#include <linux/socket.h>
17#include <linux/errno.h>
18#include <linux/mm.h>
19#include <linux/poll.h>
20#include <linux/fcntl.h>
21#include <linux/gfp.h>
22#include <linux/msm_ipc.h>
23
Karthikeyan Ramasubramanian98ee1d52012-04-13 09:24:55 -060024#ifdef CONFIG_ANDROID_PARANOID_NETWORK
25#include <linux/android_aid.h>
26#endif
27
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028#include <asm/string.h>
29#include <asm/atomic.h>
30
31#include <net/sock.h>
32
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070033#include "ipc_router.h"
34
35#define msm_ipc_sk(sk) ((struct msm_ipc_sock *)(sk))
36#define msm_ipc_sk_port(sk) ((struct msm_ipc_port *)(msm_ipc_sk(sk)->port))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070037
38static int sockets_enabled;
39static struct proto msm_ipc_proto;
40static const struct proto_ops msm_ipc_proto_ops;
41
Karthikeyan Ramasubramanian98ee1d52012-04-13 09:24:55 -060042#ifdef CONFIG_ANDROID_PARANOID_NETWORK
43static inline int check_permissions(void)
44{
45 int rc = 0;
46 if (!current_euid() || in_egroup_p(AID_NET_RAW))
47 rc = 1;
48 return rc;
49}
50# else
51static inline int check_permissions(void)
52{
53 return 1;
54}
55#endif
56
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070057static struct sk_buff_head *msm_ipc_router_build_msg(unsigned int num_sect,
58 struct iovec const *msg_sect,
59 size_t total_len)
60{
61 struct sk_buff_head *msg_head;
62 struct sk_buff *msg;
63 int i, copied, first = 1;
64 int data_size = 0, request_size, offset;
65 void *data;
66
67 for (i = 0; i < num_sect; i++)
68 data_size += msg_sect[i].iov_len;
69
70 if (!data_size)
71 return NULL;
72
73 msg_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
74 if (!msg_head) {
75 pr_err("%s: cannot allocate skb_head\n", __func__);
76 return NULL;
77 }
78 skb_queue_head_init(msg_head);
79
80 for (copied = 1, i = 0; copied && (i < num_sect); i++) {
81 data_size = msg_sect[i].iov_len;
82 offset = 0;
83 while (offset != msg_sect[i].iov_len) {
84 request_size = data_size;
85 if (first)
86 request_size += IPC_ROUTER_HDR_SIZE;
87
88 msg = alloc_skb(request_size, GFP_KERNEL);
89 if (!msg) {
90 if (request_size <= (PAGE_SIZE/2)) {
91 pr_err("%s: cannot allocated skb\n",
92 __func__);
93 goto msg_build_failure;
94 }
95 data_size = data_size / 2;
96 continue;
97 }
98
99 if (first) {
100 skb_reserve(msg, IPC_ROUTER_HDR_SIZE);
101 first = 0;
102 }
103
104 data = skb_put(msg, data_size);
105 copied = !copy_from_user(msg->data,
106 msg_sect[i].iov_base + offset,
107 data_size);
108 if (!copied) {
109 pr_err("%s: copy_from_user failed\n",
110 __func__);
111 kfree_skb(msg);
112 goto msg_build_failure;
113 }
114 skb_queue_tail(msg_head, msg);
115 offset += data_size;
116 data_size = msg_sect[i].iov_len - offset;
117 }
118 }
119 return msg_head;
120
121msg_build_failure:
122 while (!skb_queue_empty(msg_head)) {
123 msg = skb_dequeue(msg_head);
124 kfree_skb(msg);
125 }
126 kfree(msg_head);
127 return NULL;
128}
129
130static int msm_ipc_router_extract_msg(struct msghdr *m,
131 struct sk_buff_head *msg_head)
132{
133 struct sockaddr_msm_ipc *addr = (struct sockaddr_msm_ipc *)m->msg_name;
134 struct rr_header *hdr;
135 struct sk_buff *temp;
136 int offset = 0, data_len = 0, copy_len;
137
138 if (!m || !msg_head) {
139 pr_err("%s: Invalid pointers passed\n", __func__);
140 return -EINVAL;
141 }
142
143 temp = skb_peek(msg_head);
144 hdr = (struct rr_header *)(temp->data);
145 if (addr || (hdr->src_port_id != IPC_ROUTER_ADDRESS)) {
146 addr->family = AF_MSM_IPC;
147 addr->address.addrtype = MSM_IPC_ADDR_ID;
148 addr->address.addr.port_addr.node_id = hdr->src_node_id;
149 addr->address.addr.port_addr.port_id = hdr->src_port_id;
150 m->msg_namelen = sizeof(struct sockaddr_msm_ipc);
151 }
152
153 data_len = hdr->size;
154 skb_pull(temp, IPC_ROUTER_HDR_SIZE);
155 skb_queue_walk(msg_head, temp) {
156 copy_len = data_len < temp->len ? data_len : temp->len;
157 if (copy_to_user(m->msg_iov->iov_base + offset, temp->data,
158 copy_len)) {
159 pr_err("%s: Copy to user failed\n", __func__);
160 return -EFAULT;
161 }
162 offset += copy_len;
163 data_len -= copy_len;
164 }
165 return offset;
166}
167
168static void msm_ipc_router_release_msg(struct sk_buff_head *msg_head)
169{
170 struct sk_buff *temp;
171
172 if (!msg_head) {
173 pr_err("%s: Invalid msg pointer\n", __func__);
174 return;
175 }
176
177 while (!skb_queue_empty(msg_head)) {
178 temp = skb_dequeue(msg_head);
179 kfree_skb(temp);
180 }
181 kfree(msg_head);
182}
183
184static int msm_ipc_router_create(struct net *net,
185 struct socket *sock,
186 int protocol,
187 int kern)
188{
189 struct sock *sk;
190 struct msm_ipc_port *port_ptr;
191 void *pil;
192
Karthikeyan Ramasubramanian98ee1d52012-04-13 09:24:55 -0600193 if (!check_permissions()) {
194 pr_err("%s: Do not have permissions\n", __func__);
195 return -EPERM;
196 }
197
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700198 if (unlikely(protocol != 0)) {
199 pr_err("%s: Protocol not supported\n", __func__);
200 return -EPROTONOSUPPORT;
201 }
202
203 switch (sock->type) {
204 case SOCK_DGRAM:
205 break;
206 default:
207 pr_err("%s: Protocol type not supported\n", __func__);
208 return -EPROTOTYPE;
209 }
210
211 sk = sk_alloc(net, AF_MSM_IPC, GFP_KERNEL, &msm_ipc_proto);
212 if (!sk) {
213 pr_err("%s: sk_alloc failed\n", __func__);
214 return -ENOMEM;
215 }
216
217 port_ptr = msm_ipc_router_create_raw_port(sk, NULL, NULL);
218 if (!port_ptr) {
219 pr_err("%s: port_ptr alloc failed\n", __func__);
220 sk_free(sk);
221 return -ENOMEM;
222 }
223
224 sock->ops = &msm_ipc_proto_ops;
225 sock_init_data(sock, sk);
226 sk->sk_rcvtimeo = DEFAULT_RCV_TIMEO;
227
Karthikeyan Ramasubramanian6b963bd2012-05-01 11:27:54 -0600228 pil = msm_ipc_load_default_node();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700229 msm_ipc_sk(sk)->port = port_ptr;
Karthikeyan Ramasubramanian6b963bd2012-05-01 11:27:54 -0600230 msm_ipc_sk(sk)->default_pil = pil;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700231
232 return 0;
233}
234
235int msm_ipc_router_bind(struct socket *sock, struct sockaddr *uaddr,
236 int uaddr_len)
237{
238 struct sockaddr_msm_ipc *addr = (struct sockaddr_msm_ipc *)uaddr;
239 struct sock *sk = sock->sk;
240 struct msm_ipc_port *port_ptr;
241 int ret;
242
243 if (!sk)
244 return -EINVAL;
245
246 if (!uaddr_len) {
247 pr_err("%s: Invalid address length\n", __func__);
248 return -EINVAL;
249 }
250
251 if (addr->family != AF_MSM_IPC) {
252 pr_err("%s: Address family is incorrect\n", __func__);
253 return -EAFNOSUPPORT;
254 }
255
256 if (addr->address.addrtype != MSM_IPC_ADDR_NAME) {
257 pr_err("%s: Address type is incorrect\n", __func__);
258 return -EINVAL;
259 }
260
261 port_ptr = msm_ipc_sk_port(sk);
262 if (!port_ptr)
263 return -ENODEV;
264
265 lock_sock(sk);
266
267 ret = msm_ipc_router_register_server(port_ptr, &addr->address);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268
269 release_sock(sk);
270 return ret;
271}
272
273static int msm_ipc_router_sendmsg(struct kiocb *iocb, struct socket *sock,
274 struct msghdr *m, size_t total_len)
275{
276 struct sock *sk = sock->sk;
277 struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
278 struct sockaddr_msm_ipc *dest = (struct sockaddr_msm_ipc *)m->msg_name;
279 struct sk_buff_head *msg;
280 int ret;
281
282 if (!dest)
283 return -EDESTADDRREQ;
284
285 if (m->msg_namelen < sizeof(*dest) || dest->family != AF_MSM_IPC)
286 return -EINVAL;
287
288 if (total_len > MAX_IPC_PKT_SIZE)
289 return -EINVAL;
290
291 lock_sock(sk);
292 msg = msm_ipc_router_build_msg(m->msg_iovlen, m->msg_iov, total_len);
293 if (!msg) {
294 pr_err("%s: Msg build failure\n", __func__);
295 ret = -ENOMEM;
296 goto out_sendmsg;
297 }
298
299 ret = msm_ipc_router_send_to(port_ptr, msg, &dest->address);
300 if (ret == (IPC_ROUTER_HDR_SIZE + total_len))
301 ret = total_len;
302
303out_sendmsg:
304 release_sock(sk);
305 return ret;
306}
307
308static int msm_ipc_router_recvmsg(struct kiocb *iocb, struct socket *sock,
309 struct msghdr *m, size_t buf_len, int flags)
310{
311 struct sock *sk = sock->sk;
312 struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
313 struct sk_buff_head *msg;
314 long timeout;
315 int ret;
316
317 if (m->msg_iovlen != 1)
318 return -EOPNOTSUPP;
319
320 if (!buf_len)
321 return -EINVAL;
322
323 lock_sock(sk);
324 timeout = sk->sk_rcvtimeo;
325 mutex_lock(&port_ptr->port_rx_q_lock);
326 while (list_empty(&port_ptr->port_rx_q)) {
327 mutex_unlock(&port_ptr->port_rx_q_lock);
328 release_sock(sk);
329 if (timeout < 0) {
330 ret = wait_event_interruptible(
331 port_ptr->port_rx_wait_q,
332 !list_empty(&port_ptr->port_rx_q));
333 if (ret)
334 return ret;
335 } else if (timeout > 0) {
336 timeout = wait_event_interruptible_timeout(
337 port_ptr->port_rx_wait_q,
338 !list_empty(&port_ptr->port_rx_q),
339 timeout);
340 if (timeout < 0)
341 return -EFAULT;
342 }
343
344 if (timeout == 0)
345 return -ETIMEDOUT;
346 lock_sock(sk);
347 mutex_lock(&port_ptr->port_rx_q_lock);
348 }
349 mutex_unlock(&port_ptr->port_rx_q_lock);
350
351 ret = msm_ipc_router_read(port_ptr, &msg, buf_len);
352 if (ret <= 0 || !msg) {
353 release_sock(sk);
354 return ret;
355 }
356
357 ret = msm_ipc_router_extract_msg(m, msg);
358 msm_ipc_router_release_msg(msg);
359 msg = NULL;
360 release_sock(sk);
361 return ret;
362}
363
364static int msm_ipc_router_ioctl(struct socket *sock,
365 unsigned int cmd, unsigned long arg)
366{
367 struct sock *sk = sock->sk;
368 struct msm_ipc_port *port_ptr;
369 struct server_lookup_args server_arg;
370 struct msm_ipc_port_addr *port_addr = NULL;
371 unsigned int n, port_addr_sz = 0;
372 int ret;
373
374 if (!sk)
375 return -EINVAL;
376
377 lock_sock(sk);
378 port_ptr = msm_ipc_sk_port(sock->sk);
379 if (!port_ptr) {
380 release_sock(sk);
381 return -EINVAL;
382 }
383
384 switch (cmd) {
385 case IPC_ROUTER_IOCTL_GET_VERSION:
386 n = IPC_ROUTER_VERSION;
387 ret = put_user(n, (unsigned int *)arg);
388 break;
389
390 case IPC_ROUTER_IOCTL_GET_MTU:
391 n = (MAX_IPC_PKT_SIZE - IPC_ROUTER_HDR_SIZE);
392 ret = put_user(n, (unsigned int *)arg);
393 break;
394
395 case IPC_ROUTER_IOCTL_GET_CURR_PKT_SIZE:
396 ret = msm_ipc_router_get_curr_pkt_size(port_ptr);
397 break;
398
399 case IPC_ROUTER_IOCTL_LOOKUP_SERVER:
400 ret = copy_from_user(&server_arg, (void *)arg,
401 sizeof(server_arg));
402 if (ret) {
403 ret = -EFAULT;
404 break;
405 }
406
407 if (server_arg.num_entries_in_array < 0) {
408 ret = -EINVAL;
409 break;
410 }
411 if (server_arg.num_entries_in_array) {
412 port_addr_sz = server_arg.num_entries_in_array *
413 sizeof(*port_addr);
414 port_addr = kmalloc(port_addr_sz, GFP_KERNEL);
415 if (!port_addr) {
416 ret = -ENOMEM;
417 break;
418 }
419 }
420 ret = msm_ipc_router_lookup_server_name(&server_arg.port_name,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -0600421 port_addr, server_arg.num_entries_in_array,
422 server_arg.lookup_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700423 if (ret < 0) {
424 pr_err("%s: Server not found\n", __func__);
425 ret = -ENODEV;
426 kfree(port_addr);
427 break;
428 }
429 server_arg.num_entries_found = ret;
430
431 ret = copy_to_user((void *)arg, &server_arg,
432 sizeof(server_arg));
433 if (port_addr_sz) {
434 ret = copy_to_user((void *)(arg + sizeof(server_arg)),
435 port_addr, port_addr_sz);
436 if (ret)
437 ret = -EFAULT;
438 kfree(port_addr);
439 }
440 break;
441
442 case IPC_ROUTER_IOCTL_BIND_CONTROL_PORT:
443 ret = msm_ipc_router_bind_control_port(port_ptr);
444 break;
445
446 default:
447 ret = -EINVAL;
448 }
449 release_sock(sk);
450 return ret;
451}
452
453static unsigned int msm_ipc_router_poll(struct file *file,
454 struct socket *sock, poll_table *wait)
455{
456 struct sock *sk = sock->sk;
457 struct msm_ipc_port *port_ptr;
458 uint32_t mask = 0;
459
460 if (!sk)
461 return -EINVAL;
462
463 port_ptr = msm_ipc_sk_port(sk);
464 if (!port_ptr)
465 return -EINVAL;
466
467 poll_wait(file, &port_ptr->port_rx_wait_q, wait);
468
469 if (!list_empty(&port_ptr->port_rx_q))
470 mask |= (POLLRDNORM | POLLIN);
471
472 return mask;
473}
474
475static int msm_ipc_router_close(struct socket *sock)
476{
477 struct sock *sk = sock->sk;
478 struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
Karthikeyan Ramasubramanian6b963bd2012-05-01 11:27:54 -0600479 void *pil = msm_ipc_sk(sk)->default_pil;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480 int ret;
481
482 lock_sock(sk);
483 ret = msm_ipc_router_close_port(port_ptr);
Karthikeyan Ramasubramanian6b963bd2012-05-01 11:27:54 -0600484 msm_ipc_unload_default_node(pil);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700485 release_sock(sk);
486 sock_put(sk);
487 sock->sk = NULL;
488
489 return ret;
490}
491
492static const struct net_proto_family msm_ipc_family_ops = {
493 .owner = THIS_MODULE,
494 .family = AF_MSM_IPC,
495 .create = msm_ipc_router_create
496};
497
498static const struct proto_ops msm_ipc_proto_ops = {
499 .owner = THIS_MODULE,
500 .family = AF_MSM_IPC,
501 .bind = msm_ipc_router_bind,
502 .connect = sock_no_connect,
503 .sendmsg = msm_ipc_router_sendmsg,
504 .recvmsg = msm_ipc_router_recvmsg,
505 .ioctl = msm_ipc_router_ioctl,
506 .poll = msm_ipc_router_poll,
507 .setsockopt = sock_no_setsockopt,
508 .getsockopt = sock_no_getsockopt,
509 .release = msm_ipc_router_close,
510};
511
512static struct proto msm_ipc_proto = {
513 .name = "MSM_IPC",
514 .owner = THIS_MODULE,
515 .obj_size = sizeof(struct msm_ipc_sock),
516};
517
518int msm_ipc_router_init_sockets(void)
519{
520 int ret;
521
522 ret = proto_register(&msm_ipc_proto, 1);
523 if (ret) {
524 pr_err("Failed to register MSM_IPC protocol type\n");
525 goto out_init_sockets;
526 }
527
528 ret = sock_register(&msm_ipc_family_ops);
529 if (ret) {
530 pr_err("Failed to register MSM_IPC socket type\n");
531 proto_unregister(&msm_ipc_proto);
532 goto out_init_sockets;
533 }
534
535 sockets_enabled = 1;
536out_init_sockets:
537 return ret;
538}
539
540void msm_ipc_router_exit_sockets(void)
541{
542 if (!sockets_enabled)
543 return;
544
545 sockets_enabled = 0;
546 sock_unregister(msm_ipc_family_ops.family);
547 proto_unregister(&msm_ipc_proto);
548}