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