blob: 085b87a6e46035d64f24f64e8e6270ffeb253d68 [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
Karthikeyan Ramasubramanian1d6f8cc2012-04-25 21:31:00 -060033#include <mach/peripheral-loader.h>
34#include <mach/socinfo.h>
35
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070036#include "ipc_router.h"
37
38#define msm_ipc_sk(sk) ((struct msm_ipc_sock *)(sk))
39#define msm_ipc_sk_port(sk) ((struct msm_ipc_port *)(msm_ipc_sk(sk)->port))
Karthikeyan Ramasubramanian1d6f8cc2012-04-25 21:31:00 -060040#define MODEM_LOAD_TIMEOUT (10 * HZ)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041
42static int sockets_enabled;
43static struct proto msm_ipc_proto;
44static const struct proto_ops msm_ipc_proto_ops;
45
Karthikeyan Ramasubramanian98ee1d52012-04-13 09:24:55 -060046#ifdef CONFIG_ANDROID_PARANOID_NETWORK
47static inline int check_permissions(void)
48{
49 int rc = 0;
50 if (!current_euid() || in_egroup_p(AID_NET_RAW))
51 rc = 1;
52 return rc;
53}
54# else
55static inline int check_permissions(void)
56{
57 return 1;
58}
59#endif
60
Karthikeyan Ramasubramanian1d6f8cc2012-04-25 21:31:00 -060061static void msm_ipc_router_unload_modem(void *pil)
62{
63 if (pil)
64 pil_put(pil);
65}
66
67static void *msm_ipc_router_load_modem(void)
68{
69 void *pil = NULL;
70 int rc;
71
72 /* Load GNSS for Standalone 8064 but not for Fusion 3 */
73 if (cpu_is_apq8064()) {
74 if (socinfo_get_platform_subtype() == 0x0)
75 pil = pil_get("gss");
76 } else {
77 pil = pil_get("modem");
78 }
79
80 if (IS_ERR(pil) || !pil) {
81 pr_debug("%s: modem load failed\n", __func__);
82 pil = NULL;
83 } else {
84 rc = wait_for_completion_interruptible_timeout(
85 &msm_ipc_remote_router_up,
86 MODEM_LOAD_TIMEOUT);
87 if (!rc)
88 rc = -ETIMEDOUT;
89 if (rc < 0) {
90 pr_err("%s: wait for remote router failed %d\n",
91 __func__, rc);
92 msm_ipc_router_unload_modem(pil);
93 pil = NULL;
94 }
95 }
96
97 return pil;
98}
99
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700100static struct sk_buff_head *msm_ipc_router_build_msg(unsigned int num_sect,
101 struct iovec const *msg_sect,
102 size_t total_len)
103{
104 struct sk_buff_head *msg_head;
105 struct sk_buff *msg;
106 int i, copied, first = 1;
107 int data_size = 0, request_size, offset;
108 void *data;
109
110 for (i = 0; i < num_sect; i++)
111 data_size += msg_sect[i].iov_len;
112
113 if (!data_size)
114 return NULL;
115
116 msg_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
117 if (!msg_head) {
118 pr_err("%s: cannot allocate skb_head\n", __func__);
119 return NULL;
120 }
121 skb_queue_head_init(msg_head);
122
123 for (copied = 1, i = 0; copied && (i < num_sect); i++) {
124 data_size = msg_sect[i].iov_len;
125 offset = 0;
126 while (offset != msg_sect[i].iov_len) {
127 request_size = data_size;
128 if (first)
129 request_size += IPC_ROUTER_HDR_SIZE;
130
131 msg = alloc_skb(request_size, GFP_KERNEL);
132 if (!msg) {
133 if (request_size <= (PAGE_SIZE/2)) {
134 pr_err("%s: cannot allocated skb\n",
135 __func__);
136 goto msg_build_failure;
137 }
138 data_size = data_size / 2;
139 continue;
140 }
141
142 if (first) {
143 skb_reserve(msg, IPC_ROUTER_HDR_SIZE);
144 first = 0;
145 }
146
147 data = skb_put(msg, data_size);
148 copied = !copy_from_user(msg->data,
149 msg_sect[i].iov_base + offset,
150 data_size);
151 if (!copied) {
152 pr_err("%s: copy_from_user failed\n",
153 __func__);
154 kfree_skb(msg);
155 goto msg_build_failure;
156 }
157 skb_queue_tail(msg_head, msg);
158 offset += data_size;
159 data_size = msg_sect[i].iov_len - offset;
160 }
161 }
162 return msg_head;
163
164msg_build_failure:
165 while (!skb_queue_empty(msg_head)) {
166 msg = skb_dequeue(msg_head);
167 kfree_skb(msg);
168 }
169 kfree(msg_head);
170 return NULL;
171}
172
173static int msm_ipc_router_extract_msg(struct msghdr *m,
174 struct sk_buff_head *msg_head)
175{
176 struct sockaddr_msm_ipc *addr = (struct sockaddr_msm_ipc *)m->msg_name;
177 struct rr_header *hdr;
178 struct sk_buff *temp;
179 int offset = 0, data_len = 0, copy_len;
180
181 if (!m || !msg_head) {
182 pr_err("%s: Invalid pointers passed\n", __func__);
183 return -EINVAL;
184 }
185
186 temp = skb_peek(msg_head);
187 hdr = (struct rr_header *)(temp->data);
188 if (addr || (hdr->src_port_id != IPC_ROUTER_ADDRESS)) {
189 addr->family = AF_MSM_IPC;
190 addr->address.addrtype = MSM_IPC_ADDR_ID;
191 addr->address.addr.port_addr.node_id = hdr->src_node_id;
192 addr->address.addr.port_addr.port_id = hdr->src_port_id;
193 m->msg_namelen = sizeof(struct sockaddr_msm_ipc);
194 }
195
196 data_len = hdr->size;
197 skb_pull(temp, IPC_ROUTER_HDR_SIZE);
198 skb_queue_walk(msg_head, temp) {
199 copy_len = data_len < temp->len ? data_len : temp->len;
200 if (copy_to_user(m->msg_iov->iov_base + offset, temp->data,
201 copy_len)) {
202 pr_err("%s: Copy to user failed\n", __func__);
203 return -EFAULT;
204 }
205 offset += copy_len;
206 data_len -= copy_len;
207 }
208 return offset;
209}
210
211static void msm_ipc_router_release_msg(struct sk_buff_head *msg_head)
212{
213 struct sk_buff *temp;
214
215 if (!msg_head) {
216 pr_err("%s: Invalid msg pointer\n", __func__);
217 return;
218 }
219
220 while (!skb_queue_empty(msg_head)) {
221 temp = skb_dequeue(msg_head);
222 kfree_skb(temp);
223 }
224 kfree(msg_head);
225}
226
227static int msm_ipc_router_create(struct net *net,
228 struct socket *sock,
229 int protocol,
230 int kern)
231{
232 struct sock *sk;
233 struct msm_ipc_port *port_ptr;
234 void *pil;
235
Karthikeyan Ramasubramanian98ee1d52012-04-13 09:24:55 -0600236 if (!check_permissions()) {
237 pr_err("%s: Do not have permissions\n", __func__);
238 return -EPERM;
239 }
240
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700241 if (unlikely(protocol != 0)) {
242 pr_err("%s: Protocol not supported\n", __func__);
243 return -EPROTONOSUPPORT;
244 }
245
246 switch (sock->type) {
247 case SOCK_DGRAM:
248 break;
249 default:
250 pr_err("%s: Protocol type not supported\n", __func__);
251 return -EPROTOTYPE;
252 }
253
254 sk = sk_alloc(net, AF_MSM_IPC, GFP_KERNEL, &msm_ipc_proto);
255 if (!sk) {
256 pr_err("%s: sk_alloc failed\n", __func__);
257 return -ENOMEM;
258 }
259
260 port_ptr = msm_ipc_router_create_raw_port(sk, NULL, NULL);
261 if (!port_ptr) {
262 pr_err("%s: port_ptr alloc failed\n", __func__);
263 sk_free(sk);
264 return -ENOMEM;
265 }
266
267 sock->ops = &msm_ipc_proto_ops;
268 sock_init_data(sock, sk);
269 sk->sk_rcvtimeo = DEFAULT_RCV_TIMEO;
270
Karthikeyan Ramasubramanian1d6f8cc2012-04-25 21:31:00 -0600271 pil = msm_ipc_router_load_modem();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700272 msm_ipc_sk(sk)->port = port_ptr;
Karthikeyan Ramasubramanian1d6f8cc2012-04-25 21:31:00 -0600273 msm_ipc_sk(sk)->modem_pil = pil;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274
275 return 0;
276}
277
278int msm_ipc_router_bind(struct socket *sock, struct sockaddr *uaddr,
279 int uaddr_len)
280{
281 struct sockaddr_msm_ipc *addr = (struct sockaddr_msm_ipc *)uaddr;
282 struct sock *sk = sock->sk;
283 struct msm_ipc_port *port_ptr;
284 int ret;
285
286 if (!sk)
287 return -EINVAL;
288
289 if (!uaddr_len) {
290 pr_err("%s: Invalid address length\n", __func__);
291 return -EINVAL;
292 }
293
294 if (addr->family != AF_MSM_IPC) {
295 pr_err("%s: Address family is incorrect\n", __func__);
296 return -EAFNOSUPPORT;
297 }
298
299 if (addr->address.addrtype != MSM_IPC_ADDR_NAME) {
300 pr_err("%s: Address type is incorrect\n", __func__);
301 return -EINVAL;
302 }
303
304 port_ptr = msm_ipc_sk_port(sk);
305 if (!port_ptr)
306 return -ENODEV;
307
308 lock_sock(sk);
309
310 ret = msm_ipc_router_register_server(port_ptr, &addr->address);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700311
312 release_sock(sk);
313 return ret;
314}
315
316static int msm_ipc_router_sendmsg(struct kiocb *iocb, struct socket *sock,
317 struct msghdr *m, size_t total_len)
318{
319 struct sock *sk = sock->sk;
320 struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
321 struct sockaddr_msm_ipc *dest = (struct sockaddr_msm_ipc *)m->msg_name;
322 struct sk_buff_head *msg;
323 int ret;
324
325 if (!dest)
326 return -EDESTADDRREQ;
327
328 if (m->msg_namelen < sizeof(*dest) || dest->family != AF_MSM_IPC)
329 return -EINVAL;
330
331 if (total_len > MAX_IPC_PKT_SIZE)
332 return -EINVAL;
333
334 lock_sock(sk);
335 msg = msm_ipc_router_build_msg(m->msg_iovlen, m->msg_iov, total_len);
336 if (!msg) {
337 pr_err("%s: Msg build failure\n", __func__);
338 ret = -ENOMEM;
339 goto out_sendmsg;
340 }
341
342 ret = msm_ipc_router_send_to(port_ptr, msg, &dest->address);
343 if (ret == (IPC_ROUTER_HDR_SIZE + total_len))
344 ret = total_len;
345
346out_sendmsg:
347 release_sock(sk);
348 return ret;
349}
350
351static int msm_ipc_router_recvmsg(struct kiocb *iocb, struct socket *sock,
352 struct msghdr *m, size_t buf_len, int flags)
353{
354 struct sock *sk = sock->sk;
355 struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
356 struct sk_buff_head *msg;
357 long timeout;
358 int ret;
359
360 if (m->msg_iovlen != 1)
361 return -EOPNOTSUPP;
362
363 if (!buf_len)
364 return -EINVAL;
365
366 lock_sock(sk);
367 timeout = sk->sk_rcvtimeo;
368 mutex_lock(&port_ptr->port_rx_q_lock);
369 while (list_empty(&port_ptr->port_rx_q)) {
370 mutex_unlock(&port_ptr->port_rx_q_lock);
371 release_sock(sk);
372 if (timeout < 0) {
373 ret = wait_event_interruptible(
374 port_ptr->port_rx_wait_q,
375 !list_empty(&port_ptr->port_rx_q));
376 if (ret)
377 return ret;
378 } else if (timeout > 0) {
379 timeout = wait_event_interruptible_timeout(
380 port_ptr->port_rx_wait_q,
381 !list_empty(&port_ptr->port_rx_q),
382 timeout);
383 if (timeout < 0)
384 return -EFAULT;
385 }
386
387 if (timeout == 0)
388 return -ETIMEDOUT;
389 lock_sock(sk);
390 mutex_lock(&port_ptr->port_rx_q_lock);
391 }
392 mutex_unlock(&port_ptr->port_rx_q_lock);
393
394 ret = msm_ipc_router_read(port_ptr, &msg, buf_len);
395 if (ret <= 0 || !msg) {
396 release_sock(sk);
397 return ret;
398 }
399
400 ret = msm_ipc_router_extract_msg(m, msg);
401 msm_ipc_router_release_msg(msg);
402 msg = NULL;
403 release_sock(sk);
404 return ret;
405}
406
407static int msm_ipc_router_ioctl(struct socket *sock,
408 unsigned int cmd, unsigned long arg)
409{
410 struct sock *sk = sock->sk;
411 struct msm_ipc_port *port_ptr;
412 struct server_lookup_args server_arg;
413 struct msm_ipc_port_addr *port_addr = NULL;
414 unsigned int n, port_addr_sz = 0;
415 int ret;
416
417 if (!sk)
418 return -EINVAL;
419
420 lock_sock(sk);
421 port_ptr = msm_ipc_sk_port(sock->sk);
422 if (!port_ptr) {
423 release_sock(sk);
424 return -EINVAL;
425 }
426
427 switch (cmd) {
428 case IPC_ROUTER_IOCTL_GET_VERSION:
429 n = IPC_ROUTER_VERSION;
430 ret = put_user(n, (unsigned int *)arg);
431 break;
432
433 case IPC_ROUTER_IOCTL_GET_MTU:
434 n = (MAX_IPC_PKT_SIZE - IPC_ROUTER_HDR_SIZE);
435 ret = put_user(n, (unsigned int *)arg);
436 break;
437
438 case IPC_ROUTER_IOCTL_GET_CURR_PKT_SIZE:
439 ret = msm_ipc_router_get_curr_pkt_size(port_ptr);
440 break;
441
442 case IPC_ROUTER_IOCTL_LOOKUP_SERVER:
443 ret = copy_from_user(&server_arg, (void *)arg,
444 sizeof(server_arg));
445 if (ret) {
446 ret = -EFAULT;
447 break;
448 }
449
450 if (server_arg.num_entries_in_array < 0) {
451 ret = -EINVAL;
452 break;
453 }
454 if (server_arg.num_entries_in_array) {
455 port_addr_sz = server_arg.num_entries_in_array *
456 sizeof(*port_addr);
457 port_addr = kmalloc(port_addr_sz, GFP_KERNEL);
458 if (!port_addr) {
459 ret = -ENOMEM;
460 break;
461 }
462 }
463 ret = msm_ipc_router_lookup_server_name(&server_arg.port_name,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -0600464 port_addr, server_arg.num_entries_in_array,
465 server_arg.lookup_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700466 if (ret < 0) {
467 pr_err("%s: Server not found\n", __func__);
468 ret = -ENODEV;
469 kfree(port_addr);
470 break;
471 }
472 server_arg.num_entries_found = ret;
473
474 ret = copy_to_user((void *)arg, &server_arg,
475 sizeof(server_arg));
476 if (port_addr_sz) {
477 ret = copy_to_user((void *)(arg + sizeof(server_arg)),
478 port_addr, port_addr_sz);
479 if (ret)
480 ret = -EFAULT;
481 kfree(port_addr);
482 }
483 break;
484
485 case IPC_ROUTER_IOCTL_BIND_CONTROL_PORT:
486 ret = msm_ipc_router_bind_control_port(port_ptr);
487 break;
488
489 default:
490 ret = -EINVAL;
491 }
492 release_sock(sk);
493 return ret;
494}
495
496static unsigned int msm_ipc_router_poll(struct file *file,
497 struct socket *sock, poll_table *wait)
498{
499 struct sock *sk = sock->sk;
500 struct msm_ipc_port *port_ptr;
501 uint32_t mask = 0;
502
503 if (!sk)
504 return -EINVAL;
505
506 port_ptr = msm_ipc_sk_port(sk);
507 if (!port_ptr)
508 return -EINVAL;
509
510 poll_wait(file, &port_ptr->port_rx_wait_q, wait);
511
512 if (!list_empty(&port_ptr->port_rx_q))
513 mask |= (POLLRDNORM | POLLIN);
514
515 return mask;
516}
517
518static int msm_ipc_router_close(struct socket *sock)
519{
520 struct sock *sk = sock->sk;
521 struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
Karthikeyan Ramasubramanian1d6f8cc2012-04-25 21:31:00 -0600522 void *pil = msm_ipc_sk(sk)->modem_pil;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700523 int ret;
524
525 lock_sock(sk);
526 ret = msm_ipc_router_close_port(port_ptr);
Karthikeyan Ramasubramanian1d6f8cc2012-04-25 21:31:00 -0600527 msm_ipc_router_unload_modem(pil);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700528 release_sock(sk);
529 sock_put(sk);
530 sock->sk = NULL;
531
532 return ret;
533}
534
535static const struct net_proto_family msm_ipc_family_ops = {
536 .owner = THIS_MODULE,
537 .family = AF_MSM_IPC,
538 .create = msm_ipc_router_create
539};
540
541static const struct proto_ops msm_ipc_proto_ops = {
542 .owner = THIS_MODULE,
543 .family = AF_MSM_IPC,
544 .bind = msm_ipc_router_bind,
545 .connect = sock_no_connect,
546 .sendmsg = msm_ipc_router_sendmsg,
547 .recvmsg = msm_ipc_router_recvmsg,
548 .ioctl = msm_ipc_router_ioctl,
549 .poll = msm_ipc_router_poll,
550 .setsockopt = sock_no_setsockopt,
551 .getsockopt = sock_no_getsockopt,
552 .release = msm_ipc_router_close,
553};
554
555static struct proto msm_ipc_proto = {
556 .name = "MSM_IPC",
557 .owner = THIS_MODULE,
558 .obj_size = sizeof(struct msm_ipc_sock),
559};
560
561int msm_ipc_router_init_sockets(void)
562{
563 int ret;
564
565 ret = proto_register(&msm_ipc_proto, 1);
566 if (ret) {
567 pr_err("Failed to register MSM_IPC protocol type\n");
568 goto out_init_sockets;
569 }
570
571 ret = sock_register(&msm_ipc_family_ops);
572 if (ret) {
573 pr_err("Failed to register MSM_IPC socket type\n");
574 proto_unregister(&msm_ipc_proto);
575 goto out_init_sockets;
576 }
577
578 sockets_enabled = 1;
579out_init_sockets:
580 return ret;
581}
582
583void msm_ipc_router_exit_sockets(void)
584{
585 if (!sockets_enabled)
586 return;
587
588 sockets_enabled = 0;
589 sock_unregister(msm_ipc_family_ops.family);
590 proto_unregister(&msm_ipc_proto);
591}