blob: 4e53861c4acc731d181536b1b014da8cd236657a [file] [log] [blame]
Arun Kumar Neelakantam6f3f1fa2018-07-19 14:25:22 +05301/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved.
Karthikeyan Ramasubramanian6a116d62016-09-16 16:05:32 -06002 *
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#include <linux/sched.h>
24#include <linux/thread_info.h>
25#include <linux/slab.h>
26#include <linux/kmemleak.h>
27#include <linux/ipc_logging.h>
28#include <linux/string.h>
29#include <linux/atomic.h>
30#include <linux/ipc_router.h>
31
32#include <net/sock.h>
33
34#include "ipc_router_private.h"
35#include "ipc_router_security.h"
36
37#define msm_ipc_sk(sk) ((struct msm_ipc_sock *)(sk))
38#define msm_ipc_sk_port(sk) ((struct msm_ipc_port *)(msm_ipc_sk(sk)->port))
39
40#ifndef SIZE_MAX
41#define SIZE_MAX ((size_t)-1)
42#endif
43
44static int sockets_enabled;
45static struct proto msm_ipc_proto;
46static const struct proto_ops msm_ipc_proto_ops;
47static RAW_NOTIFIER_HEAD(ipcrtr_af_init_chain);
48static DEFINE_MUTEX(ipcrtr_af_init_lock);
49
50static struct sk_buff_head *msm_ipc_router_build_msg(struct msghdr *m,
51 size_t total_len)
52{
53 struct sk_buff_head *msg_head;
54 struct sk_buff *msg;
55 int first = 1;
56 int last = 1;
57 size_t data_size = 0;
58 size_t alloc_size, align_size;
59 void *data;
60 size_t total_copied_size = 0, copied_size;
61
62 if (iov_iter_count(&m->msg_iter) == total_len)
63 data_size = total_len;
64
65 if (!data_size)
66 return NULL;
67 align_size = ALIGN_SIZE(data_size);
68
69 msg_head = kmalloc(sizeof(*msg_head), GFP_KERNEL);
70 if (!msg_head) {
71 IPC_RTR_ERR("%s: cannot allocate skb_head\n", __func__);
72 return NULL;
73 }
74 skb_queue_head_init(msg_head);
75
76 while (total_copied_size < total_len) {
77 alloc_size = data_size;
78 if (first)
79 alloc_size += IPC_ROUTER_HDR_SIZE;
80 if (last)
81 alloc_size += align_size;
82
83 msg = alloc_skb(alloc_size, GFP_KERNEL);
84 if (!msg) {
85 if (alloc_size <= (PAGE_SIZE / 2)) {
86 IPC_RTR_ERR("%s: cannot allocated skb\n",
87 __func__);
88 goto msg_build_failure;
89 }
90 data_size = data_size / 2;
91 last = 0;
92 continue;
93 }
94
95 if (first) {
96 skb_reserve(msg, IPC_ROUTER_HDR_SIZE);
97 first = 0;
98 }
99
100 data = skb_put(msg, data_size);
101 copied_size = copy_from_iter(msg->data, data_size,
102 &m->msg_iter);
103 if (copied_size != data_size) {
104 IPC_RTR_ERR("%s: copy_from_iter failed %zu %zu %zu\n",
105 __func__, alloc_size, data_size,
106 copied_size);
107 kfree_skb(msg);
108 goto msg_build_failure;
109 }
110 skb_queue_tail(msg_head, msg);
111 total_copied_size += data_size;
112 data_size = total_len - total_copied_size;
113 last = 1;
114 }
115 return msg_head;
116
117msg_build_failure:
118 while (!skb_queue_empty(msg_head)) {
119 msg = skb_dequeue(msg_head);
120 kfree_skb(msg);
121 }
122 kfree(msg_head);
123 return NULL;
124}
125
126static int msm_ipc_router_extract_msg(struct msghdr *m,
127 struct rr_packet *pkt)
128{
129 struct sockaddr_msm_ipc *addr;
130 struct rr_header_v1 *hdr;
131 struct sk_buff *temp;
132 union rr_control_msg *ctl_msg;
133 int offset = 0, data_len = 0, copy_len, copied_len;
134
135 if (!m || !pkt) {
136 IPC_RTR_ERR("%s: Invalid pointers passed\n", __func__);
137 return -EINVAL;
138 }
139 addr = (struct sockaddr_msm_ipc *)m->msg_name;
140
141 hdr = &pkt->hdr;
142 if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_RESUME_TX)) {
143 temp = skb_peek(pkt->pkt_fragment_q);
Chris Lew42ea9612017-10-04 15:58:16 -0700144 if (!temp || !temp->data) {
145 IPC_RTR_ERR("%s: Invalid skb\n", __func__);
146 return -EINVAL;
147 }
Karthikeyan Ramasubramanian6a116d62016-09-16 16:05:32 -0600148 ctl_msg = (union rr_control_msg *)(temp->data);
Arun Kumar Neelakantam6f3f1fa2018-07-19 14:25:22 +0530149 memset(addr, 0x0, sizeof(*addr));
Karthikeyan Ramasubramanian6a116d62016-09-16 16:05:32 -0600150 addr->family = AF_MSM_IPC;
151 addr->address.addrtype = MSM_IPC_ADDR_ID;
152 addr->address.addr.port_addr.node_id = ctl_msg->cli.node_id;
153 addr->address.addr.port_addr.port_id = ctl_msg->cli.port_id;
154 m->msg_namelen = sizeof(struct sockaddr_msm_ipc);
155 return offset;
156 }
157 if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_DATA)) {
Arun Kumar Neelakantam6f3f1fa2018-07-19 14:25:22 +0530158 memset(addr, 0x0, sizeof(*addr));
Karthikeyan Ramasubramanian6a116d62016-09-16 16:05:32 -0600159 addr->family = AF_MSM_IPC;
160 addr->address.addrtype = MSM_IPC_ADDR_ID;
161 addr->address.addr.port_addr.node_id = hdr->src_node_id;
162 addr->address.addr.port_addr.port_id = hdr->src_port_id;
163 m->msg_namelen = sizeof(struct sockaddr_msm_ipc);
164 }
165
166 data_len = hdr->size;
167 skb_queue_walk(pkt->pkt_fragment_q, temp) {
168 copy_len = data_len < temp->len ? data_len : temp->len;
169 copied_len = copy_to_iter(temp->data, copy_len, &m->msg_iter);
170 if (copy_len != copied_len) {
171 IPC_RTR_ERR("%s: Copy to user failed\n", __func__);
172 return -EFAULT;
173 }
174 offset += copy_len;
175 data_len -= copy_len;
176 }
177 return offset;
178}
179
180static int msm_ipc_router_create(struct net *net,
181 struct socket *sock,
182 int protocol,
183 int kern)
184{
185 struct sock *sk;
186 struct msm_ipc_port *port_ptr;
187
188 if (unlikely(protocol != 0)) {
189 IPC_RTR_ERR("%s: Protocol not supported\n", __func__);
190 return -EPROTONOSUPPORT;
191 }
192
193 switch (sock->type) {
194 case SOCK_DGRAM:
195 break;
196 default:
197 IPC_RTR_ERR("%s: Protocol type not supported\n", __func__);
198 return -EPROTOTYPE;
199 }
200
201 sk = sk_alloc(net, AF_MSM_IPC, GFP_KERNEL, &msm_ipc_proto, kern);
202 if (!sk) {
203 IPC_RTR_ERR("%s: sk_alloc failed\n", __func__);
204 return -ENOMEM;
205 }
206
207 sock->ops = &msm_ipc_proto_ops;
208 sock_init_data(sock, sk);
209 sk->sk_data_ready = NULL;
210 sk->sk_write_space = ipc_router_dummy_write_space;
211 sk->sk_rcvtimeo = DEFAULT_RCV_TIMEO;
212 sk->sk_sndtimeo = DEFAULT_SND_TIMEO;
213
214 port_ptr = msm_ipc_router_create_raw_port(sk, NULL, NULL);
215 if (!port_ptr) {
216 IPC_RTR_ERR("%s: port_ptr alloc failed\n", __func__);
217 sock_put(sk);
218 sock->sk = NULL;
219 return -ENOMEM;
220 }
221
222 port_ptr->check_send_permissions = msm_ipc_check_send_permissions;
223 msm_ipc_sk(sk)->port = port_ptr;
224 msm_ipc_sk(sk)->default_node_vote_info = NULL;
225
226 return 0;
227}
228
229int msm_ipc_router_bind(struct socket *sock, struct sockaddr *uaddr,
230 int uaddr_len)
231{
232 struct sockaddr_msm_ipc *addr = (struct sockaddr_msm_ipc *)uaddr;
233 struct sock *sk = sock->sk;
234 struct msm_ipc_port *port_ptr;
235 int ret;
236
237 if (!sk)
238 return -EINVAL;
239
240 if (!check_permissions()) {
241 IPC_RTR_ERR("%s: %s Do not have permissions\n",
242 __func__, current->comm);
243 return -EPERM;
244 }
245
246 if (!uaddr_len) {
247 IPC_RTR_ERR("%s: Invalid address length\n", __func__);
248 return -EINVAL;
249 }
250
251 if (addr->family != AF_MSM_IPC) {
252 IPC_RTR_ERR("%s: Address family is incorrect\n", __func__);
253 return -EAFNOSUPPORT;
254 }
255
256 if (addr->address.addrtype != MSM_IPC_ADDR_NAME) {
257 IPC_RTR_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 if (!msm_ipc_sk(sk)->default_node_vote_info)
266 msm_ipc_sk(sk)->default_node_vote_info =
267 msm_ipc_load_default_node();
268 lock_sock(sk);
269
270 ret = msm_ipc_router_register_server(port_ptr, &addr->address);
271
272 release_sock(sk);
273 return ret;
274}
275
276static int ipc_router_connect(struct socket *sock, struct sockaddr *uaddr,
277 int uaddr_len, int flags)
278{
279 struct sockaddr_msm_ipc *addr = (struct sockaddr_msm_ipc *)uaddr;
280 struct sock *sk = sock->sk;
281 struct msm_ipc_port *port_ptr;
282 int ret;
283
284 if (!sk)
285 return -EINVAL;
286
287 if (uaddr_len <= 0) {
288 IPC_RTR_ERR("%s: Invalid address length\n", __func__);
289 return -EINVAL;
290 }
291
292 if (!addr) {
293 IPC_RTR_ERR("%s: Invalid address\n", __func__);
294 return -EINVAL;
295 }
296
297 if (addr->family != AF_MSM_IPC) {
298 IPC_RTR_ERR("%s: Address family is incorrect\n", __func__);
299 return -EAFNOSUPPORT;
300 }
301
302 port_ptr = msm_ipc_sk_port(sk);
303 if (!port_ptr)
304 return -ENODEV;
305
306 lock_sock(sk);
307 ret = ipc_router_set_conn(port_ptr, &addr->address);
308 release_sock(sk);
309 return ret;
310}
311
312static int msm_ipc_router_sendmsg(struct socket *sock,
313 struct msghdr *m, size_t total_len)
314{
315 struct sock *sk = sock->sk;
316 struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
317 struct sockaddr_msm_ipc *dest = (struct sockaddr_msm_ipc *)m->msg_name;
318 struct sk_buff_head *msg;
319 int ret;
320 struct msm_ipc_addr dest_addr = {0};
321 long timeout;
322
323 if (dest) {
324 if (m->msg_namelen < sizeof(*dest) ||
325 dest->family != AF_MSM_IPC)
326 return -EINVAL;
327 memcpy(&dest_addr, &dest->address, sizeof(dest_addr));
328 } else {
329 if (port_ptr->conn_status == NOT_CONNECTED)
330 return -EDESTADDRREQ;
331 if (port_ptr->conn_status < CONNECTION_RESET)
332 return -ENETRESET;
333 memcpy(&dest_addr.addr.port_addr, &port_ptr->dest_addr,
334 sizeof(struct msm_ipc_port_addr));
335 dest_addr.addrtype = MSM_IPC_ADDR_ID;
336 }
337
338 if (total_len > MAX_IPC_PKT_SIZE)
339 return -EINVAL;
340
341 lock_sock(sk);
342 timeout = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);
343 msg = msm_ipc_router_build_msg(m, total_len);
344 if (!msg) {
345 IPC_RTR_ERR("%s: Msg build failure\n", __func__);
346 ret = -ENOMEM;
347 goto out_sendmsg;
348 }
349 kmemleak_not_leak(msg);
350
351 if (port_ptr->type == CLIENT_PORT)
352 wait_for_irsc_completion();
353 ret = msm_ipc_router_send_to(port_ptr, msg, &dest_addr, timeout);
354 if (ret != total_len) {
355 if (ret < 0) {
356 if (ret != -EAGAIN)
357 IPC_RTR_ERR("%s: Send_to failure %d\n",
358 __func__, ret);
359 msm_ipc_router_free_skb(msg);
360 } else if (ret >= 0) {
361 ret = -EFAULT;
362 }
363 }
364
365out_sendmsg:
366 release_sock(sk);
367 return ret;
368}
369
370static int msm_ipc_router_recvmsg(struct socket *sock,
371 struct msghdr *m, size_t buf_len, int flags)
372{
373 struct sock *sk = sock->sk;
374 struct msm_ipc_port *port_ptr = msm_ipc_sk_port(sk);
375 struct rr_packet *pkt;
376 long timeout;
377 int ret;
378
379 lock_sock(sk);
380 if (!buf_len) {
381 if (flags & MSG_PEEK)
382 ret = msm_ipc_router_get_curr_pkt_size(port_ptr);
383 else
384 ret = -EINVAL;
385 release_sock(sk);
386 return ret;
387 }
388 timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
389
390 ret = msm_ipc_router_rx_data_wait(port_ptr, timeout);
391 if (ret) {
392 release_sock(sk);
393 if (ret == -ENOMSG)
394 m->msg_namelen = 0;
395 return ret;
396 }
397
398 ret = msm_ipc_router_read(port_ptr, &pkt, buf_len);
399 if (ret <= 0 || !pkt) {
400 release_sock(sk);
401 return ret;
402 }
403
404 ret = msm_ipc_router_extract_msg(m, pkt);
405 release_pkt(pkt);
406 release_sock(sk);
407 return ret;
408}
409
410static int msm_ipc_router_ioctl(struct socket *sock,
411 unsigned int cmd, unsigned long arg)
412{
413 struct sock *sk = sock->sk;
414 struct msm_ipc_port *port_ptr;
415 struct server_lookup_args server_arg;
416 struct msm_ipc_server_info *srv_info = NULL;
417 unsigned int n;
418 size_t srv_info_sz = 0;
419 int ret;
420
421 if (!sk)
422 return -EINVAL;
423
424 lock_sock(sk);
425 port_ptr = msm_ipc_sk_port(sock->sk);
426 if (!port_ptr) {
427 release_sock(sk);
428 return -EINVAL;
429 }
430
431 switch (cmd) {
432 case IPC_ROUTER_IOCTL_GET_VERSION:
433 n = IPC_ROUTER_V1;
434 ret = put_user(n, (unsigned int *)arg);
435 break;
436
437 case IPC_ROUTER_IOCTL_GET_MTU:
438 n = (MAX_IPC_PKT_SIZE - IPC_ROUTER_HDR_SIZE);
439 ret = put_user(n, (unsigned int *)arg);
440 break;
441
442 case IPC_ROUTER_IOCTL_GET_CURR_PKT_SIZE:
443 ret = msm_ipc_router_get_curr_pkt_size(port_ptr);
444 break;
445
446 case IPC_ROUTER_IOCTL_LOOKUP_SERVER:
447 if (!msm_ipc_sk(sk)->default_node_vote_info)
448 msm_ipc_sk(sk)->default_node_vote_info =
449 msm_ipc_load_default_node();
450
451 ret = copy_from_user(&server_arg, (void *)arg,
452 sizeof(server_arg));
453 if (ret) {
454 ret = -EFAULT;
455 break;
456 }
457
458 if (server_arg.num_entries_in_array < 0) {
459 ret = -EINVAL;
460 break;
461 }
462 if (server_arg.num_entries_in_array) {
463 if (server_arg.num_entries_in_array >
464 (SIZE_MAX / sizeof(*srv_info))) {
465 IPC_RTR_ERR("%s: Integer Overflow %zu * %d\n",
466 __func__, sizeof(*srv_info),
467 server_arg.num_entries_in_array);
468 ret = -EINVAL;
469 break;
470 }
471 srv_info_sz = server_arg.num_entries_in_array *
472 sizeof(*srv_info);
473 srv_info = kmalloc(srv_info_sz, GFP_KERNEL);
474 if (!srv_info) {
475 ret = -ENOMEM;
476 break;
477 }
478 }
479 ret = msm_ipc_router_lookup_server_name
480 (&server_arg.port_name, srv_info,
481 server_arg.num_entries_in_array,
482 server_arg.lookup_mask);
483 if (ret < 0) {
484 IPC_RTR_ERR("%s: Server not found\n", __func__);
485 ret = -ENODEV;
486 kfree(srv_info);
487 break;
488 }
489 server_arg.num_entries_found = ret;
490
491 ret = copy_to_user((void *)arg, &server_arg,
492 sizeof(server_arg));
493
494 n = min(server_arg.num_entries_found,
495 server_arg.num_entries_in_array);
496
497 if (ret == 0 && n) {
498 ret = copy_to_user((void *)(arg + sizeof(server_arg)),
499 srv_info, n * sizeof(*srv_info));
500 }
501
502 if (ret)
503 ret = -EFAULT;
504 kfree(srv_info);
505 break;
506
507 case IPC_ROUTER_IOCTL_BIND_CONTROL_PORT:
508 ret = msm_ipc_router_bind_control_port(port_ptr);
509 break;
510
511 case IPC_ROUTER_IOCTL_CONFIG_SEC_RULES:
512 ret = msm_ipc_config_sec_rules((void *)arg);
513 if (ret != -EPERM)
514 port_ptr->type = IRSC_PORT;
515 break;
516
517 default:
518 ret = -EINVAL;
519 }
520 release_sock(sk);
521 return ret;
522}
523
524static unsigned int msm_ipc_router_poll(struct file *file, struct socket *sock,
525 poll_table *wait)
526{
527 struct sock *sk = sock->sk;
528 struct msm_ipc_port *port_ptr;
529 u32 mask = 0;
530
531 if (!sk)
532 return -EINVAL;
533
534 port_ptr = msm_ipc_sk_port(sk);
535 if (!port_ptr)
536 return -EINVAL;
537
538 poll_wait(file, &port_ptr->port_rx_wait_q, wait);
539
540 if (!list_empty(&port_ptr->port_rx_q))
541 mask |= (POLLRDNORM | POLLIN);
542
543 if (port_ptr->conn_status == CONNECTION_RESET)
544 mask |= (POLLHUP | POLLERR);
545
546 return mask;
547}
548
549static int msm_ipc_router_close(struct socket *sock)
550{
551 struct sock *sk = sock->sk;
Arun Kumar Neelakantam3fc03e02016-09-21 18:34:01 +0530552 struct msm_ipc_port *port_ptr;
Karthikeyan Ramasubramanian6a116d62016-09-16 16:05:32 -0600553 int ret;
554
Arun Kumar Neelakantam3fc03e02016-09-21 18:34:01 +0530555 if (!sk)
556 return -EINVAL;
557
Karthikeyan Ramasubramanian6a116d62016-09-16 16:05:32 -0600558 lock_sock(sk);
Arun Kumar Neelakantam3fc03e02016-09-21 18:34:01 +0530559 port_ptr = msm_ipc_sk_port(sk);
560 if (!port_ptr) {
561 release_sock(sk);
562 return -EINVAL;
563 }
Karthikeyan Ramasubramanian6a116d62016-09-16 16:05:32 -0600564 ret = msm_ipc_router_close_port(port_ptr);
565 msm_ipc_unload_default_node(msm_ipc_sk(sk)->default_node_vote_info);
566 release_sock(sk);
567 sock_put(sk);
568 sock->sk = NULL;
569
570 return ret;
571}
572
573/**
574 * register_ipcrtr_af_init_notifier() - Register for ipc router socket
575 * address family initialization callback
576 * @nb: Notifier block which will be notified when address family is
577 * initialized.
578 *
579 * Return: 0 on success, standard error code otherwise.
580 */
581int register_ipcrtr_af_init_notifier(struct notifier_block *nb)
582{
583 int ret;
584
585 if (!nb)
586 return -EINVAL;
587 mutex_lock(&ipcrtr_af_init_lock);
588 if (sockets_enabled)
589 nb->notifier_call(nb, IPCRTR_AF_INIT, NULL);
590 ret = raw_notifier_chain_register(&ipcrtr_af_init_chain, nb);
591 mutex_unlock(&ipcrtr_af_init_lock);
592 return ret;
593}
594EXPORT_SYMBOL(register_ipcrtr_af_init_notifier);
595
596/**
597 * unregister_ipcrtr_af_init_notifier() - Unregister for ipc router socket
598 * address family initialization callback
599 * @nb: Notifier block which will be notified once address family is
600 * initialized.
601 *
602 * Return: 0 on success, standard error code otherwise.
603 */
604int unregister_ipcrtr_af_init_notifier(struct notifier_block *nb)
605{
606 int ret;
607
608 if (!nb)
609 return -EINVAL;
610 ret = raw_notifier_chain_unregister(&ipcrtr_af_init_chain, nb);
611 return ret;
612}
613EXPORT_SYMBOL(unregister_ipcrtr_af_init_notifier);
614
615static const struct net_proto_family msm_ipc_family_ops = {
616 .owner = THIS_MODULE,
617 .family = AF_MSM_IPC,
618 .create = msm_ipc_router_create
619};
620
621static const struct proto_ops msm_ipc_proto_ops = {
622 .family = AF_MSM_IPC,
623 .owner = THIS_MODULE,
624 .release = msm_ipc_router_close,
625 .bind = msm_ipc_router_bind,
626 .connect = ipc_router_connect,
627 .socketpair = sock_no_socketpair,
628 .accept = sock_no_accept,
629 .getname = sock_no_getname,
630 .poll = msm_ipc_router_poll,
631 .ioctl = msm_ipc_router_ioctl,
632#ifdef CONFIG_COMPAT
633 .compat_ioctl = msm_ipc_router_ioctl,
634#endif
635 .listen = sock_no_listen,
636 .shutdown = sock_no_shutdown,
637 .setsockopt = sock_no_setsockopt,
638 .getsockopt = sock_no_getsockopt,
639#ifdef CONFIG_COMPAT
640 .compat_setsockopt = sock_no_setsockopt,
641 .compat_getsockopt = sock_no_getsockopt,
642#endif
643 .sendmsg = msm_ipc_router_sendmsg,
644 .recvmsg = msm_ipc_router_recvmsg,
645 .mmap = sock_no_mmap,
646 .sendpage = sock_no_sendpage,
647};
648
649static struct proto msm_ipc_proto = {
650 .name = "MSM_IPC",
651 .owner = THIS_MODULE,
652 .obj_size = sizeof(struct msm_ipc_sock),
653};
654
655int msm_ipc_router_init_sockets(void)
656{
657 int ret;
658
659 ret = proto_register(&msm_ipc_proto, 1);
660 if (ret) {
661 IPC_RTR_ERR("%s: Failed to register MSM_IPC protocol type\n",
662 __func__);
663 goto out_init_sockets;
664 }
665
666 ret = sock_register(&msm_ipc_family_ops);
667 if (ret) {
668 IPC_RTR_ERR("%s: Failed to register MSM_IPC socket type\n",
669 __func__);
670 proto_unregister(&msm_ipc_proto);
671 goto out_init_sockets;
672 }
673
674 mutex_lock(&ipcrtr_af_init_lock);
675 sockets_enabled = 1;
676 raw_notifier_call_chain(&ipcrtr_af_init_chain,
677 IPCRTR_AF_INIT, NULL);
678 mutex_unlock(&ipcrtr_af_init_lock);
679out_init_sockets:
680 return ret;
681}
682
683void msm_ipc_router_exit_sockets(void)
684{
685 if (!sockets_enabled)
686 return;
687
688 sock_unregister(msm_ipc_family_ops.family);
689 proto_unregister(&msm_ipc_proto);
690 mutex_lock(&ipcrtr_af_init_lock);
691 sockets_enabled = 0;
692 raw_notifier_call_chain(&ipcrtr_af_init_chain,
693 IPCRTR_AF_DEINIT, NULL);
694 mutex_unlock(&ipcrtr_af_init_lock);
695}