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