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