1 /* $NetBSD: can.c,v 1.2 2017/05/27 21:02:56 bouyer 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.2 2017/05/27 21:02:56 bouyer 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, NULL); 271 if (sotag) 272 m_tag_unlink(m, sotag); 273 274 m_tag_delete_nonpersistent(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, NULL); 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 m_freem(mc); 401 } else 402 sorwakeup(canp->canp_socket); 403 mutex_exit(&canp->canp_mtx); 404 if (m == NULL) 405 break; 406 } 407 if (sender_canp) { 408 canp_unref(sender_canp); 409 } 410 /* If it didn't go anywhere just delete it */ 411 if (m) { 412 m_freem(m); 413 } 414 } 415 mutex_exit(softnet_lock); 416 } 417 418 void 419 can_bpf_mtap(struct ifnet *ifp, struct mbuf *m, bool do_softint) 420 { 421 /* bpf wants the CAN id in network byte order */ 422 struct can_frame *cf; 423 canid_t oid; 424 425 cf = mtod(m, struct can_frame *); 426 oid = cf->can_id; 427 cf->can_id = htonl(oid); 428 if (do_softint) 429 bpf_mtap_softint(ifp, m); 430 else 431 bpf_mtap(ifp, m); 432 cf->can_id = oid; 433 } 434 435 static int 436 can_attach(struct socket *so, int proto) 437 { 438 int error; 439 440 KASSERT(sotocanpcb(so) == NULL); 441 442 /* Assign the lock (must happen even if we will error out). */ 443 sosetlock(so); 444 445 #ifdef MBUFTRACE 446 so->so_mowner = &can_mowner; 447 so->so_rcv.sb_mowner = &can_rx_mowner; 448 so->so_snd.sb_mowner = &can_tx_mowner; 449 #endif 450 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 451 error = soreserve(so, can_sendspace, can_recvspace); 452 if (error) { 453 return error; 454 } 455 } 456 457 error = can_pcballoc(so, &cbtable); 458 if (error) { 459 return error; 460 } 461 KASSERT(solocked(so)); 462 463 return error; 464 } 465 466 static void 467 can_detach(struct socket *so) 468 { 469 struct canpcb *canp; 470 471 KASSERT(solocked(so)); 472 canp = sotocanpcb(so); 473 can_pcbdetach(canp); 474 } 475 476 static int 477 can_accept(struct socket *so, struct sockaddr *nam) 478 { 479 KASSERT(solocked(so)); 480 481 panic("can_accept"); 482 483 return EOPNOTSUPP; 484 } 485 486 static int 487 can_bind(struct socket *so, struct sockaddr *nam, struct lwp *l) 488 { 489 struct canpcb *canp = sotocanpcb(so); 490 struct sockaddr_can *scan = (struct sockaddr_can *)nam; 491 492 KASSERT(solocked(so)); 493 KASSERT(nam != NULL); 494 495 return can_pcbbind(canp, scan, l); 496 } 497 498 static int 499 can_listen(struct socket *so, struct lwp *l) 500 { 501 KASSERT(solocked(so)); 502 503 return EOPNOTSUPP; 504 } 505 506 static int 507 can_connect(struct socket *so, struct sockaddr *nam, struct lwp *l) 508 { 509 struct canpcb *canp = sotocanpcb(so); 510 int error = 0; 511 512 KASSERT(solocked(so)); 513 KASSERT(canp != NULL); 514 KASSERT(nam != NULL); 515 516 error = can_pcbconnect(canp, (struct sockaddr_can *)nam); 517 if (! error) 518 soisconnected(so); 519 return error; 520 } 521 522 static int 523 can_connect2(struct socket *so, struct socket *so2) 524 { 525 KASSERT(solocked(so)); 526 527 return EOPNOTSUPP; 528 } 529 530 static int 531 can_disconnect(struct socket *so) 532 { 533 struct canpcb *canp = sotocanpcb(so); 534 535 KASSERT(solocked(so)); 536 KASSERT(canp != NULL); 537 538 /*soisdisconnected(so);*/ 539 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 540 can_pcbdisconnect(canp); 541 return 0; 542 } 543 544 static int 545 can_shutdown(struct socket *so) 546 { 547 KASSERT(solocked(so)); 548 549 socantsendmore(so); 550 return 0; 551 } 552 553 static int 554 can_abort(struct socket *so) 555 { 556 KASSERT(solocked(so)); 557 558 panic("can_abort"); 559 560 return EOPNOTSUPP; 561 } 562 563 static int 564 can_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp) 565 { 566 return can_control(so, cmd, nam, ifp); 567 } 568 569 static int 570 can_stat(struct socket *so, struct stat *ub) 571 { 572 KASSERT(solocked(so)); 573 574 /* stat: don't bother with a blocksize. */ 575 return 0; 576 } 577 578 static int 579 can_peeraddr(struct socket *so, struct sockaddr *nam) 580 { 581 KASSERT(solocked(so)); 582 KASSERT(sotocanpcb(so) != NULL); 583 KASSERT(nam != NULL); 584 585 return EOPNOTSUPP; 586 } 587 588 static int 589 can_sockaddr(struct socket *so, struct sockaddr *nam) 590 { 591 KASSERT(solocked(so)); 592 KASSERT(sotocanpcb(so) != NULL); 593 KASSERT(nam != NULL); 594 595 can_setsockaddr(sotocanpcb(so), (struct sockaddr_can *)nam); 596 597 return 0; 598 } 599 600 static int 601 can_rcvd(struct socket *so, int flags, struct lwp *l) 602 { 603 KASSERT(solocked(so)); 604 605 return EOPNOTSUPP; 606 } 607 608 static int 609 can_recvoob(struct socket *so, struct mbuf *m, int flags) 610 { 611 KASSERT(solocked(so)); 612 613 return EOPNOTSUPP; 614 } 615 616 static int 617 can_send(struct socket *so, struct mbuf *m, struct sockaddr *nam, 618 struct mbuf *control, struct lwp *l) 619 { 620 struct canpcb *canp = sotocanpcb(so); 621 int error = 0; 622 int s; 623 624 if (control && control->m_len) { 625 m_freem(control); 626 error = EINVAL; 627 goto err; 628 } 629 if (m->m_len > sizeof(struct can_frame) || 630 m->m_len < offsetof(struct can_frame, can_dlc)) { 631 error = EINVAL; 632 goto err; 633 } 634 635 /* we expect all data in the first mbuf */ 636 KASSERT((m->m_flags & M_PKTHDR) != 0); 637 KASSERT(m->m_len == m->m_pkthdr.len); 638 639 if (nam) { 640 if ((so->so_state & SS_ISCONNECTED) != 0) { 641 error = EISCONN; 642 goto err; 643 } 644 s = splnet(); 645 error = can_pcbbind(canp, (struct sockaddr_can *)nam, l); 646 if (error) { 647 splx(s); 648 goto err; 649 } 650 } else { 651 if ((so->so_state & SS_ISCONNECTED) == 0) { 652 error = EDESTADDRREQ; 653 goto err; 654 } 655 } 656 error = can_output(m, canp); 657 if (nam) { 658 struct sockaddr_can lscan; 659 memset(&lscan, 0, sizeof(lscan)); 660 lscan.can_family = AF_CAN; 661 lscan.can_len = sizeof(lscan); 662 can_pcbbind(canp, &lscan, l); 663 } 664 if (error) 665 goto err; 666 return 0; 667 668 err: 669 m_freem(m); 670 return error; 671 } 672 673 static int 674 can_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control) 675 { 676 KASSERT(solocked(so)); 677 678 m_freem(m); 679 m_freem(control); 680 681 return EOPNOTSUPP; 682 } 683 684 #if 0 685 int 686 can_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, 687 struct mbuf *control, struct lwp *l) 688 { 689 struct canpcb *canp; 690 int s; 691 int error = 0; 692 693 if (req == PRU_CONTROL) 694 return (can_control(so, (long)m, nam, 695 (struct ifnet *)control)); 696 697 if (req == PRU_PURGEIF) { 698 #if 0 699 can_pcbpurgeif0(&udbtable, (struct ifnet *)control); 700 can_purgeif((struct ifnet *)control); 701 can_pcbpurgeif(&udbtable, (struct ifnet *)control); 702 #endif 703 return (0); 704 } 705 706 s = splsoftnet(); 707 canp = sotocanpcb(so); 708 #ifdef DIAGNOSTIC 709 if (req != PRU_SEND && req != PRU_SENDOOB && control) 710 panic("can_usrreq: unexpected control mbuf"); 711 #endif 712 if (canp == 0 && req != PRU_ATTACH) { 713 printf("can_usrreq: no pcb %p %d\n", canp, req); 714 error = EINVAL; 715 goto release; 716 } 717 718 /* 719 * Note: need to block can_input while changing 720 * the can pcb queue and/or pcb addresses. 721 */ 722 switch (req) { 723 724 case PRU_ATTACH: 725 if (canp != 0) { 726 error = EISCONN; 727 break; 728 } 729 #ifdef MBUFTRACE 730 so->so_mowner = &can_mowner; 731 so->so_rcv.sb_mowner = &can_rx_mowner; 732 so->so_snd.sb_mowner = &can_tx_mowner; 733 #endif 734 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 735 error = soreserve(so, can_sendspace, can_recvspace); 736 if (error) 737 break; 738 } 739 error = can_pcballoc(so, &cbtable); 740 if (error) 741 break; 742 canp = sotocanpcb(so); 743 #if 0 744 inp->inp_ip.ip_ttl = ip_defttl; 745 #endif 746 break; 747 748 case PRU_DETACH: 749 can_pcbdetach(canp); 750 break; 751 752 case PRU_BIND: 753 error = can_pcbbind(canp, nam, l); 754 break; 755 756 case PRU_LISTEN: 757 error = EOPNOTSUPP; 758 break; 759 760 case PRU_CONNECT: 761 error = can_pcbconnect(canp, nam); 762 if (error) 763 break; 764 soisconnected(so); 765 break; 766 767 case PRU_CONNECT2: 768 error = EOPNOTSUPP; 769 break; 770 771 case PRU_DISCONNECT: 772 /*soisdisconnected(so);*/ 773 so->so_state &= ~SS_ISCONNECTED; /* XXX */ 774 can_pcbdisconnect(canp); 775 can_pcbstate(canp, CANP_BOUND); /* XXX */ 776 break; 777 778 case PRU_SHUTDOWN: 779 socantsendmore(so); 780 break; 781 782 case PRU_RCVD: 783 error = EOPNOTSUPP; 784 break; 785 786 case PRU_SEND: 787 break; 788 789 case PRU_SENSE: 790 /* 791 * stat: don't bother with a blocksize. 792 */ 793 splx(s); 794 return (0); 795 796 case PRU_RCVOOB: 797 error = EOPNOTSUPP; 798 break; 799 800 case PRU_SENDOOB: 801 m_freem(control); 802 m_freem(m); 803 error = EOPNOTSUPP; 804 break; 805 806 case PRU_SOCKADDR: 807 808 break; 809 810 case PRU_PEERADDR: 811 error = EOPNOTSUPP; 812 break; 813 814 default: 815 panic("can_usrreq"); 816 } 817 818 release: 819 splx(s); 820 return (error); 821 } 822 #endif 823 824 #if 0 825 static void 826 can_notify(struct canpcb *canp, int errno) 827 { 828 829 canp->canp_socket->so_error = errno; 830 sorwakeup(canp->canp_socket); 831 sowwakeup(canp->canp_socket); 832 } 833 834 void * 835 can_ctlinput(int cmd, struct sockaddr *sa, void *v) 836 { 837 struct ip *ip = v; 838 struct canhdr *uh; 839 void (*notify) __P((struct inpcb *, int)) = can_notify; 840 int errno; 841 842 if (sa->sa_family != AF_CAN 843 || sa->sa_len != sizeof(struct sockaddr_can)) 844 return NULL; 845 if ((unsigned)cmd >= PRC_NCMDS) 846 return NULL; 847 errno = inetctlerrmap[cmd]; 848 if (PRC_IS_REDIRECT(cmd)) 849 notify = in_rtchange, ip = 0; 850 else if (cmd == PRC_HOSTDEAD) 851 ip = 0; 852 else if (errno == 0) 853 return NULL; 854 if (ip) { 855 uh = (struct canhdr *)((caddr_t)ip + (ip->ip_hl << 2)); 856 in_pcbnotify(&udbtable, satosin(sa)->sin_addr, uh->uh_dport, 857 ip->ip_src, uh->uh_sport, errno, notify); 858 859 /* XXX mapped address case */ 860 } else 861 can_pcbnotifyall(&cbtable, satoscan(sa)->scan_addr, errno, 862 notify); 863 return NULL; 864 } 865 #endif 866 867 static int 868 can_raw_getop(struct canpcb *canp, struct sockopt *sopt) 869 { 870 int optval = 0; 871 int error; 872 873 switch (sopt->sopt_name) { 874 case CAN_RAW_LOOPBACK: 875 optval = (canp->canp_flags & CANP_NO_LOOPBACK) ? 0 : 1; 876 error = sockopt_set(sopt, &optval, sizeof(optval)); 877 break; 878 case CAN_RAW_RECV_OWN_MSGS: 879 optval = (canp->canp_flags & CANP_RECEIVE_OWN) ? 1 : 0; 880 error = sockopt_set(sopt, &optval, sizeof(optval)); 881 break; 882 case CAN_RAW_FILTER: 883 error = sockopt_set(sopt, canp->canp_filters, 884 sizeof(struct can_filter) * canp->canp_nfilters); 885 break; 886 default: 887 error = ENOPROTOOPT; 888 break; 889 } 890 return error; 891 } 892 893 static int 894 can_raw_setop(struct canpcb *canp, struct sockopt *sopt) 895 { 896 int optval = 0; 897 int error; 898 899 switch (sopt->sopt_name) { 900 case CAN_RAW_LOOPBACK: 901 error = sockopt_getint(sopt, &optval); 902 if (error == 0) { 903 if (optval) { 904 canp->canp_flags &= ~CANP_NO_LOOPBACK; 905 } else { 906 canp->canp_flags |= CANP_NO_LOOPBACK; 907 } 908 } 909 break; 910 case CAN_RAW_RECV_OWN_MSGS: 911 error = sockopt_getint(sopt, &optval); 912 if (error == 0) { 913 if (optval) { 914 canp->canp_flags |= CANP_RECEIVE_OWN; 915 } else { 916 canp->canp_flags &= ~CANP_RECEIVE_OWN; 917 } 918 } 919 break; 920 case CAN_RAW_FILTER: 921 { 922 int nfilters = sopt->sopt_size / sizeof(struct can_filter); 923 if (sopt->sopt_size % sizeof(struct can_filter) != 0) 924 return EINVAL; 925 mutex_enter(&canp->canp_mtx); 926 error = can_pcbsetfilter(canp, sopt->sopt_data, nfilters); 927 mutex_exit(&canp->canp_mtx); 928 break; 929 } 930 default: 931 error = ENOPROTOOPT; 932 break; 933 } 934 return error; 935 } 936 937 /* 938 * Called by getsockopt and setsockopt. 939 * 940 */ 941 int 942 can_ctloutput(int op, struct socket *so, struct sockopt *sopt) 943 { 944 struct canpcb *canp; 945 int error; 946 int s; 947 948 if (so->so_proto->pr_domain->dom_family != PF_CAN) 949 return EAFNOSUPPORT; 950 951 if (sopt->sopt_level != SOL_CAN_RAW) 952 return EINVAL; 953 954 s = splsoftnet(); 955 canp = sotocanpcb(so); 956 if (canp == NULL) { 957 splx(s); 958 return ECONNRESET; 959 } 960 961 if (op == PRCO_SETOPT) { 962 error = can_raw_setop(canp, sopt); 963 } else if (op == PRCO_GETOPT) { 964 error = can_raw_getop(canp, sopt); 965 } else { 966 error = EINVAL; 967 } 968 splx(s); 969 return error; 970 } 971 972 PR_WRAP_USRREQS(can) 973 #define can_attach can_attach_wrapper 974 #define can_detach can_detach_wrapper 975 #define can_accept can_accept_wrapper 976 #define can_bind can_bind_wrapper 977 #define can_listen can_listen_wrapper 978 #define can_connect can_connect_wrapper 979 #define can_connect2 can_connect2_wrapper 980 #define can_disconnect can_disconnect_wrapper 981 #define can_shutdown can_shutdown_wrapper 982 #define can_abort can_abort_wrapper 983 #define can_ioctl can_ioctl_wrapper 984 #define can_stat can_stat_wrapper 985 #define can_peeraddr can_peeraddr_wrapper 986 #define can_sockaddr can_sockaddr_wrapper 987 #define can_rcvd can_rcvd_wrapper 988 #define can_recvoob can_recvoob_wrapper 989 #define can_send can_send_wrapper 990 #define can_sendoob can_sendoob_wrapper 991 #define can_purgeif can_purgeif_wrapper 992 993 const struct pr_usrreqs can_usrreqs = { 994 .pr_attach = can_attach, 995 .pr_detach = can_detach, 996 .pr_accept = can_accept, 997 .pr_bind = can_bind, 998 .pr_listen = can_listen, 999 .pr_connect = can_connect, 1000 .pr_connect2 = can_connect2, 1001 .pr_disconnect = can_disconnect, 1002 .pr_shutdown = can_shutdown, 1003 .pr_abort = can_abort, 1004 .pr_ioctl = can_ioctl, 1005 .pr_stat = can_stat, 1006 .pr_peeraddr = can_peeraddr, 1007 .pr_sockaddr = can_sockaddr, 1008 .pr_rcvd = can_rcvd, 1009 .pr_recvoob = can_recvoob, 1010 .pr_send = can_send, 1011 .pr_sendoob = can_sendoob, 1012 .pr_purgeif = can_purgeif, 1013 }; 1014