1 // SPDX-License-Identifier: GPL-2.0 2 /* net/atm/svc.c - ATM SVC sockets */ 3 4 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ 5 6 #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ 7 8 #include <linux/string.h> 9 #include <linux/net.h> /* struct socket, struct proto_ops */ 10 #include <linux/errno.h> /* error codes */ 11 #include <linux/kernel.h> /* printk */ 12 #include <linux/skbuff.h> 13 #include <linux/wait.h> 14 #include <linux/sched/signal.h> 15 #include <linux/fcntl.h> /* O_NONBLOCK */ 16 #include <linux/init.h> 17 #include <linux/atm.h> /* ATM stuff */ 18 #include <linux/atmsap.h> 19 #include <linux/atmsvc.h> 20 #include <linux/atmdev.h> 21 #include <linux/bitops.h> 22 #include <net/sock.h> /* for sock_no_* */ 23 #include <linux/uaccess.h> 24 #include <linux/export.h> 25 26 #include "resources.h" 27 #include "common.h" /* common for PVCs and SVCs */ 28 #include "signaling.h" 29 #include "addr.h" 30 31 #ifdef CONFIG_COMPAT 32 /* It actually takes struct sockaddr_atmsvc, not struct atm_iobuf */ 33 #define COMPAT_ATM_ADDPARTY _IOW('a', ATMIOC_SPECIAL + 4, struct compat_atm_iobuf) 34 #endif 35 36 static int svc_create(struct net *net, struct socket *sock, int protocol, 37 int kern); 38 39 /* 40 * Note: since all this is still nicely synchronized with the signaling demon, 41 * there's no need to protect sleep loops with clis. If signaling is 42 * moved into the kernel, that would change. 43 */ 44 45 46 static int svc_shutdown(struct socket *sock, int how) 47 { 48 return 0; 49 } 50 51 static void svc_disconnect(struct atm_vcc *vcc) 52 { 53 DEFINE_WAIT(wait); 54 struct sk_buff *skb; 55 struct sock *sk = sk_atm(vcc); 56 57 pr_debug("%p\n", vcc); 58 if (test_bit(ATM_VF_REGIS, &vcc->flags)) { 59 sigd_enq(vcc, as_close, NULL, NULL, NULL); 60 for (;;) { 61 prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); 62 if (test_bit(ATM_VF_RELEASED, &vcc->flags) || !sigd) 63 break; 64 schedule(); 65 } 66 finish_wait(sk_sleep(sk), &wait); 67 } 68 /* beware - socket is still in use by atmsigd until the last 69 as_indicate has been answered */ 70 while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { 71 atm_return(vcc, skb->truesize); 72 pr_debug("LISTEN REL\n"); 73 sigd_enq2(NULL, as_reject, vcc, NULL, NULL, &vcc->qos, 0); 74 dev_kfree_skb(skb); 75 } 76 clear_bit(ATM_VF_REGIS, &vcc->flags); 77 /* ... may retry later */ 78 } 79 80 static int svc_release(struct socket *sock) 81 { 82 struct sock *sk = sock->sk; 83 struct atm_vcc *vcc; 84 85 if (sk) { 86 vcc = ATM_SD(sock); 87 pr_debug("%p\n", vcc); 88 clear_bit(ATM_VF_READY, &vcc->flags); 89 /* 90 * VCC pointer is used as a reference, 91 * so we must not free it (thereby subjecting it to re-use) 92 * before all pending connections are closed 93 */ 94 svc_disconnect(vcc); 95 vcc_release(sock); 96 } 97 return 0; 98 } 99 100 static int svc_bind(struct socket *sock, struct sockaddr *sockaddr, 101 int sockaddr_len) 102 { 103 DEFINE_WAIT(wait); 104 struct sock *sk = sock->sk; 105 struct sockaddr_atmsvc *addr; 106 struct atm_vcc *vcc; 107 int error; 108 109 if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) 110 return -EINVAL; 111 lock_sock(sk); 112 if (sock->state == SS_CONNECTED) { 113 error = -EISCONN; 114 goto out; 115 } 116 if (sock->state != SS_UNCONNECTED) { 117 error = -EINVAL; 118 goto out; 119 } 120 vcc = ATM_SD(sock); 121 addr = (struct sockaddr_atmsvc *) sockaddr; 122 if (addr->sas_family != AF_ATMSVC) { 123 error = -EAFNOSUPPORT; 124 goto out; 125 } 126 clear_bit(ATM_VF_BOUND, &vcc->flags); 127 /* failing rebind will kill old binding */ 128 /* @@@ check memory (de)allocation on rebind */ 129 if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) { 130 error = -EBADFD; 131 goto out; 132 } 133 vcc->local = *addr; 134 set_bit(ATM_VF_WAITING, &vcc->flags); 135 sigd_enq(vcc, as_bind, NULL, NULL, &vcc->local); 136 for (;;) { 137 prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); 138 if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd) 139 break; 140 schedule(); 141 } 142 finish_wait(sk_sleep(sk), &wait); 143 clear_bit(ATM_VF_REGIS, &vcc->flags); /* doesn't count */ 144 if (!sigd) { 145 error = -EUNATCH; 146 goto out; 147 } 148 if (!sk->sk_err) 149 set_bit(ATM_VF_BOUND, &vcc->flags); 150 error = -sk->sk_err; 151 out: 152 release_sock(sk); 153 return error; 154 } 155 156 static int svc_connect(struct socket *sock, struct sockaddr *sockaddr, 157 int sockaddr_len, int flags) 158 { 159 DEFINE_WAIT(wait); 160 struct sock *sk = sock->sk; 161 struct sockaddr_atmsvc *addr; 162 struct atm_vcc *vcc = ATM_SD(sock); 163 int error; 164 165 pr_debug("%p\n", vcc); 166 lock_sock(sk); 167 if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) { 168 error = -EINVAL; 169 goto out; 170 } 171 172 switch (sock->state) { 173 default: 174 error = -EINVAL; 175 goto out; 176 case SS_CONNECTED: 177 error = -EISCONN; 178 goto out; 179 case SS_CONNECTING: 180 if (test_bit(ATM_VF_WAITING, &vcc->flags)) { 181 error = -EALREADY; 182 goto out; 183 } 184 sock->state = SS_UNCONNECTED; 185 if (sk->sk_err) { 186 error = -sk->sk_err; 187 goto out; 188 } 189 break; 190 case SS_UNCONNECTED: 191 addr = (struct sockaddr_atmsvc *) sockaddr; 192 if (addr->sas_family != AF_ATMSVC) { 193 error = -EAFNOSUPPORT; 194 goto out; 195 } 196 if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) { 197 error = -EBADFD; 198 goto out; 199 } 200 if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS || 201 vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) { 202 error = -EINVAL; 203 goto out; 204 } 205 if (!vcc->qos.txtp.traffic_class && 206 !vcc->qos.rxtp.traffic_class) { 207 error = -EINVAL; 208 goto out; 209 } 210 vcc->remote = *addr; 211 set_bit(ATM_VF_WAITING, &vcc->flags); 212 sigd_enq(vcc, as_connect, NULL, NULL, &vcc->remote); 213 if (flags & O_NONBLOCK) { 214 sock->state = SS_CONNECTING; 215 error = -EINPROGRESS; 216 goto out; 217 } 218 error = 0; 219 prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 220 while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { 221 schedule(); 222 if (!signal_pending(current)) { 223 prepare_to_wait(sk_sleep(sk), &wait, 224 TASK_INTERRUPTIBLE); 225 continue; 226 } 227 pr_debug("*ABORT*\n"); 228 /* 229 * This is tricky: 230 * Kernel ---close--> Demon 231 * Kernel <--close--- Demon 232 * or 233 * Kernel ---close--> Demon 234 * Kernel <--error--- Demon 235 * or 236 * Kernel ---close--> Demon 237 * Kernel <--okay---- Demon 238 * Kernel <--close--- Demon 239 */ 240 sigd_enq(vcc, as_close, NULL, NULL, NULL); 241 while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) { 242 prepare_to_wait(sk_sleep(sk), &wait, 243 TASK_INTERRUPTIBLE); 244 schedule(); 245 } 246 if (!sk->sk_err) 247 while (!test_bit(ATM_VF_RELEASED, &vcc->flags) && 248 sigd) { 249 prepare_to_wait(sk_sleep(sk), &wait, 250 TASK_INTERRUPTIBLE); 251 schedule(); 252 } 253 clear_bit(ATM_VF_REGIS, &vcc->flags); 254 clear_bit(ATM_VF_RELEASED, &vcc->flags); 255 clear_bit(ATM_VF_CLOSE, &vcc->flags); 256 /* we're gone now but may connect later */ 257 error = -EINTR; 258 break; 259 } 260 finish_wait(sk_sleep(sk), &wait); 261 if (error) 262 goto out; 263 if (!sigd) { 264 error = -EUNATCH; 265 goto out; 266 } 267 if (sk->sk_err) { 268 error = -sk->sk_err; 269 goto out; 270 } 271 } 272 273 vcc->qos.txtp.max_pcr = SELECT_TOP_PCR(vcc->qos.txtp); 274 vcc->qos.txtp.pcr = 0; 275 vcc->qos.txtp.min_pcr = 0; 276 277 error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci); 278 if (!error) 279 sock->state = SS_CONNECTED; 280 else 281 (void)svc_disconnect(vcc); 282 out: 283 release_sock(sk); 284 return error; 285 } 286 287 static int svc_listen(struct socket *sock, int backlog) 288 { 289 DEFINE_WAIT(wait); 290 struct sock *sk = sock->sk; 291 struct atm_vcc *vcc = ATM_SD(sock); 292 int error; 293 294 pr_debug("%p\n", vcc); 295 lock_sock(sk); 296 /* let server handle listen on unbound sockets */ 297 if (test_bit(ATM_VF_SESSION, &vcc->flags)) { 298 error = -EINVAL; 299 goto out; 300 } 301 if (test_bit(ATM_VF_LISTEN, &vcc->flags)) { 302 error = -EADDRINUSE; 303 goto out; 304 } 305 set_bit(ATM_VF_WAITING, &vcc->flags); 306 sigd_enq(vcc, as_listen, NULL, NULL, &vcc->local); 307 for (;;) { 308 prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); 309 if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd) 310 break; 311 schedule(); 312 } 313 finish_wait(sk_sleep(sk), &wait); 314 if (!sigd) { 315 error = -EUNATCH; 316 goto out; 317 } 318 set_bit(ATM_VF_LISTEN, &vcc->flags); 319 vcc_insert_socket(sk); 320 sk->sk_max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT; 321 error = -sk->sk_err; 322 out: 323 release_sock(sk); 324 return error; 325 } 326 327 static int svc_accept(struct socket *sock, struct socket *newsock, 328 struct proto_accept_arg *arg) 329 { 330 struct sock *sk = sock->sk; 331 struct sk_buff *skb; 332 struct atmsvc_msg *msg; 333 struct atm_vcc *old_vcc = ATM_SD(sock); 334 struct atm_vcc *new_vcc; 335 int error; 336 337 lock_sock(sk); 338 339 error = svc_create(sock_net(sk), newsock, 0, arg->kern); 340 if (error) 341 goto out; 342 343 new_vcc = ATM_SD(newsock); 344 345 pr_debug("%p -> %p\n", old_vcc, new_vcc); 346 while (1) { 347 DEFINE_WAIT(wait); 348 349 prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 350 while (!(skb = skb_dequeue(&sk->sk_receive_queue)) && 351 sigd) { 352 if (test_bit(ATM_VF_RELEASED, &old_vcc->flags)) 353 break; 354 if (test_bit(ATM_VF_CLOSE, &old_vcc->flags)) { 355 error = -sk->sk_err; 356 break; 357 } 358 if (arg->flags & O_NONBLOCK) { 359 error = -EAGAIN; 360 break; 361 } 362 release_sock(sk); 363 schedule(); 364 lock_sock(sk); 365 if (signal_pending(current)) { 366 error = -ERESTARTSYS; 367 break; 368 } 369 prepare_to_wait(sk_sleep(sk), &wait, 370 TASK_INTERRUPTIBLE); 371 } 372 finish_wait(sk_sleep(sk), &wait); 373 if (error) 374 goto out; 375 if (!skb) { 376 error = -EUNATCH; 377 goto out; 378 } 379 msg = (struct atmsvc_msg *)skb->data; 380 new_vcc->qos = msg->qos; 381 set_bit(ATM_VF_HASQOS, &new_vcc->flags); 382 new_vcc->remote = msg->svc; 383 new_vcc->local = msg->local; 384 new_vcc->sap = msg->sap; 385 error = vcc_connect(newsock, msg->pvc.sap_addr.itf, 386 msg->pvc.sap_addr.vpi, 387 msg->pvc.sap_addr.vci); 388 dev_kfree_skb(skb); 389 sk_acceptq_removed(sk); 390 if (error) { 391 sigd_enq2(NULL, as_reject, old_vcc, NULL, NULL, 392 &old_vcc->qos, error); 393 error = error == -EAGAIN ? -EBUSY : error; 394 goto out; 395 } 396 /* wait should be short, so we ignore the non-blocking flag */ 397 set_bit(ATM_VF_WAITING, &new_vcc->flags); 398 sigd_enq(new_vcc, as_accept, old_vcc, NULL, NULL); 399 for (;;) { 400 prepare_to_wait(sk_sleep(sk_atm(new_vcc)), &wait, 401 TASK_UNINTERRUPTIBLE); 402 if (!test_bit(ATM_VF_WAITING, &new_vcc->flags) || !sigd) 403 break; 404 release_sock(sk); 405 schedule(); 406 lock_sock(sk); 407 } 408 finish_wait(sk_sleep(sk_atm(new_vcc)), &wait); 409 if (!sigd) { 410 error = -EUNATCH; 411 goto out; 412 } 413 if (!sk_atm(new_vcc)->sk_err) 414 break; 415 if (sk_atm(new_vcc)->sk_err != ERESTARTSYS) { 416 error = -sk_atm(new_vcc)->sk_err; 417 goto out; 418 } 419 } 420 newsock->state = SS_CONNECTED; 421 out: 422 release_sock(sk); 423 return error; 424 } 425 426 static int svc_getname(struct socket *sock, struct sockaddr *sockaddr, 427 int peer) 428 { 429 struct sockaddr_atmsvc *addr; 430 431 addr = (struct sockaddr_atmsvc *) sockaddr; 432 memcpy(addr, peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local, 433 sizeof(struct sockaddr_atmsvc)); 434 return sizeof(struct sockaddr_atmsvc); 435 } 436 437 int svc_change_qos(struct atm_vcc *vcc, struct atm_qos *qos) 438 { 439 struct sock *sk = sk_atm(vcc); 440 DEFINE_WAIT(wait); 441 442 set_bit(ATM_VF_WAITING, &vcc->flags); 443 sigd_enq2(vcc, as_modify, NULL, NULL, &vcc->local, qos, 0); 444 for (;;) { 445 prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE); 446 if (!test_bit(ATM_VF_WAITING, &vcc->flags) || 447 test_bit(ATM_VF_RELEASED, &vcc->flags) || !sigd) { 448 break; 449 } 450 schedule(); 451 } 452 finish_wait(sk_sleep(sk), &wait); 453 if (!sigd) 454 return -EUNATCH; 455 return -sk->sk_err; 456 } 457 458 static int svc_setsockopt(struct socket *sock, int level, int optname, 459 sockptr_t optval, unsigned int optlen) 460 { 461 struct sock *sk = sock->sk; 462 struct atm_vcc *vcc = ATM_SD(sock); 463 int value, error = 0; 464 465 lock_sock(sk); 466 switch (optname) { 467 case SO_ATMSAP: 468 if (level != SOL_ATM || optlen != sizeof(struct atm_sap)) { 469 error = -EINVAL; 470 goto out; 471 } 472 if (copy_from_sockptr(&vcc->sap, optval, optlen)) { 473 error = -EFAULT; 474 goto out; 475 } 476 set_bit(ATM_VF_HASSAP, &vcc->flags); 477 break; 478 case SO_MULTIPOINT: 479 if (level != SOL_ATM || optlen != sizeof(int)) { 480 error = -EINVAL; 481 goto out; 482 } 483 if (copy_from_sockptr(&value, optval, sizeof(int))) { 484 error = -EFAULT; 485 goto out; 486 } 487 if (value == 1) 488 set_bit(ATM_VF_SESSION, &vcc->flags); 489 else if (value == 0) 490 clear_bit(ATM_VF_SESSION, &vcc->flags); 491 else 492 error = -EINVAL; 493 break; 494 default: 495 error = vcc_setsockopt(sock, level, optname, optval, optlen); 496 } 497 498 out: 499 release_sock(sk); 500 return error; 501 } 502 503 static int svc_getsockopt(struct socket *sock, int level, int optname, 504 char __user *optval, int __user *optlen) 505 { 506 struct sock *sk = sock->sk; 507 int error = 0, len; 508 509 lock_sock(sk); 510 if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP) { 511 error = vcc_getsockopt(sock, level, optname, optval, optlen); 512 goto out; 513 } 514 if (get_user(len, optlen)) { 515 error = -EFAULT; 516 goto out; 517 } 518 if (len != sizeof(struct atm_sap)) { 519 error = -EINVAL; 520 goto out; 521 } 522 if (copy_to_user(optval, &ATM_SD(sock)->sap, sizeof(struct atm_sap))) { 523 error = -EFAULT; 524 goto out; 525 } 526 out: 527 release_sock(sk); 528 return error; 529 } 530 531 static int svc_addparty(struct socket *sock, struct sockaddr *sockaddr, 532 int sockaddr_len, int flags) 533 { 534 DEFINE_WAIT(wait); 535 struct sock *sk = sock->sk; 536 struct atm_vcc *vcc = ATM_SD(sock); 537 int error; 538 539 lock_sock(sk); 540 set_bit(ATM_VF_WAITING, &vcc->flags); 541 sigd_enq(vcc, as_addparty, NULL, NULL, 542 (struct sockaddr_atmsvc *) sockaddr); 543 if (flags & O_NONBLOCK) { 544 error = -EINPROGRESS; 545 goto out; 546 } 547 pr_debug("added wait queue\n"); 548 for (;;) { 549 prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 550 if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd) 551 break; 552 schedule(); 553 } 554 finish_wait(sk_sleep(sk), &wait); 555 error = -xchg(&sk->sk_err_soft, 0); 556 out: 557 release_sock(sk); 558 return error; 559 } 560 561 static int svc_dropparty(struct socket *sock, int ep_ref) 562 { 563 DEFINE_WAIT(wait); 564 struct sock *sk = sock->sk; 565 struct atm_vcc *vcc = ATM_SD(sock); 566 int error; 567 568 lock_sock(sk); 569 set_bit(ATM_VF_WAITING, &vcc->flags); 570 sigd_enq2(vcc, as_dropparty, NULL, NULL, NULL, NULL, ep_ref); 571 for (;;) { 572 prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); 573 if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd) 574 break; 575 schedule(); 576 } 577 finish_wait(sk_sleep(sk), &wait); 578 if (!sigd) { 579 error = -EUNATCH; 580 goto out; 581 } 582 error = -xchg(&sk->sk_err_soft, 0); 583 out: 584 release_sock(sk); 585 return error; 586 } 587 588 static int svc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) 589 { 590 int error, ep_ref; 591 struct sockaddr_atmsvc sa; 592 struct atm_vcc *vcc = ATM_SD(sock); 593 594 switch (cmd) { 595 case ATM_ADDPARTY: 596 if (!test_bit(ATM_VF_SESSION, &vcc->flags)) 597 return -EINVAL; 598 if (copy_from_user(&sa, (void __user *) arg, sizeof(sa))) 599 return -EFAULT; 600 error = svc_addparty(sock, (struct sockaddr *)&sa, sizeof(sa), 601 0); 602 break; 603 case ATM_DROPPARTY: 604 if (!test_bit(ATM_VF_SESSION, &vcc->flags)) 605 return -EINVAL; 606 if (copy_from_user(&ep_ref, (void __user *) arg, sizeof(int))) 607 return -EFAULT; 608 error = svc_dropparty(sock, ep_ref); 609 break; 610 default: 611 error = vcc_ioctl(sock, cmd, arg); 612 } 613 614 return error; 615 } 616 617 #ifdef CONFIG_COMPAT 618 static int svc_compat_ioctl(struct socket *sock, unsigned int cmd, 619 unsigned long arg) 620 { 621 /* The definition of ATM_ADDPARTY uses the size of struct atm_iobuf. 622 But actually it takes a struct sockaddr_atmsvc, which doesn't need 623 compat handling. So all we have to do is fix up cmd... */ 624 if (cmd == COMPAT_ATM_ADDPARTY) 625 cmd = ATM_ADDPARTY; 626 627 if (cmd == ATM_ADDPARTY || cmd == ATM_DROPPARTY) 628 return svc_ioctl(sock, cmd, arg); 629 else 630 return vcc_compat_ioctl(sock, cmd, arg); 631 } 632 #endif /* CONFIG_COMPAT */ 633 634 static const struct proto_ops svc_proto_ops = { 635 .family = PF_ATMSVC, 636 .owner = THIS_MODULE, 637 638 .release = svc_release, 639 .bind = svc_bind, 640 .connect = svc_connect, 641 .socketpair = sock_no_socketpair, 642 .accept = svc_accept, 643 .getname = svc_getname, 644 .poll = vcc_poll, 645 .ioctl = svc_ioctl, 646 #ifdef CONFIG_COMPAT 647 .compat_ioctl = svc_compat_ioctl, 648 #endif 649 .gettstamp = sock_gettstamp, 650 .listen = svc_listen, 651 .shutdown = svc_shutdown, 652 .setsockopt = svc_setsockopt, 653 .getsockopt = svc_getsockopt, 654 .sendmsg = vcc_sendmsg, 655 .recvmsg = vcc_recvmsg, 656 .mmap = sock_no_mmap, 657 }; 658 659 660 static int svc_create(struct net *net, struct socket *sock, int protocol, 661 int kern) 662 { 663 int error; 664 665 if (!net_eq(net, &init_net)) 666 return -EAFNOSUPPORT; 667 668 sock->ops = &svc_proto_ops; 669 error = vcc_create(net, sock, protocol, AF_ATMSVC, kern); 670 if (error) 671 return error; 672 ATM_SD(sock)->local.sas_family = AF_ATMSVC; 673 ATM_SD(sock)->remote.sas_family = AF_ATMSVC; 674 return 0; 675 } 676 677 static const struct net_proto_family svc_family_ops = { 678 .family = PF_ATMSVC, 679 .create = svc_create, 680 .owner = THIS_MODULE, 681 }; 682 683 684 /* 685 * Initialize the ATM SVC protocol family 686 */ 687 688 int __init atmsvc_init(void) 689 { 690 return sock_register(&svc_family_ops); 691 } 692 693 void atmsvc_exit(void) 694 { 695 sock_unregister(PF_ATMSVC); 696 } 697
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.