1 /* $NetBSD: can.c,v 1.6 2018/11/15 10:23:56 maxv Exp $ */ 2 3 /*- 4 * Copyright (c) 2003, 2017 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Robert Swindells and Manuel Bouyer 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: can.c,v 1.6 2018/11/15 10:23:56 maxv Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/mbuf.h> 38 #include <sys/ioctl.h> 39 #include <sys/domain.h> 40 #include <sys/protosw.h> 41 #include <sys/errno.h> 42 #include <sys/socket.h> 43 #include <sys/socketvar.h> 44 #include <sys/proc.h> 45 #include <sys/kauth.h> 46 47 #include <net/if.h> 48 #include <net/if_types.h> 49 #include <net/netisr.h> 50 #include <net/route.h> 51 #include <net/bpf.h> 52 53 #include <netcan/can.h> 54 #include <netcan/can_pcb.h> 55 #include <netcan/can_var.h> 56 57 struct canpcb canpcb; 58 #if 0 59 struct canpcb canrawpcb; 60 #endif 61 62 struct canpcbtable cbtable; 63 64 struct ifqueue canintrq; 65 int canqmaxlen = IFQ_MAXLEN; 66 67 int can_copy_output = 0; 68 int can_output_cnt = 0; 69 struct mbuf *can_lastout; 70 71 int can_sendspace = 4096; /* really max datagram size */ 72 int can_recvspace = 40 * (1024 + sizeof(struct sockaddr_can)); 73 /* 40 1K datagrams */ 74 #ifndef CANHASHSIZE 75 #define CANHASHSIZE 128 76 #endif 77 int canhashsize = CANHASHSIZE; 78 79 static int can_output(struct mbuf *, struct canpcb *); 80 81 static int can_control(struct socket *, u_long, void *, struct ifnet *); 82 83 void 84 can_init(void) 85 { 86 canintrq.ifq_maxlen = canqmaxlen; 87 IFQ_LOCK_INIT(&canintrq); 88 can_pcbinit(&cbtable, canhashsize, canhashsize); 89 } 90 91 /* 92 * Generic control operations (ioctl's). 93 */ 94 static int 95 can_get_netlink(struct ifnet *ifp, struct ifdrv *ifd) 96 { 97 struct canif_softc *csc = ifp->if_softc; 98 99 if (ifp->if_dlt != DLT_CAN_SOCKETCAN || csc == NULL) 100 return EOPNOTSUPP; 101 102 switch(ifd->ifd_cmd) { 103 case CANGLINKTIMECAP: 104 if (ifd->ifd_len != sizeof(struct can_link_timecaps)) 105 return EINVAL; 106 return copyout(&csc->csc_timecaps, ifd->ifd_data, ifd->ifd_len); 107 case CANGLINKTIMINGS: 108 if (ifd->ifd_len != sizeof(struct can_link_timings)) 109 return EINVAL; 110 return copyout(&csc->csc_timings, ifd->ifd_data, ifd->ifd_len); 111 case CANGLINKMODE: 112 if (ifd->ifd_len != sizeof(uint32_t)) 113 return EINVAL; 114 return copyout(&csc->csc_linkmodes, ifd->ifd_data, ifd->ifd_len); 115 } 116 return EOPNOTSUPP; 117 } 118 119 static int 120 can_set_netlink(struct ifnet *ifp, struct ifdrv *ifd) 121 { 122 struct canif_softc *csc = ifp->if_softc; 123 uint32_t mode; 124 int error; 125 126 if (ifp->if_dlt != DLT_CAN_SOCKETCAN || csc == NULL) 127 return EOPNOTSUPP; 128 129 error = kauth_authorize_network(curlwp->l_cred, 130 KAUTH_NETWORK_INTERFACE, 131 KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, 132 (void *)SIOCSDRVSPEC, NULL); 133 if (error != 0) 134 return error; 135 136 if ((ifp->if_flags & IFF_UP) != 0) { 137 return EBUSY; 138 } 139 140 switch(ifd->ifd_cmd) { 141 case CANSLINKTIMINGS: 142 if (ifd->ifd_len != sizeof(struct can_link_timings)) 143 return EINVAL; 144 return copyin(ifd->ifd_data, &csc->csc_timings, ifd->ifd_len); 145 146 case CANSLINKMODE: 147 case CANCLINKMODE: 148 if (ifd->ifd_len != sizeof(uint32_t)) 149 return EINVAL; 150 error = copyin(ifd->ifd_data, &mode, ifd->ifd_len); 151 if (error) 152 return error; 153 if ((mode & csc->csc_timecaps.cltc_linkmode_caps) != mode) 154 return EINVAL; 155 /* XXX locking */ 156 if (ifd->ifd_cmd == CANSLINKMODE) 157 csc->csc_linkmodes |= mode; 158 else 159 csc->csc_linkmodes &= ~mode; 160 return 0; 161 } 162 return EOPNOTSUPP; 163 } 164 165 /* ARGSUSED */ 166 static int 167 can_control(struct socket *so, u_long cmd, void *data, struct ifnet *ifp) 168 { 169 #if 0 170 struct can_ifreq *cfr = (struct can_ifreq *)data; 171 int error = 0; 172 #endif 173 if (ifp == NULL) 174 return (EOPNOTSUPP); 175 176 switch (cmd) { 177 case SIOCGDRVSPEC: 178 return can_get_netlink(ifp, (struct ifdrv *) data); 179 case SIOCSDRVSPEC: 180 return can_set_netlink(ifp, (struct ifdrv *) data); 181 default: 182 if (ifp->if_ioctl == 0) 183 return (EOPNOTSUPP); 184 return ((*ifp->if_ioctl)(ifp, cmd, data)); 185 } 186 return (0); 187 } 188 189 static int 190 can_purgeif(struct socket *so, struct ifnet *ifp) 191 { 192 return 0; 193 } 194 195 void 196 can_ifattach(struct ifnet *ifp) 197 { 198 if_attach(ifp); 199 ifp->if_mtu = sizeof(struct can_frame); 200 ifp->if_type = IFT_OTHER; 201 ifp->if_hdrlen = 0; 202 ifp->if_addrlen = 0; 203 ifp->if_dlt = DLT_CAN_SOCKETCAN; 204 ifp->if_output = NULL; /* unused */ 205 IFQ_SET_READY(&ifp->if_snd); 206 if_alloc_sadl(ifp); 207 bpf_attach(ifp, DLT_CAN_SOCKETCAN, 0); 208 } 209 210 void 211 can_ifdetach(struct ifnet *ifp) 212 { 213 bpf_detach(ifp); 214 if_detach(ifp); 215 } 216 217 void 218 can_ifinit_timings(struct canif_softc *csc) 219 { 220 /* uninitialized parameters is all-one */ 221 memset(&csc->csc_timings, 0xff, sizeof(struct can_link_timings)); 222 } 223 224 static int 225 can_output(struct mbuf *m, struct canpcb *canp) 226 { 227 struct ifnet *ifp; 228 struct m_tag *sotag; 229 struct canif_softc *csc; 230 231 if (canp == NULL) { 232 printf("can_output: no pcb\n"); 233 return EINVAL; 234 } 235 ifp = canp->canp_ifp; 236 if (ifp == 0) { 237 return EDESTADDRREQ; 238 } 239 csc = ifp->if_softc; 240 if (csc && (csc->csc_linkmodes & CAN_LINKMODE_LISTENONLY)) { 241 return ENETUNREACH; 242 } 243 244 sotag = m_tag_get(PACKET_TAG_SO, sizeof(struct socket *), PR_NOWAIT); 245 if (sotag == NULL) { 246 ifp->if_oerrors++; 247 return ENOMEM; 248 } 249 mutex_enter(&canp->canp_mtx); 250 canp_ref(canp); 251 mutex_exit(&canp->canp_mtx); 252 *(struct canpcb **)(sotag + 1) = canp; 253 m_tag_prepend(m, sotag); 254 255 if (m->m_len <= ifp->if_mtu) { 256 can_output_cnt++; 257 return ifq_enqueue(ifp, m); 258 } else 259 return EMSGSIZE; 260 } 261 262 /* 263 * cleanup mbuf tag, keeping the PACKET_TAG_SO tag 264 */ 265 void 266 can_mbuf_tag_clean(struct mbuf *m) 267 { 268 struct m_tag *sotag; 269 270 sotag = m_tag_find(m, PACKET_TAG_SO); 271 if (sotag) 272 m_tag_unlink(m, sotag); 273 274 m_tag_delete_chain(m); 275 if (sotag) 276 m_tag_prepend(m, sotag); 277 } 278 279 /* 280 * Process a received CAN frame 281 * the packet is in the mbuf chain m with 282 * the CAN header. 283 */ 284 void 285 can_input(struct ifnet *ifp, struct mbuf *m) 286 { 287 struct ifqueue *inq; 288 289 if ((ifp->if_flags & IFF_UP) == 0) { 290 m_freem(m); 291 return; 292 } 293 294 inq = &canintrq; 295 296 IFQ_LOCK(inq); 297 if (IF_QFULL(inq)) { 298 IF_DROP(inq); 299 IFQ_UNLOCK(inq); 300 m_freem(m); 301 } else { 302 IF_ENQUEUE(inq, m); 303 IFQ_UNLOCK(inq); 304 ifp->if_ipackets++; 305 ifp->if_ibytes += m->m_pkthdr.len; 306 schednetisr(NETISR_CAN); 307 } 308 } 309 310 void 311 canintr(void) 312 { 313 int rcv_ifindex; 314 struct mbuf *m; 315 316 struct sockaddr_can from; 317 struct canpcb *canp; 318 struct m_tag *sotag; 319 struct canpcb *sender_canp; 320 321 mutex_enter(softnet_lock); 322 for (;;) { 323 IFQ_LOCK(&canintrq); 324 IF_DEQUEUE(&canintrq, m); 325 IFQ_UNLOCK(&canintrq); 326 327 if (m == NULL) /* no more queued packets */ 328 break; 329 330 #if 0 331 m_claim(m, &can_rx_mowner); 332 #endif 333 sotag = m_tag_find(m, PACKET_TAG_SO); 334 if (sotag) { 335 sender_canp = *(struct canpcb **)(sotag + 1); 336 m_tag_delete(m, sotag); 337 KASSERT(sender_canp != NULL); 338 /* if the sender doesn't want loopback, don't do it */ 339 if ((sender_canp->canp_flags & CANP_NO_LOOPBACK) != 0) { 340 m_freem(m); 341 canp_unref(sender_canp); 342 continue; 343 } 344 } else { 345 sender_canp = NULL; 346 } 347 memset(&from, 0, sizeof(struct sockaddr_can)); 348 rcv_ifindex = m->m_pkthdr.rcvif_index; 349 from.can_ifindex = rcv_ifindex; 350 from.can_len = sizeof(struct sockaddr_can); 351 from.can_family = AF_CAN; 352 353 TAILQ_FOREACH(canp, &cbtable.canpt_queue, canp_queue) { 354 struct mbuf *mc; 355 356 mutex_enter(&canp->canp_mtx); 357 /* skip if we're detached */ 358 if (canp->canp_state == CANP_DETACHED) { 359 mutex_exit(&canp->canp_mtx); 360 continue; 361 } 362 363 /* don't loop back to sockets on other interfaces */ 364 if (canp->canp_ifp != NULL && 365 canp->canp_ifp->if_index != rcv_ifindex) { 366 mutex_exit(&canp->canp_mtx); 367 continue; 368 } 369 /* don't loop back to myself if I don't want it */ 370 if (canp == sender_canp && 371 (canp->canp_flags & CANP_RECEIVE_OWN) == 0) { 372 mutex_exit(&canp->canp_mtx); 373 continue; 374 } 375 376 /* skip if the accept filter doen't match this pkt */ 377 if (!can_pcbfilter(canp, m)) { 378 mutex_exit(&canp->canp_mtx); 379 continue; 380 } 381 382 if (TAILQ_NEXT(canp, canp_queue) != NULL) { 383 /* 384 * we can't be sure we won't need 385 * the original mbuf later so copy 386 */ 387 mc = m_copypacket(m, M_NOWAIT); 388 if (mc == NULL) { 389 /* deliver this mbuf and abort */ 390 mc = m; 391 m = NULL; 392 } 393 } else { 394 mc = m; 395 m = NULL; 396 } 397 if (sbappendaddr(&canp->canp_socket->so_rcv, 398 (struct sockaddr *) &from, mc, 399 (struct mbuf *) 0) == 0) { 400 soroverflow(canp->canp_socket); 401 m_freem(mc); 402 } else 403 sorwakeup(canp->canp_socket); 404 mutex_exit(&canp->canp_mtx); 405 if (m == NULL) 406 break; 407 } 408 if (sender_canp) { 409 canp_unref(sender_canp); 410 } 411 /* If it didn't go anywhere just delete it */ 412 if (m) { 413 m_freem(m); 414 } 415 } 416 mutex_exit(softnet_lock); 417 } 418 419 void 420 can_bpf_mtap(struct ifnet *ifp, struct mbuf *m, bool do_softint) 421 { 422 /* bpf wants the CAN id in network byte order */ 423 struct can_frame *cf; 424 canid_t oid; 425 426 cf = mtod(m, struct can_frame *); 427 oid = cf->can_id; 428 cf->can_id = htonl(oid); 429 /* Assume the direction is input when do_softint is set. */ 430 if (do_softint) 431 bpf_mtap_softint(ifp, m); 432 else 433 bpf_mtap(ifp, m, BPF_D_OUT); 434 cf->can_id = oid; 435 } 436 437 static int 438 can_attach(struct socket *so, int proto) 439 { 440 int error; 441 442 KASSERT(sotocanpcb(so) == NULL); 443 444 /* Assign the lock (must happen even if we will error out). */ 445 sosetlock(so); 446 447 #ifdef MBUFTRACE 448 so->so_mowner = &can_mowner; 449 so->so_rcv.sb_mowner = &can_rx_mowner; 450 so->so_snd.sb_mowner = &can_tx_mowner; 451 #endif 452 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 453 error = soreserve(so, can_sendspace, can_recvspace); 454 if (error) { 455 return error; 456 } 457 } 458 459 error = can_pcballoc(so, &cbtable); 460 if (error) { 461 return error; 462 } 463 KASSERT(solocked(so)); 464 465 return error; 466 } 467 468 static void 469 can_detach(struct socket *so) 470 { 471 struct canpcb *canp; 472 473 KASSERT(solocked(so)); 474 canp = sotocanpcb(so); 475 can_pcbdetach(canp); 476 } 477 478 static int 479 can_accept(struct socket *so, struct sockaddr *nam) 480 { 481 KASSERT(solocked(so)); 482 483 panic("can_accept"); 484 485 return EOPNOTSUPP; 486 } 487 488 static int 489 can_bind(struct socket *so, struct sockaddr *nam, struct lwp *l) 490 { 491 struct canpcb *canp = sotocanpcb(so); 492 struct sockaddr_can *scan = (struct sockaddr_can *)nam; 493 494 KASSERT(solocked(so)); 495 KASSERT(nam != NULL); 496 497 return can_pcbbind(canp, scan, l); 498 } 499 500 static int 501 can_listen(struct socket *so, struct lwp *l) 502 { 503 KASSERT(solocked(so)); 504 505 return EOPNOTSUPP; 506 } 507 508 static int 509 can_connect(struct socket *so, struct sockaddr *nam, struct lwp *l) 510 { 511 struct canpcb *canp = sotocanpcb(so); 512 int error = 0; 513 514 KASSERT(solocked(so)); 515 KASSERT(canp != NULL); 516 KASSERT(nam != NULL); 517 518 error = can_pcbconnect(canp, (struct sockaddr_can *)nam); 519 if (! error) 520 soisconnected(so); 521 return error; 522 } 523 524 static int 525 can_connect2(struct socket *so, struct socket *so2) 526 { 527 KASSERT(solocked(so)); 528 529 return EOPNOTSUPP; 530 } 531 532 static int 533 can_disconnect(struct socket *so) 534 { 535 struct canpcb *canp = sotocanpcb(so); 536 537 KASSERT(solocked(so)); 538 KASSERT(canp != NULL); 539 540 /*soisdisconnected(so);*/ 541 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 542 can_pcbdisconnect(canp); 543 return 0; 544 } 545 546 static int 547 can_shutdown(struct socket *so) 548 { 549 KASSERT(solocked(so)); 550 551 socantsendmore(so); 552 return 0; 553 } 554 555 static int 556 can_abort(struct socket *so) 557 { 558 KASSERT(solocked(so)); 559 560 panic("can_abort"); 561 562 return EOPNOTSUPP; 563 } 564 565 static int 566 can_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp) 567 { 568 return can_control(so, cmd, nam, ifp); 569 } 570 571 static int 572 can_stat(struct socket *so, struct stat *ub) 573 { 574 KASSERT(solocked(so)); 575 576 /* stat: don't bother with a blocksize. */ 577 return 0; 578 } 579 580 static int 581 can_peeraddr(struct socket *so, struct sockaddr *nam) 582 { 583 KASSERT(solocked(so)); 584 KASSERT(sotocanpcb(so) != NULL); 585 KASSERT(nam != NULL); 586 587 return EOPNOTSUPP; 588 } 589 590 static int 591 can_sockaddr(struct socket *so, struct sockaddr *nam) 592 { 593 KASSERT(solocked(so)); 594 KASSERT(sotocanpcb(so) != NULL); 595 KASSERT(nam != NULL); 596 597 can_setsockaddr(sotocanpcb(so), (struct sockaddr_can *)nam); 598 599 return 0; 600 } 601 602 static int 603 can_rcvd(struct socket *so, int flags, struct lwp *l) 604 { 605 KASSERT(solocked(so)); 606 607 return EOPNOTSUPP; 608 } 609 610 static int 611 can_recvoob(struct socket *so, struct mbuf *m, int flags) 612 { 613 KASSERT(solocked(so)); 614 615 return EOPNOTSUPP; 616 } 617 618 static int 619 can_send(struct socket *so, struct mbuf *m, struct sockaddr *nam, 620 struct mbuf *control, struct lwp *l) 621 { 622 struct canpcb *canp = sotocanpcb(so); 623 int error = 0; 624 int s; 625 626 if (control && control->m_len) { 627 m_freem(control); 628 error = EINVAL; 629 goto err; 630 } 631 if (m->m_len > sizeof(struct can_frame) || 632 m->m_len < offsetof(struct can_frame, can_dlc)) { 633 error = EINVAL; 634 goto err; 635 } 636 637 /* we expect all data in the first mbuf */ 638 KASSERT((m->m_flags & M_PKTHDR) != 0); 639 KASSERT(m->m_len == m->m_pkthdr.len); 640 641 if (nam) { 642 if ((so->so_state & SS_ISCONNECTED) != 0) { 643 error = EISCONN; 644 goto err; 645 } 646 s = splnet(); 647 error = can_pcbbind(canp, (struct sockaddr_can *)nam, l); 648 if (error) { 649 splx(s); 650 goto err; 651 } 652 } else { 653 if ((so->so_state & SS_ISCONNECTED) == 0) { 654 error = EDESTADDRREQ; 655 goto err; 656 } 657 } 658 error = can_output(m, canp); 659 if (nam) { 660 struct sockaddr_can lscan; 661 memset(&lscan, 0, sizeof(lscan)); 662 lscan.can_family = AF_CAN; 663 lscan.can_len = sizeof(lscan); 664 can_pcbbind(canp, &lscan, l); 665 } 666 if (error) 667 goto err; 668 return 0; 669 670 err: 671 m_freem(m); 672 return error; 673 } 674 675 static int 676 can_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control) 677 { 678 KASSERT(solocked(so)); 679 680 m_freem(m); 681 m_freem(control); 682 683 return EOPNOTSUPP; 684 } 685 686 #if 0 687 int 688 can_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, 689 struct mbuf *control, struct lwp *l) 690 { 691 struct canpcb *canp; 692 int s; 693 int error = 0; 694 695 if (req == PRU_CONTROL) 696 return (can_control(so, (long)m, nam, 697 (struct ifnet *)control)); 698 699 if (req == PRU_PURGEIF) { 700 #if 0 701 can_pcbpurgeif0(&udbtable, (struct ifnet *)control); 702 can_purgeif((struct ifnet *)control); 703 can_pcbpurgeif(&udbtable, (struct ifnet *)control); 704 #endif 705 return (0); 706 } 707 708 s = splsoftnet(); 709 canp = sotocanpcb(so); 710 #ifdef DIAGNOSTIC 711 if (req != PRU_SEND && req != PRU_SENDOOB && control) 712 panic("can_usrreq: unexpected control mbuf"); 713 #endif 714 if (canp == 0 && req != PRU_ATTACH) { 715 printf("can_usrreq: no pcb %p %d\n", canp, req); 716 error = EINVAL; 717 goto release; 718 } 719 720 /* 721 * Note: need to block can_input while changing 722 * the can pcb queue and/or pcb addresses. 723 */ 724 switch (req) { 725 726 case PRU_ATTACH: 727 if (canp != 0) { 728 error = EISCONN; 729 break; 730 } 731 #ifdef MBUFTRACE 732 so->so_mowner = &can_mowner; 733 so->so_rcv.sb_mowner = &can_rx_mowner; 734 so->so_snd.sb_mowner = &can_tx_mowner; 735 #endif 736 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 737 error = soreserve(so, can_sendspace, can_recvspace); 738 if (error) 739 break; 740 } 741 error = can_pcballoc(so, &cbtable); 742 if (error) 743 break; 744 canp = sotocanpcb(so); 745 #if 0 746 inp->inp_ip.ip_ttl = ip_defttl; 747 #endif 748 break; 749 750 case PRU_DETACH: 751 can_pcbdetach(canp); 752 break; 753 754 case PRU_BIND: 755 error = can_pcbbind(canp, nam, l); 756 break; 757 758 case PRU_LISTEN: 759 error = EOPNOTSUPP; 760 break; 761 762 case PRU_CONNECT: 763 error = can_pcbconnect(canp, nam); 764 if (error) 765 break; 766 soisconnected(so); 767 break; 768 769 case PRU_CONNECT2: 770 error = EOPNOTSUPP; 771 break; 772 773 case PRU_DISCONNECT: 774 /*soisdisconnected(so);*/ 775 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 776 can_pcbdisconnect(canp); 777 can_pcbstate(canp, CANP_BOUND); /* XXX */ 778 break; 779 780 case PRU_SHUTDOWN: 781 socantsendmore(so); 782 break; 783 784 case PRU_RCVD: 785 error = EOPNOTSUPP; 786 break; 787 788 case PRU_SEND: 789 break; 790 791 case PRU_SENSE: 792 /* 793 * stat: don't bother with a blocksize. 794 */ 795 splx(s); 796 return (0); 797 798 case PRU_RCVOOB: 799 error = EOPNOTSUPP; 800 break; 801 802 case PRU_SENDOOB: 803 m_freem(control); 804 m_freem(m); 805 error = EOPNOTSUPP; 806 break; 807 808 case PRU_SOCKADDR: 809 810 break; 811 812 case PRU_PEERADDR: 813 error = EOPNOTSUPP; 814 break; 815 816 default: 817 panic("can_usrreq"); 818 } 819 820 release: 821 splx(s); 822 return (error); 823 } 824 #endif 825 826 #if 0 827 static void 828 can_notify(struct canpcb *canp, int errno) 829 { 830 831 canp->canp_socket->so_error = errno; 832 sorwakeup(canp->canp_socket); 833 sowwakeup(canp->canp_socket); 834 } 835 836 void * 837 can_ctlinput(int cmd, struct sockaddr *sa, void *v) 838 { 839 struct ip *ip = v; 840 struct canhdr *uh; 841 void (*notify) __P((struct inpcb *, int)) = can_notify; 842 int errno; 843 844 if (sa->sa_family != AF_CAN 845 || sa->sa_len != sizeof(struct sockaddr_can)) 846 return NULL; 847 if ((unsigned)cmd >= PRC_NCMDS) 848 return NULL; 849 errno = inetctlerrmap[cmd]; 850 if (PRC_IS_REDIRECT(cmd)) 851 notify = in_rtchange, ip = 0; 852 else if (cmd == PRC_HOSTDEAD) 853 ip = 0; 854 else if (errno == 0) 855 return NULL; 856 if (ip) { 857 uh = (struct canhdr *)((caddr_t)ip + (ip->ip_hl << 2)); 858 in_pcbnotify(&udbtable, satosin(sa)->sin_addr, uh->uh_dport, 859 ip->ip_src, uh->uh_sport, errno, notify); 860 861 /* XXX mapped address case */ 862 } else 863 can_pcbnotifyall(&cbtable, satoscan(sa)->scan_addr, errno, 864 notify); 865 return NULL; 866 } 867 #endif 868 869 static int 870 can_raw_getop(struct canpcb *canp, struct sockopt *sopt) 871 { 872 int optval = 0; 873 int error; 874 875 switch (sopt->sopt_name) { 876 case CAN_RAW_LOOPBACK: 877 optval = (canp->canp_flags & CANP_NO_LOOPBACK) ? 0 : 1; 878 error = sockopt_set(sopt, &optval, sizeof(optval)); 879 break; 880 case CAN_RAW_RECV_OWN_MSGS: 881 optval = (canp->canp_flags & CANP_RECEIVE_OWN) ? 1 : 0; 882 error = sockopt_set(sopt, &optval, sizeof(optval)); 883 break; 884 case CAN_RAW_FILTER: 885 error = sockopt_set(sopt, canp->canp_filters, 886 sizeof(struct can_filter) * canp->canp_nfilters); 887 break; 888 default: 889 error = ENOPROTOOPT; 890 break; 891 } 892 return error; 893 } 894 895 static int 896 can_raw_setop(struct canpcb *canp, struct sockopt *sopt) 897 { 898 int optval = 0; 899 int error; 900 901 switch (sopt->sopt_name) { 902 case CAN_RAW_LOOPBACK: 903 error = sockopt_getint(sopt, &optval); 904 if (error == 0) { 905 if (optval) { 906 canp->canp_flags &= ~CANP_NO_LOOPBACK; 907 } else { 908 canp->canp_flags |= CANP_NO_LOOPBACK; 909 } 910 } 911 break; 912 case CAN_RAW_RECV_OWN_MSGS: 913 error = sockopt_getint(sopt, &optval); 914 if (error == 0) { 915 if (optval) { 916 canp->canp_flags |= CANP_RECEIVE_OWN; 917 } else { 918 canp->canp_flags &= ~CANP_RECEIVE_OWN; 919 } 920 } 921 break; 922 case CAN_RAW_FILTER: 923 { 924 int nfilters = sopt->sopt_size / sizeof(struct can_filter); 925 if (sopt->sopt_size % sizeof(struct can_filter) != 0) 926 return EINVAL; 927 mutex_enter(&canp->canp_mtx); 928 error = can_pcbsetfilter(canp, sopt->sopt_data, nfilters); 929 mutex_exit(&canp->canp_mtx); 930 break; 931 } 932 default: 933 error = ENOPROTOOPT; 934 break; 935 } 936 return error; 937 } 938 939 /* 940 * Called by getsockopt and setsockopt. 941 * 942 */ 943 int 944 can_ctloutput(int op, struct socket *so, struct sockopt *sopt) 945 { 946 struct canpcb *canp; 947 int error; 948 int s; 949 950 if (so->so_proto->pr_domain->dom_family != PF_CAN) 951 return EAFNOSUPPORT; 952 953 if (sopt->sopt_level != SOL_CAN_RAW) 954 return EINVAL; 955 956 s = splsoftnet(); 957 canp = sotocanpcb(so); 958 if (canp == NULL) { 959 splx(s); 960 return ECONNRESET; 961 } 962 963 if (op == PRCO_SETOPT) { 964 error = can_raw_setop(canp, sopt); 965 } else if (op == PRCO_GETOPT) { 966 error = can_raw_getop(canp, sopt); 967 } else { 968 error = EINVAL; 969 } 970 splx(s); 971 return error; 972 } 973 974 PR_WRAP_USRREQS(can) 975 #define can_attach can_attach_wrapper 976 #define can_detach can_detach_wrapper 977 #define can_accept can_accept_wrapper 978 #define can_bind can_bind_wrapper 979 #define can_listen can_listen_wrapper 980 #define can_connect can_connect_wrapper 981 #define can_connect2 can_connect2_wrapper 982 #define can_disconnect can_disconnect_wrapper 983 #define can_shutdown can_shutdown_wrapper 984 #define can_abort can_abort_wrapper 985 #define can_ioctl can_ioctl_wrapper 986 #define can_stat can_stat_wrapper 987 #define can_peeraddr can_peeraddr_wrapper 988 #define can_sockaddr can_sockaddr_wrapper 989 #define can_rcvd can_rcvd_wrapper 990 #define can_recvoob can_recvoob_wrapper 991 #define can_send can_send_wrapper 992 #define can_sendoob can_sendoob_wrapper 993 #define can_purgeif can_purgeif_wrapper 994 995 const struct pr_usrreqs can_usrreqs = { 996 .pr_attach = can_attach, 997 .pr_detach = can_detach, 998 .pr_accept = can_accept, 999 .pr_bind = can_bind, 1000 .pr_listen = can_listen, 1001 .pr_connect = can_connect, 1002 .pr_connect2 = can_connect2, 1003 .pr_disconnect = can_disconnect, 1004 .pr_shutdown = can_shutdown, 1005 .pr_abort = can_abort, 1006 .pr_ioctl = can_ioctl, 1007 .pr_stat = can_stat, 1008 .pr_peeraddr = can_peeraddr, 1009 .pr_sockaddr = can_sockaddr, 1010 .pr_rcvd = can_rcvd, 1011 .pr_recvoob = can_recvoob, 1012 .pr_send = can_send, 1013 .pr_sendoob = can_sendoob, 1014 .pr_purgeif = can_purgeif, 1015 }; 1016