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