1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* 3 * Copyright (c) 2015, Sony Mobile Communications Inc. 4 * Copyright (c) 2013, The Linux Foundation. All rights reserved. 5 * Copyright (c) 2020, Linaro Ltd. 6 */ 7 8 #include <linux/module.h> 9 #include <linux/qrtr.h> 10 #include <linux/workqueue.h> 11 #include <net/sock.h> 12 13 #include "qrtr.h" 14 15 #define CREATE_TRACE_POINTS 16 #include <trace/events/qrtr.h> 17 18 static RADIX_TREE(nodes, GFP_KERNEL); 19 20 static struct { 21 struct socket *sock; 22 struct sockaddr_qrtr bcast_sq; 23 struct list_head lookups; 24 struct workqueue_struct *workqueue; 25 struct work_struct work; 26 int local_node; 27 } qrtr_ns; 28 29 static const char * const qrtr_ctrl_pkt_strings[] = { 30 [QRTR_TYPE_HELLO] = "hello", 31 [QRTR_TYPE_BYE] = "bye", 32 [QRTR_TYPE_NEW_SERVER] = "new-server", 33 [QRTR_TYPE_DEL_SERVER] = "del-server", 34 [QRTR_TYPE_DEL_CLIENT] = "del-client", 35 [QRTR_TYPE_RESUME_TX] = "resume-tx", 36 [QRTR_TYPE_EXIT] = "exit", 37 [QRTR_TYPE_PING] = "ping", 38 [QRTR_TYPE_NEW_LOOKUP] = "new-lookup", 39 [QRTR_TYPE_DEL_LOOKUP] = "del-lookup", 40 }; 41 42 struct qrtr_server_filter { 43 unsigned int service; 44 unsigned int instance; 45 unsigned int ifilter; 46 }; 47 48 struct qrtr_lookup { 49 unsigned int service; 50 unsigned int instance; 51 52 struct sockaddr_qrtr sq; 53 struct list_head li; 54 }; 55 56 struct qrtr_server { 57 unsigned int service; 58 unsigned int instance; 59 60 unsigned int node; 61 unsigned int port; 62 63 struct list_head qli; 64 }; 65 66 struct qrtr_node { 67 unsigned int id; 68 struct radix_tree_root servers; 69 }; 70 71 static struct qrtr_node *node_get(unsigned int node_id) 72 { 73 struct qrtr_node *node; 74 75 node = radix_tree_lookup(&nodes, node_id); 76 if (node) 77 return node; 78 79 /* If node didn't exist, allocate and insert it to the tree */ 80 node = kzalloc(sizeof(*node), GFP_KERNEL); 81 if (!node) 82 return NULL; 83 84 node->id = node_id; 85 86 radix_tree_insert(&nodes, node_id, node); 87 88 return node; 89 } 90 91 static int server_match(const struct qrtr_server *srv, 92 const struct qrtr_server_filter *f) 93 { 94 unsigned int ifilter = f->ifilter; 95 96 if (f->service != 0 && srv->service != f->service) 97 return 0; 98 if (!ifilter && f->instance) 99 ifilter = ~0; 100 101 return (srv->instance & ifilter) == f->instance; 102 } 103 104 static int service_announce_new(struct sockaddr_qrtr *dest, 105 struct qrtr_server *srv) 106 { 107 struct qrtr_ctrl_pkt pkt; 108 struct msghdr msg = { }; 109 struct kvec iv; 110 111 trace_qrtr_ns_service_announce_new(srv->service, srv->instance, 112 srv->node, srv->port); 113 114 iv.iov_base = &pkt; 115 iv.iov_len = sizeof(pkt); 116 117 memset(&pkt, 0, sizeof(pkt)); 118 pkt.cmd = cpu_to_le32(QRTR_TYPE_NEW_SERVER); 119 pkt.server.service = cpu_to_le32(srv->service); 120 pkt.server.instance = cpu_to_le32(srv->instance); 121 pkt.server.node = cpu_to_le32(srv->node); 122 pkt.server.port = cpu_to_le32(srv->port); 123 124 msg.msg_name = (struct sockaddr *)dest; 125 msg.msg_namelen = sizeof(*dest); 126 127 return kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt)); 128 } 129 130 static int service_announce_del(struct sockaddr_qrtr *dest, 131 struct qrtr_server *srv) 132 { 133 struct qrtr_ctrl_pkt pkt; 134 struct msghdr msg = { }; 135 struct kvec iv; 136 int ret; 137 138 trace_qrtr_ns_service_announce_del(srv->service, srv->instance, 139 srv->node, srv->port); 140 141 iv.iov_base = &pkt; 142 iv.iov_len = sizeof(pkt); 143 144 memset(&pkt, 0, sizeof(pkt)); 145 pkt.cmd = cpu_to_le32(QRTR_TYPE_DEL_SERVER); 146 pkt.server.service = cpu_to_le32(srv->service); 147 pkt.server.instance = cpu_to_le32(srv->instance); 148 pkt.server.node = cpu_to_le32(srv->node); 149 pkt.server.port = cpu_to_le32(srv->port); 150 151 msg.msg_name = (struct sockaddr *)dest; 152 msg.msg_namelen = sizeof(*dest); 153 154 ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt)); 155 if (ret < 0) 156 pr_err("failed to announce del service\n"); 157 158 return ret; 159 } 160 161 static void lookup_notify(struct sockaddr_qrtr *to, struct qrtr_server *srv, 162 bool new) 163 { 164 struct qrtr_ctrl_pkt pkt; 165 struct msghdr msg = { }; 166 struct kvec iv; 167 int ret; 168 169 iv.iov_base = &pkt; 170 iv.iov_len = sizeof(pkt); 171 172 memset(&pkt, 0, sizeof(pkt)); 173 pkt.cmd = new ? cpu_to_le32(QRTR_TYPE_NEW_SERVER) : 174 cpu_to_le32(QRTR_TYPE_DEL_SERVER); 175 if (srv) { 176 pkt.server.service = cpu_to_le32(srv->service); 177 pkt.server.instance = cpu_to_le32(srv->instance); 178 pkt.server.node = cpu_to_le32(srv->node); 179 pkt.server.port = cpu_to_le32(srv->port); 180 } 181 182 msg.msg_name = (struct sockaddr *)to; 183 msg.msg_namelen = sizeof(*to); 184 185 ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt)); 186 if (ret < 0) 187 pr_err("failed to send lookup notification\n"); 188 } 189 190 static int announce_servers(struct sockaddr_qrtr *sq) 191 { 192 struct radix_tree_iter iter; 193 struct qrtr_server *srv; 194 struct qrtr_node *node; 195 void __rcu **slot; 196 int ret; 197 198 node = node_get(qrtr_ns.local_node); 199 if (!node) 200 return 0; 201 202 /* Announce the list of servers registered in this node */ 203 radix_tree_for_each_slot(slot, &node->servers, &iter, 0) { 204 srv = radix_tree_deref_slot(slot); 205 206 ret = service_announce_new(sq, srv); 207 if (ret < 0) { 208 pr_err("failed to announce new service\n"); 209 return ret; 210 } 211 } 212 213 return 0; 214 } 215 216 static struct qrtr_server *server_add(unsigned int service, 217 unsigned int instance, 218 unsigned int node_id, 219 unsigned int port) 220 { 221 struct qrtr_server *srv; 222 struct qrtr_server *old; 223 struct qrtr_node *node; 224 225 if (!service || !port) 226 return NULL; 227 228 srv = kzalloc(sizeof(*srv), GFP_KERNEL); 229 if (!srv) 230 return NULL; 231 232 srv->service = service; 233 srv->instance = instance; 234 srv->node = node_id; 235 srv->port = port; 236 237 node = node_get(node_id); 238 if (!node) 239 goto err; 240 241 /* Delete the old server on the same port */ 242 old = radix_tree_lookup(&node->servers, port); 243 if (old) { 244 radix_tree_delete(&node->servers, port); 245 kfree(old); 246 } 247 248 radix_tree_insert(&node->servers, port, srv); 249 250 trace_qrtr_ns_server_add(srv->service, srv->instance, 251 srv->node, srv->port); 252 253 return srv; 254 255 err: 256 kfree(srv); 257 return NULL; 258 } 259 260 static int server_del(struct qrtr_node *node, unsigned int port) 261 { 262 struct qrtr_lookup *lookup; 263 struct qrtr_server *srv; 264 struct list_head *li; 265 266 srv = radix_tree_lookup(&node->servers, port); 267 if (!srv) 268 return -ENOENT; 269 270 radix_tree_delete(&node->servers, port); 271 272 /* Broadcast the removal of local servers */ 273 if (srv->node == qrtr_ns.local_node) 274 service_announce_del(&qrtr_ns.bcast_sq, srv); 275 276 /* Announce the service's disappearance to observers */ 277 list_for_each(li, &qrtr_ns.lookups) { 278 lookup = container_of(li, struct qrtr_lookup, li); 279 if (lookup->service && lookup->service != srv->service) 280 continue; 281 if (lookup->instance && lookup->instance != srv->instance) 282 continue; 283 284 lookup_notify(&lookup->sq, srv, false); 285 } 286 287 kfree(srv); 288 289 return 0; 290 } 291 292 static int say_hello(struct sockaddr_qrtr *dest) 293 { 294 struct qrtr_ctrl_pkt pkt; 295 struct msghdr msg = { }; 296 struct kvec iv; 297 int ret; 298 299 iv.iov_base = &pkt; 300 iv.iov_len = sizeof(pkt); 301 302 memset(&pkt, 0, sizeof(pkt)); 303 pkt.cmd = cpu_to_le32(QRTR_TYPE_HELLO); 304 305 msg.msg_name = (struct sockaddr *)dest; 306 msg.msg_namelen = sizeof(*dest); 307 308 ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt)); 309 if (ret < 0) 310 pr_err("failed to send hello msg\n"); 311 312 return ret; 313 } 314 315 /* Announce the list of servers registered on the local node */ 316 static int ctrl_cmd_hello(struct sockaddr_qrtr *sq) 317 { 318 int ret; 319 320 ret = say_hello(sq); 321 if (ret < 0) 322 return ret; 323 324 return announce_servers(sq); 325 } 326 327 static int ctrl_cmd_bye(struct sockaddr_qrtr *from) 328 { 329 struct qrtr_node *local_node; 330 struct radix_tree_iter iter; 331 struct qrtr_ctrl_pkt pkt; 332 struct qrtr_server *srv; 333 struct sockaddr_qrtr sq; 334 struct msghdr msg = { }; 335 struct qrtr_node *node; 336 void __rcu **slot; 337 struct kvec iv; 338 int ret; 339 340 iv.iov_base = &pkt; 341 iv.iov_len = sizeof(pkt); 342 343 node = node_get(from->sq_node); 344 if (!node) 345 return 0; 346 347 /* Advertise removal of this client to all servers of remote node */ 348 radix_tree_for_each_slot(slot, &node->servers, &iter, 0) { 349 srv = radix_tree_deref_slot(slot); 350 server_del(node, srv->port); 351 } 352 353 /* Advertise the removal of this client to all local servers */ 354 local_node = node_get(qrtr_ns.local_node); 355 if (!local_node) 356 return 0; 357 358 memset(&pkt, 0, sizeof(pkt)); 359 pkt.cmd = cpu_to_le32(QRTR_TYPE_BYE); 360 pkt.client.node = cpu_to_le32(from->sq_node); 361 362 radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) { 363 srv = radix_tree_deref_slot(slot); 364 365 sq.sq_family = AF_QIPCRTR; 366 sq.sq_node = srv->node; 367 sq.sq_port = srv->port; 368 369 msg.msg_name = (struct sockaddr *)&sq; 370 msg.msg_namelen = sizeof(sq); 371 372 ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt)); 373 if (ret < 0) { 374 pr_err("failed to send bye cmd\n"); 375 return ret; 376 } 377 } 378 379 return 0; 380 } 381 382 static int ctrl_cmd_del_client(struct sockaddr_qrtr *from, 383 unsigned int node_id, unsigned int port) 384 { 385 struct qrtr_node *local_node; 386 struct radix_tree_iter iter; 387 struct qrtr_lookup *lookup; 388 struct qrtr_ctrl_pkt pkt; 389 struct msghdr msg = { }; 390 struct qrtr_server *srv; 391 struct sockaddr_qrtr sq; 392 struct qrtr_node *node; 393 struct list_head *tmp; 394 struct list_head *li; 395 void __rcu **slot; 396 struct kvec iv; 397 int ret; 398 399 iv.iov_base = &pkt; 400 iv.iov_len = sizeof(pkt); 401 402 /* Don't accept spoofed messages */ 403 if (from->sq_node != node_id) 404 return -EINVAL; 405 406 /* Local DEL_CLIENT messages comes from the port being closed */ 407 if (from->sq_node == qrtr_ns.local_node && from->sq_port != port) 408 return -EINVAL; 409 410 /* Remove any lookups by this client */ 411 list_for_each_safe(li, tmp, &qrtr_ns.lookups) { 412 lookup = container_of(li, struct qrtr_lookup, li); 413 if (lookup->sq.sq_node != node_id) 414 continue; 415 if (lookup->sq.sq_port != port) 416 continue; 417 418 list_del(&lookup->li); 419 kfree(lookup); 420 } 421 422 /* Remove the server belonging to this port */ 423 node = node_get(node_id); 424 if (node) 425 server_del(node, port); 426 427 /* Advertise the removal of this client to all local servers */ 428 local_node = node_get(qrtr_ns.local_node); 429 if (!local_node) 430 return 0; 431 432 memset(&pkt, 0, sizeof(pkt)); 433 pkt.cmd = cpu_to_le32(QRTR_TYPE_DEL_CLIENT); 434 pkt.client.node = cpu_to_le32(node_id); 435 pkt.client.port = cpu_to_le32(port); 436 437 radix_tree_for_each_slot(slot, &local_node->servers, &iter, 0) { 438 srv = radix_tree_deref_slot(slot); 439 440 sq.sq_family = AF_QIPCRTR; 441 sq.sq_node = srv->node; 442 sq.sq_port = srv->port; 443 444 msg.msg_name = (struct sockaddr *)&sq; 445 msg.msg_namelen = sizeof(sq); 446 447 ret = kernel_sendmsg(qrtr_ns.sock, &msg, &iv, 1, sizeof(pkt)); 448 if (ret < 0) { 449 pr_err("failed to send del client cmd\n"); 450 return ret; 451 } 452 } 453 454 return 0; 455 } 456 457 static int ctrl_cmd_new_server(struct sockaddr_qrtr *from, 458 unsigned int service, unsigned int instance, 459 unsigned int node_id, unsigned int port) 460 { 461 struct qrtr_lookup *lookup; 462 struct qrtr_server *srv; 463 struct list_head *li; 464 int ret = 0; 465 466 /* Ignore specified node and port for local servers */ 467 if (from->sq_node == qrtr_ns.local_node) { 468 node_id = from->sq_node; 469 port = from->sq_port; 470 } 471 472 /* Don't accept spoofed messages */ 473 if (from->sq_node != node_id) 474 return -EINVAL; 475 476 srv = server_add(service, instance, node_id, port); 477 if (!srv) 478 return -EINVAL; 479 480 if (srv->node == qrtr_ns.local_node) { 481 ret = service_announce_new(&qrtr_ns.bcast_sq, srv); 482 if (ret < 0) { 483 pr_err("failed to announce new service\n"); 484 return ret; 485 } 486 } 487 488 /* Notify any potential lookups about the new server */ 489 list_for_each(li, &qrtr_ns.lookups) { 490 lookup = container_of(li, struct qrtr_lookup, li); 491 if (lookup->service && lookup->service != service) 492 continue; 493 if (lookup->instance && lookup->instance != instance) 494 continue; 495 496 lookup_notify(&lookup->sq, srv, true); 497 } 498 499 return ret; 500 } 501 502 static int ctrl_cmd_del_server(struct sockaddr_qrtr *from, 503 unsigned int service, unsigned int instance, 504 unsigned int node_id, unsigned int port) 505 { 506 struct qrtr_node *node; 507 508 /* Ignore specified node and port for local servers*/ 509 if (from->sq_node == qrtr_ns.local_node) { 510 node_id = from->sq_node; 511 port = from->sq_port; 512 } 513 514 /* Don't accept spoofed messages */ 515 if (from->sq_node != node_id) 516 return -EINVAL; 517 518 /* Local servers may only unregister themselves */ 519 if (from->sq_node == qrtr_ns.local_node && from->sq_port != port) 520 return -EINVAL; 521 522 node = node_get(node_id); 523 if (!node) 524 return -ENOENT; 525 526 return server_del(node, port); 527 } 528 529 static int ctrl_cmd_new_lookup(struct sockaddr_qrtr *from, 530 unsigned int service, unsigned int instance) 531 { 532 struct radix_tree_iter node_iter; 533 struct qrtr_server_filter filter; 534 struct radix_tree_iter srv_iter; 535 struct qrtr_lookup *lookup; 536 struct qrtr_node *node; 537 void __rcu **node_slot; 538 void __rcu **srv_slot; 539 540 /* Accept only local observers */ 541 if (from->sq_node != qrtr_ns.local_node) 542 return -EINVAL; 543 544 lookup = kzalloc(sizeof(*lookup), GFP_KERNEL); 545 if (!lookup) 546 return -ENOMEM; 547 548 lookup->sq = *from; 549 lookup->service = service; 550 lookup->instance = instance; 551 list_add_tail(&lookup->li, &qrtr_ns.lookups); 552 553 memset(&filter, 0, sizeof(filter)); 554 filter.service = service; 555 filter.instance = instance; 556 557 radix_tree_for_each_slot(node_slot, &nodes, &node_iter, 0) { 558 node = radix_tree_deref_slot(node_slot); 559 560 radix_tree_for_each_slot(srv_slot, &node->servers, 561 &srv_iter, 0) { 562 struct qrtr_server *srv; 563 564 srv = radix_tree_deref_slot(srv_slot); 565 if (!server_match(srv, &filter)) 566 continue; 567 568 lookup_notify(from, srv, true); 569 } 570 } 571 572 /* Empty notification, to indicate end of listing */ 573 lookup_notify(from, NULL, true); 574 575 return 0; 576 } 577 578 static void ctrl_cmd_del_lookup(struct sockaddr_qrtr *from, 579 unsigned int service, unsigned int instance) 580 { 581 struct qrtr_lookup *lookup; 582 struct list_head *tmp; 583 struct list_head *li; 584 585 list_for_each_safe(li, tmp, &qrtr_ns.lookups) { 586 lookup = container_of(li, struct qrtr_lookup, li); 587 if (lookup->sq.sq_node != from->sq_node) 588 continue; 589 if (lookup->sq.sq_port != from->sq_port) 590 continue; 591 if (lookup->service != service) 592 continue; 593 if (lookup->instance && lookup->instance != instance) 594 continue; 595 596 list_del(&lookup->li); 597 kfree(lookup); 598 } 599 } 600 601 static void qrtr_ns_worker(struct work_struct *work) 602 { 603 const struct qrtr_ctrl_pkt *pkt; 604 size_t recv_buf_size = 4096; 605 struct sockaddr_qrtr sq; 606 struct msghdr msg = { }; 607 unsigned int cmd; 608 ssize_t msglen; 609 void *recv_buf; 610 struct kvec iv; 611 int ret; 612 613 msg.msg_name = (struct sockaddr *)&sq; 614 msg.msg_namelen = sizeof(sq); 615 616 recv_buf = kzalloc(recv_buf_size, GFP_KERNEL); 617 if (!recv_buf) 618 return; 619 620 for (;;) { 621 iv.iov_base = recv_buf; 622 iv.iov_len = recv_buf_size; 623 624 msglen = kernel_recvmsg(qrtr_ns.sock, &msg, &iv, 1, 625 iv.iov_len, MSG_DONTWAIT); 626 627 if (msglen == -EAGAIN) 628 break; 629 630 if (msglen < 0) { 631 pr_err("error receiving packet: %zd\n", msglen); 632 break; 633 } 634 635 pkt = recv_buf; 636 cmd = le32_to_cpu(pkt->cmd); 637 if (cmd < ARRAY_SIZE(qrtr_ctrl_pkt_strings) && 638 qrtr_ctrl_pkt_strings[cmd]) 639 trace_qrtr_ns_message(qrtr_ctrl_pkt_strings[cmd], 640 sq.sq_node, sq.sq_port); 641 642 ret = 0; 643 switch (cmd) { 644 case QRTR_TYPE_HELLO: 645 ret = ctrl_cmd_hello(&sq); 646 break; 647 case QRTR_TYPE_BYE: 648 ret = ctrl_cmd_bye(&sq); 649 break; 650 case QRTR_TYPE_DEL_CLIENT: 651 ret = ctrl_cmd_del_client(&sq, 652 le32_to_cpu(pkt->client.node), 653 le32_to_cpu(pkt->client.port)); 654 break; 655 case QRTR_TYPE_NEW_SERVER: 656 ret = ctrl_cmd_new_server(&sq, 657 le32_to_cpu(pkt->server.service), 658 le32_to_cpu(pkt->server.instance), 659 le32_to_cpu(pkt->server.node), 660 le32_to_cpu(pkt->server.port)); 661 break; 662 case QRTR_TYPE_DEL_SERVER: 663 ret = ctrl_cmd_del_server(&sq, 664 le32_to_cpu(pkt->server.service), 665 le32_to_cpu(pkt->server.instance), 666 le32_to_cpu(pkt->server.node), 667 le32_to_cpu(pkt->server.port)); 668 break; 669 case QRTR_TYPE_EXIT: 670 case QRTR_TYPE_PING: 671 case QRTR_TYPE_RESUME_TX: 672 break; 673 case QRTR_TYPE_NEW_LOOKUP: 674 ret = ctrl_cmd_new_lookup(&sq, 675 le32_to_cpu(pkt->server.service), 676 le32_to_cpu(pkt->server.instance)); 677 break; 678 case QRTR_TYPE_DEL_LOOKUP: 679 ctrl_cmd_del_lookup(&sq, 680 le32_to_cpu(pkt->server.service), 681 le32_to_cpu(pkt->server.instance)); 682 break; 683 } 684 685 if (ret < 0) 686 pr_err("failed while handling packet from %d:%d", 687 sq.sq_node, sq.sq_port); 688 } 689 690 kfree(recv_buf); 691 } 692 693 static void qrtr_ns_data_ready(struct sock *sk) 694 { 695 queue_work(qrtr_ns.workqueue, &qrtr_ns.work); 696 } 697 698 void qrtr_ns_init(void) 699 { 700 struct sockaddr_qrtr sq; 701 int ret; 702 703 INIT_LIST_HEAD(&qrtr_ns.lookups); 704 INIT_WORK(&qrtr_ns.work, qrtr_ns_worker); 705 706 ret = sock_create_kern(&init_net, AF_QIPCRTR, SOCK_DGRAM, 707 PF_QIPCRTR, &qrtr_ns.sock); 708 if (ret < 0) 709 return; 710 711 ret = kernel_getsockname(qrtr_ns.sock, (struct sockaddr *)&sq); 712 if (ret < 0) { 713 pr_err("failed to get socket name\n"); 714 goto err_sock; 715 } 716 717 qrtr_ns.workqueue = alloc_workqueue("qrtr_ns_handler", WQ_UNBOUND, 1); 718 if (!qrtr_ns.workqueue) 719 goto err_sock; 720 721 qrtr_ns.sock->sk->sk_data_ready = qrtr_ns_data_ready; 722 723 sq.sq_port = QRTR_PORT_CTRL; 724 qrtr_ns.local_node = sq.sq_node; 725 726 ret = kernel_bind(qrtr_ns.sock, (struct sockaddr *)&sq, sizeof(sq)); 727 if (ret < 0) { 728 pr_err("failed to bind to socket\n"); 729 goto err_wq; 730 } 731 732 qrtr_ns.bcast_sq.sq_family = AF_QIPCRTR; 733 qrtr_ns.bcast_sq.sq_node = QRTR_NODE_BCAST; 734 qrtr_ns.bcast_sq.sq_port = QRTR_PORT_CTRL; 735 736 ret = say_hello(&qrtr_ns.bcast_sq); 737 if (ret < 0) 738 goto err_wq; 739 740 return; 741 742 err_wq: 743 destroy_workqueue(qrtr_ns.workqueue); 744 err_sock: 745 sock_release(qrtr_ns.sock); 746 } 747 EXPORT_SYMBOL_GPL(qrtr_ns_init); 748 749 void qrtr_ns_remove(void) 750 { 751 cancel_work_sync(&qrtr_ns.work); 752 destroy_workqueue(qrtr_ns.workqueue); 753 sock_release(qrtr_ns.sock); 754 } 755 EXPORT_SYMBOL_GPL(qrtr_ns_remove); 756 757 MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); 758 MODULE_DESCRIPTION("Qualcomm IPC Router Nameservice"); 759 MODULE_LICENSE("Dual BSD/GPL"); 760