blob: f9aa9b2451c8fdb1e560bda02e94cc57b1e0dbe3 [file] [log] [blame]
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -06001/* Copyright (c) 2011-2013, The Linux Foundation. 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
24#include <asm/string.h>
25#include <asm/atomic.h>
26
27#include <net/sock.h>
28
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070029#include "ipc_router.h"
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -060030#include "msm_ipc_router_security.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070031
32#define msm_ipc_sk(sk) ((struct msm_ipc_sock *)(sk))
33#define msm_ipc_sk_port(sk) ((struct msm_ipc_port *)(msm_ipc_sk(sk)->port))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070034
35static int sockets_enabled;
36static struct proto msm_ipc_proto;
37static const struct proto_ops msm_ipc_proto_ops;
38
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039static struct sk_buff_head *msm_ipc_router_build_msg(unsigned int num_sect,
40 struct iovec const *msg_sect,
41 size_t total_len)
42{
43 struct sk_buff_head *msg_head;
44 struct sk_buff *msg;
45 int i, copied, first = 1;
46 int data_size = 0, request_size, offset;
47 void *data;
48
49 for (i = 0; i < num_sect; i++)
50 data_size += msg_sect[i].iov_len;
51
52 if (!data_size)
53 return NULL;
54
55 msg_head = kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL);
56 if (!msg_head) {
57 pr_err("%s: cannot allocate skb_head\n", __func__);
58 return NULL;
59 }
60 skb_queue_head_init(msg_head);
61
62 for (copied = 1, i = 0; copied && (i < num_sect); i++) {
63 data_size = msg_sect[i].iov_len;
64 offset = 0;
65 while (offset != msg_sect[i].iov_len) {
66 request_size = data_size;
67 if (first)
68 request_size += IPC_ROUTER_HDR_SIZE;
69
70 msg = alloc_skb(request_size, GFP_KERNEL);
71 if (!msg) {
72 if (request_size <= (PAGE_SIZE/2)) {
73 pr_err("%s: cannot allocated skb\n",
74 __func__);
75 goto msg_build_failure;
76 }
77 data_size = data_size / 2;
78 continue;
79 }
80
81 if (first) {
82 skb_reserve(msg, IPC_ROUTER_HDR_SIZE);
83 first = 0;
84 }
85
86 data = skb_put(msg, data_size);
87 copied = !copy_from_user(msg->data,
88 msg_sect[i].iov_base + offset,
89 data_size);
90 if (!copied) {
91 pr_err("%s: copy_from_user failed\n",
92 __func__);
93 kfree_skb(msg);
94 goto msg_build_failure;
95 }
96 skb_queue_tail(msg_head, msg);
97 offset += data_size;
98 data_size = msg_sect[i].iov_len - offset;
99 }
100 }
101 return msg_head;
102
103msg_build_failure:
104 while (!skb_queue_empty(msg_head)) {
105 msg = skb_dequeue(msg_head);
106 kfree_skb(msg);
107 }
108 kfree(msg_head);
109 return NULL;
110}
111
112static int msm_ipc_router_extract_msg(struct msghdr *m,
113 struct sk_buff_head *msg_head)
114{
Karthikeyan Ramasubramanian2272b882013-04-05 11:30:53 -0600115 struct sockaddr_msm_ipc *addr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700116 struct rr_header *hdr;
117 struct sk_buff *temp;
118 int offset = 0, data_len = 0, copy_len;
119
120 if (!m || !msg_head) {
121 pr_err("%s: Invalid pointers passed\n", __func__);
122 return -EINVAL;
123 }
Karthikeyan Ramasubramanian2272b882013-04-05 11:30:53 -0600124 addr = (struct sockaddr_msm_ipc *)m->msg_name;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700125
126 temp = skb_peek(msg_head);
127 hdr = (struct rr_header *)(temp->data);
Karthikeyan Ramasubramanian2272b882013-04-05 11:30:53 -0600128 if (addr && (hdr->src_port_id != IPC_ROUTER_ADDRESS)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129 addr->family = AF_MSM_IPC;
130 addr->address.addrtype = MSM_IPC_ADDR_ID;
131 addr->address.addr.port_addr.node_id = hdr->src_node_id;
132 addr->address.addr.port_addr.port_id = hdr->src_port_id;
133 m->msg_namelen = sizeof(struct sockaddr_msm_ipc);
134 }
135
136 data_len = hdr->size;
137 skb_pull(temp, IPC_ROUTER_HDR_SIZE);
138 skb_queue_walk(msg_head, temp) {
139 copy_len = data_len < temp->len ? data_len : temp->len;
140 if (copy_to_user(m->msg_iov->iov_base + offset, temp->data,
141 copy_len)) {
142 pr_err("%s: Copy to user failed\n", __func__);
143 return -EFAULT;
144 }
145 offset += copy_len;
146 data_len -= copy_len;
147 }
148 return offset;
149}
150
151static void msm_ipc_router_release_msg(struct sk_buff_head *msg_head)
152{
153 struct sk_buff *temp;
154
155 if (!msg_head) {
156 pr_err("%s: Invalid msg pointer\n", __func__);
157 return;
158 }
159
160 while (!skb_queue_empty(msg_head)) {
161 temp = skb_dequeue(msg_head);
162 kfree_skb(temp);
163 }
164 kfree(msg_head);
165}
166
167static int msm_ipc_router_create(struct net *net,
168 struct socket *sock,
169 int protocol,
170 int kern)
171{
172 struct sock *sk;
173 struct msm_ipc_port *port_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700174
175 if (unlikely(protocol != 0)) {
176 pr_err("%s: Protocol not supported\n", __func__);
177 return -EPROTONOSUPPORT;
178 }
179
180 switch (sock->type) {
181 case SOCK_DGRAM:
182 break;
183 default:
184 pr_err("%s: Protocol type not supported\n", __func__);
185 return -EPROTOTYPE;
186 }
187
188 sk = sk_alloc(net, AF_MSM_IPC, GFP_KERNEL, &msm_ipc_proto);
189 if (!sk) {
190 pr_err("%s: sk_alloc failed\n", __func__);
191 return -ENOMEM;
192 }
193
194 port_ptr = msm_ipc_router_create_raw_port(sk, NULL, NULL);
195 if (!port_ptr) {
196 pr_err("%s: port_ptr alloc failed\n", __func__);
197 sk_free(sk);
198 return -ENOMEM;
199 }
200
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600201 port_ptr->check_send_permissions = msm_ipc_check_send_permissions;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700202 sock->ops = &msm_ipc_proto_ops;
203 sock_init_data(sock, sk);
204 sk->sk_rcvtimeo = DEFAULT_RCV_TIMEO;
205
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700206 msm_ipc_sk(sk)->port = port_ptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700207
208 return 0;
209}
210
211int msm_ipc_router_bind(struct socket *sock, struct sockaddr *uaddr,
212 int uaddr_len)
213{
214 struct sockaddr_msm_ipc *addr = (struct sockaddr_msm_ipc *)uaddr;
215 struct sock *sk = sock->sk;
216 struct msm_ipc_port *port_ptr;
217 int ret;
Karthikeyan Ramasubramanianaf90ba82013-06-03 12:05:50 -0600218 void *pil;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219
220 if (!sk)
221 return -EINVAL;
222
Karthikeyan Ramasubramanian54426332013-01-24 11:45:41 -0700223 if (!check_permissions()) {
224 pr_err("%s: %s Do not have permissions\n",
225 __func__, current->comm);
226 return -EPERM;
227 }
228
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700229 if (!uaddr_len) {
230 pr_err("%s: Invalid address length\n", __func__);
231 return -EINVAL;
232 }
233
234 if (addr->family != AF_MSM_IPC) {
235 pr_err("%s: Address family is incorrect\n", __func__);
236 return -EAFNOSUPPORT;
237 }
238
239 if (addr->address.addrtype != MSM_IPC_ADDR_NAME) {
240 pr_err("%s: Address type is incorrect\n", __func__);
241 return -EINVAL;
242 }
243
244 port_ptr = msm_ipc_sk_port(sk);
245 if (!port_ptr)
246 return -ENODEV;
247
Karthikeyan Ramasubramanianaf90ba82013-06-03 12:05:50 -0600248 pil = msm_ipc_load_default_node();
249 msm_ipc_sk(sk)->default_pil = pil;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250 lock_sock(sk);
251
252 ret = msm_ipc_router_register_server(port_ptr, &addr->address);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700253
254 release_sock(sk);
255 return ret;
256}
257
258static int msm_ipc_router_sendmsg(struct kiocb *iocb, struct socket *sock,
259 struct msghdr *m, size_t total_len)
260{
261 struct sock *sk = sock->sk;
262 struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
263 struct sockaddr_msm_ipc *dest = (struct sockaddr_msm_ipc *)m->msg_name;
264 struct sk_buff_head *msg;
265 int ret;
266
267 if (!dest)
268 return -EDESTADDRREQ;
269
270 if (m->msg_namelen < sizeof(*dest) || dest->family != AF_MSM_IPC)
271 return -EINVAL;
272
273 if (total_len > MAX_IPC_PKT_SIZE)
274 return -EINVAL;
275
276 lock_sock(sk);
277 msg = msm_ipc_router_build_msg(m->msg_iovlen, m->msg_iov, total_len);
278 if (!msg) {
279 pr_err("%s: Msg build failure\n", __func__);
280 ret = -ENOMEM;
281 goto out_sendmsg;
282 }
283
Karthikeyan Ramasubramaniand6dbfae2013-01-16 09:00:28 -0700284 if (port_ptr->type == CLIENT_PORT)
285 wait_for_irsc_completion();
286
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700287 ret = msm_ipc_router_send_to(port_ptr, msg, &dest->address);
288 if (ret == (IPC_ROUTER_HDR_SIZE + total_len))
289 ret = total_len;
290
291out_sendmsg:
292 release_sock(sk);
293 return ret;
294}
295
296static int msm_ipc_router_recvmsg(struct kiocb *iocb, struct socket *sock,
297 struct msghdr *m, size_t buf_len, int flags)
298{
299 struct sock *sk = sock->sk;
300 struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
301 struct sk_buff_head *msg;
302 long timeout;
303 int ret;
304
305 if (m->msg_iovlen != 1)
306 return -EOPNOTSUPP;
307
308 if (!buf_len)
309 return -EINVAL;
310
311 lock_sock(sk);
312 timeout = sk->sk_rcvtimeo;
313 mutex_lock(&port_ptr->port_rx_q_lock);
314 while (list_empty(&port_ptr->port_rx_q)) {
315 mutex_unlock(&port_ptr->port_rx_q_lock);
316 release_sock(sk);
317 if (timeout < 0) {
318 ret = wait_event_interruptible(
319 port_ptr->port_rx_wait_q,
320 !list_empty(&port_ptr->port_rx_q));
321 if (ret)
322 return ret;
323 } else if (timeout > 0) {
324 timeout = wait_event_interruptible_timeout(
325 port_ptr->port_rx_wait_q,
326 !list_empty(&port_ptr->port_rx_q),
327 timeout);
328 if (timeout < 0)
329 return -EFAULT;
330 }
331
332 if (timeout == 0)
333 return -ETIMEDOUT;
334 lock_sock(sk);
335 mutex_lock(&port_ptr->port_rx_q_lock);
336 }
337 mutex_unlock(&port_ptr->port_rx_q_lock);
338
339 ret = msm_ipc_router_read(port_ptr, &msg, buf_len);
340 if (ret <= 0 || !msg) {
341 release_sock(sk);
342 return ret;
343 }
344
345 ret = msm_ipc_router_extract_msg(m, msg);
346 msm_ipc_router_release_msg(msg);
347 msg = NULL;
348 release_sock(sk);
349 return ret;
350}
351
352static int msm_ipc_router_ioctl(struct socket *sock,
353 unsigned int cmd, unsigned long arg)
354{
355 struct sock *sk = sock->sk;
356 struct msm_ipc_port *port_ptr;
357 struct server_lookup_args server_arg;
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -0600358 struct msm_ipc_server_info *srv_info = NULL;
359 unsigned int n, srv_info_sz = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700360 int ret;
Karthikeyan Ramasubramanianaf90ba82013-06-03 12:05:50 -0600361 void *pil;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700362
363 if (!sk)
364 return -EINVAL;
365
366 lock_sock(sk);
367 port_ptr = msm_ipc_sk_port(sock->sk);
368 if (!port_ptr) {
369 release_sock(sk);
370 return -EINVAL;
371 }
372
373 switch (cmd) {
374 case IPC_ROUTER_IOCTL_GET_VERSION:
375 n = IPC_ROUTER_VERSION;
376 ret = put_user(n, (unsigned int *)arg);
377 break;
378
379 case IPC_ROUTER_IOCTL_GET_MTU:
380 n = (MAX_IPC_PKT_SIZE - IPC_ROUTER_HDR_SIZE);
381 ret = put_user(n, (unsigned int *)arg);
382 break;
383
384 case IPC_ROUTER_IOCTL_GET_CURR_PKT_SIZE:
385 ret = msm_ipc_router_get_curr_pkt_size(port_ptr);
386 break;
387
388 case IPC_ROUTER_IOCTL_LOOKUP_SERVER:
Karthikeyan Ramasubramanianaf90ba82013-06-03 12:05:50 -0600389 pil = msm_ipc_load_default_node();
390 msm_ipc_sk(sk)->default_pil = pil;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391 ret = copy_from_user(&server_arg, (void *)arg,
392 sizeof(server_arg));
393 if (ret) {
394 ret = -EFAULT;
395 break;
396 }
397
398 if (server_arg.num_entries_in_array < 0) {
399 ret = -EINVAL;
400 break;
401 }
402 if (server_arg.num_entries_in_array) {
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -0600403 srv_info_sz = server_arg.num_entries_in_array *
404 sizeof(*srv_info);
Karthikeyan Ramasubramanianabe0b062013-02-26 16:37:50 -0700405 if ((srv_info_sz / sizeof(*srv_info)) !=
406 server_arg.num_entries_in_array) {
407 pr_err("%s: Integer Overflow %d * %d\n",
408 __func__, sizeof(*srv_info),
409 server_arg.num_entries_in_array);
410 ret = -EINVAL;
411 break;
412 }
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -0600413 srv_info = kmalloc(srv_info_sz, GFP_KERNEL);
414 if (!srv_info) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415 ret = -ENOMEM;
416 break;
417 }
418 }
419 ret = msm_ipc_router_lookup_server_name(&server_arg.port_name,
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -0600420 srv_info, server_arg.num_entries_in_array,
Karthikeyan Ramasubramaniancc450c92011-07-27 14:38:15 -0600421 server_arg.lookup_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422 if (ret < 0) {
423 pr_err("%s: Server not found\n", __func__);
424 ret = -ENODEV;
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -0600425 kfree(srv_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426 break;
427 }
428 server_arg.num_entries_found = ret;
429
430 ret = copy_to_user((void *)arg, &server_arg,
431 sizeof(server_arg));
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -0600432 if (srv_info_sz) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700433 ret = copy_to_user((void *)(arg + sizeof(server_arg)),
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -0600434 srv_info, srv_info_sz);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700435 if (ret)
436 ret = -EFAULT;
Karthikeyan Ramasubramaniandfde01b2012-06-12 14:25:13 -0600437 kfree(srv_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700438 }
439 break;
440
441 case IPC_ROUTER_IOCTL_BIND_CONTROL_PORT:
442 ret = msm_ipc_router_bind_control_port(port_ptr);
443 break;
444
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600445 case IPC_ROUTER_IOCTL_CONFIG_SEC_RULES:
446 ret = msm_ipc_config_sec_rules((void *)arg);
Karthikeyan Ramasubramaniand6dbfae2013-01-16 09:00:28 -0700447 if (ret != -EPERM)
448 port_ptr->type = IRSC_PORT;
Karthikeyan Ramasubramanian1668cc62012-09-23 22:23:36 -0600449 break;
450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451 default:
452 ret = -EINVAL;
453 }
454 release_sock(sk);
455 return ret;
456}
457
458static unsigned int msm_ipc_router_poll(struct file *file,
459 struct socket *sock, poll_table *wait)
460{
461 struct sock *sk = sock->sk;
462 struct msm_ipc_port *port_ptr;
463 uint32_t mask = 0;
464
465 if (!sk)
466 return -EINVAL;
467
468 port_ptr = msm_ipc_sk_port(sk);
469 if (!port_ptr)
470 return -EINVAL;
471
472 poll_wait(file, &port_ptr->port_rx_wait_q, wait);
473
474 if (!list_empty(&port_ptr->port_rx_q))
475 mask |= (POLLRDNORM | POLLIN);
476
477 return mask;
478}
479
480static int msm_ipc_router_close(struct socket *sock)
481{
482 struct sock *sk = sock->sk;
483 struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
Karthikeyan Ramasubramanianaf90ba82013-06-03 12:05:50 -0600484 void *pil = msm_ipc_sk(sk)->default_pil;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700485 int ret;
486
487 lock_sock(sk);
488 ret = msm_ipc_router_close_port(port_ptr);
Karthikeyan Ramasubramanianaf90ba82013-06-03 12:05:50 -0600489 if (pil)
490 msm_ipc_unload_default_node(pil);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700491 release_sock(sk);
492 sock_put(sk);
493 sock->sk = NULL;
494
495 return ret;
496}
497
498static const struct net_proto_family msm_ipc_family_ops = {
499 .owner = THIS_MODULE,
500 .family = AF_MSM_IPC,
501 .create = msm_ipc_router_create
502};
503
504static const struct proto_ops msm_ipc_proto_ops = {
505 .owner = THIS_MODULE,
506 .family = AF_MSM_IPC,
507 .bind = msm_ipc_router_bind,
508 .connect = sock_no_connect,
509 .sendmsg = msm_ipc_router_sendmsg,
510 .recvmsg = msm_ipc_router_recvmsg,
511 .ioctl = msm_ipc_router_ioctl,
512 .poll = msm_ipc_router_poll,
513 .setsockopt = sock_no_setsockopt,
514 .getsockopt = sock_no_getsockopt,
515 .release = msm_ipc_router_close,
516};
517
518static struct proto msm_ipc_proto = {
519 .name = "MSM_IPC",
520 .owner = THIS_MODULE,
521 .obj_size = sizeof(struct msm_ipc_sock),
522};
523
524int msm_ipc_router_init_sockets(void)
525{
526 int ret;
527
528 ret = proto_register(&msm_ipc_proto, 1);
529 if (ret) {
530 pr_err("Failed to register MSM_IPC protocol type\n");
531 goto out_init_sockets;
532 }
533
534 ret = sock_register(&msm_ipc_family_ops);
535 if (ret) {
536 pr_err("Failed to register MSM_IPC socket type\n");
537 proto_unregister(&msm_ipc_proto);
538 goto out_init_sockets;
539 }
540
541 sockets_enabled = 1;
542out_init_sockets:
543 return ret;
544}
545
546void msm_ipc_router_exit_sockets(void)
547{
548 if (!sockets_enabled)
549 return;
550
551 sockets_enabled = 0;
552 sock_unregister(msm_ipc_family_ops.family);
553 proto_unregister(&msm_ipc_proto);
554}