123162Smckusick /* 223162Smckusick * Copyright (c) 1980 Regents of the University of California. 323162Smckusick * All rights reserved. The Berkeley software License Agreement 423162Smckusick * specifies the terms and conditions for redistribution. 523162Smckusick * 6*25501Skarels * @(#)raw_usrreq.c 6.10 (Berkeley) 11/19/85 723162Smckusick */ 85121Swnj 917037Sbloom #include "param.h" 1017037Sbloom #include "mbuf.h" 1117037Sbloom #include "domain.h" 1217037Sbloom #include "protosw.h" 1317037Sbloom #include "socket.h" 1417037Sbloom #include "socketvar.h" 1517037Sbloom #include "errno.h" 1610890Ssam 1717037Sbloom #include "if.h" 1817037Sbloom #include "route.h" 1917037Sbloom #include "netisr.h" 2017037Sbloom #include "raw_cb.h" 215121Swnj 2210890Ssam #include "../vax/mtpr.h" 2310890Ssam 245121Swnj /* 255612Swnj * Initialize raw connection block q. 266211Swnj */ 275612Swnj raw_init() 285612Swnj { 296211Swnj 305612Swnj rawcb.rcb_next = rawcb.rcb_prev = &rawcb; 316211Swnj rawintrq.ifq_maxlen = IFQ_MAXLEN; 325612Swnj } 335612Swnj 345612Swnj /* 355121Swnj * Raw protocol interface. 365121Swnj */ 376529Ssam raw_input(m0, proto, src, dst) 385612Swnj struct mbuf *m0; 396509Ssam struct sockproto *proto; 406529Ssam struct sockaddr *src, *dst; 415121Swnj { 425612Swnj register struct mbuf *m; 435612Swnj struct raw_header *rh; 445121Swnj int s; 455121Swnj 465612Swnj /* 475612Swnj * Rip off an mbuf for a generic header. 485612Swnj */ 499638Ssam m = m_get(M_DONTWAIT, MT_HEADER); 505612Swnj if (m == 0) { 515612Swnj m_freem(m0); 525612Swnj return; 535612Swnj } 545612Swnj m->m_next = m0; 555612Swnj m->m_len = sizeof(struct raw_header); 565612Swnj rh = mtod(m, struct raw_header *); 576509Ssam rh->raw_dst = *dst; 586509Ssam rh->raw_src = *src; 596509Ssam rh->raw_proto = *proto; 605612Swnj 615612Swnj /* 625612Swnj * Header now contains enough info to decide 635612Swnj * which socket to place packet in (if any). 645612Swnj * Queue it up for the raw protocol process 655612Swnj * running at software interrupt level. 665612Swnj */ 675121Swnj s = splimp(); 686211Swnj if (IF_QFULL(&rawintrq)) 696211Swnj m_freem(m); 706211Swnj else 716211Swnj IF_ENQUEUE(&rawintrq, m); 725121Swnj splx(s); 736263Swnj schednetisr(NETISR_RAW); 745121Swnj } 755121Swnj 765612Swnj /* 775612Swnj * Raw protocol input routine. Process packets entered 785612Swnj * into the queue at interrupt time. Find the socket 795612Swnj * associated with the packet(s) and move them over. If 805612Swnj * nothing exists for this packet, drop it. 815612Swnj */ 825121Swnj rawintr() 835121Swnj { 845121Swnj int s; 855121Swnj struct mbuf *m; 865612Swnj register struct rawcb *rp; 876529Ssam register struct raw_header *rh; 885612Swnj struct socket *last; 895121Swnj 905121Swnj next: 915121Swnj s = splimp(); 925121Swnj IF_DEQUEUE(&rawintrq, m); 935121Swnj splx(s); 945121Swnj if (m == 0) 955121Swnj return; 966509Ssam rh = mtod(m, struct raw_header *); 975612Swnj last = 0; 985612Swnj for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) { 9921769Skarels if (rp->rcb_proto.sp_family != rh->raw_proto.sp_family) 1005612Swnj continue; 10121769Skarels if (rp->rcb_proto.sp_protocol && 10221769Skarels rp->rcb_proto.sp_protocol != rh->raw_proto.sp_protocol) 1035612Swnj continue; 1045612Swnj /* 1055612Swnj * We assume the lower level routines have 1065612Swnj * placed the address in a canonical format 1076509Ssam * suitable for a structure comparison. 1085612Swnj */ 1096529Ssam #define equal(a1, a2) \ 1106529Ssam (bcmp((caddr_t)&(a1), (caddr_t)&(a2), sizeof (struct sockaddr)) == 0) 1116509Ssam if ((rp->rcb_flags & RAW_LADDR) && 1126529Ssam !equal(rp->rcb_laddr, rh->raw_dst)) 1135612Swnj continue; 1146509Ssam if ((rp->rcb_flags & RAW_FADDR) && 1156529Ssam !equal(rp->rcb_faddr, rh->raw_src)) 1166509Ssam continue; 1175612Swnj if (last) { 1185612Swnj struct mbuf *n; 11921531Skarels if (n = m_copy(m->m_next, 0, (int)M_COPYALL)) { 12021531Skarels if (sbappendaddr(&last->so_rcv, &rh->raw_src, 12121531Skarels n, (struct mbuf *)0) == 0) 12221531Skarels /* should notify about lost packet */ 12321531Skarels m_freem(n); 12421531Skarels else 12521531Skarels sorwakeup(last); 1265646Ssam } 1275612Swnj } 1286509Ssam last = rp->rcb_socket; 1295612Swnj } 1306584Ssam if (last) { 13112783Ssam if (sbappendaddr(&last->so_rcv, &rh->raw_src, 13221531Skarels m->m_next, (struct mbuf *)0) == 0) 13321531Skarels m_freem(m->m_next); 13421531Skarels else 13521531Skarels sorwakeup(last); 13621531Skarels (void) m_free(m); /* header */ 13721531Skarels } else 13821531Skarels m_freem(m); 1395121Swnj goto next; 1405121Swnj } 1415121Swnj 1428636Sroot /*ARGSUSED*/ 1436584Ssam raw_ctlinput(cmd, arg) 1446584Ssam int cmd; 1456584Ssam caddr_t arg; 1466584Ssam { 1476591Ssam 1486591Ssam if (cmd < 0 || cmd > PRC_NCMDS) 1496591Ssam return; 1508636Sroot /* INCOMPLETE */ 1516584Ssam } 1526584Ssam 1535121Swnj /*ARGSUSED*/ 15412783Ssam raw_usrreq(so, req, m, nam, rights) 1555121Swnj struct socket *so; 1565121Swnj int req; 15712783Ssam struct mbuf *m, *nam, *rights; 1585121Swnj { 1595612Swnj register struct rawcb *rp = sotorawcb(so); 16012783Ssam register int error = 0; 1615121Swnj 162*25501Skarels if (req == PRU_CONTROL) 163*25501Skarels return (EOPNOTSUPP); 16412783Ssam if (rights && rights->m_len) { 16512783Ssam error = EOPNOTSUPP; 16612783Ssam goto release; 16712783Ssam } 16812783Ssam if (rp == 0 && req != PRU_ATTACH) { 16912783Ssam error = EINVAL; 17012783Ssam goto release; 17112783Ssam } 1725612Swnj switch (req) { 1735612Swnj 1745612Swnj /* 1755612Swnj * Allocate a raw control block and fill in the 1765612Swnj * necessary info to allow packets to be routed to 1775612Swnj * the appropriate raw interface routine. 1785612Swnj */ 1795612Swnj case PRU_ATTACH: 18012783Ssam if ((so->so_state & SS_PRIV) == 0) { 18112783Ssam error = EACCES; 18213116Ssam break; 18312783Ssam } 18412783Ssam if (rp) { 18512783Ssam error = EINVAL; 18613116Ssam break; 18712783Ssam } 18821769Skarels error = raw_attach(so, (int)nam); 1895612Swnj break; 1905612Swnj 1915612Swnj /* 1925612Swnj * Destroy state just before socket deallocation. 1935612Swnj * Flush data or not depending on the options. 1945612Swnj */ 1955612Swnj case PRU_DETACH: 19612783Ssam if (rp == 0) { 19712783Ssam error = ENOTCONN; 19813116Ssam break; 19912783Ssam } 2005612Swnj raw_detach(rp); 2015612Swnj break; 2025612Swnj 2035612Swnj /* 2045612Swnj * If a socket isn't bound to a single address, 2055612Swnj * the raw input routine will hand it anything 2065612Swnj * within that protocol family (assuming there's 2075612Swnj * nothing else around it should go to). 2085612Swnj */ 2095612Swnj case PRU_CONNECT: 21012783Ssam if (rp->rcb_flags & RAW_FADDR) { 21112783Ssam error = EISCONN; 21213116Ssam break; 21312783Ssam } 2148395Swnj raw_connaddr(rp, nam); 2155612Swnj soisconnected(so); 2165612Swnj break; 2175612Swnj 21813116Ssam case PRU_CONNECT2: 21913116Ssam error = EOPNOTSUPP; 22013116Ssam goto release; 22113116Ssam 22212783Ssam case PRU_BIND: 22312783Ssam if (rp->rcb_flags & RAW_LADDR) { 22412783Ssam error = EINVAL; /* XXX */ 22513116Ssam break; 22612783Ssam } 22712783Ssam error = raw_bind(so, nam); 22812783Ssam break; 22912783Ssam 2305612Swnj case PRU_DISCONNECT: 23112783Ssam if ((rp->rcb_flags & RAW_FADDR) == 0) { 23212783Ssam error = ENOTCONN; 23313116Ssam break; 23412783Ssam } 23513451Ssam if (rp->rcb_route.ro_rt) 23613451Ssam rtfree(rp->rcb_route.ro_rt); 2375612Swnj raw_disconnect(rp); 2385612Swnj soisdisconnected(so); 2395612Swnj break; 2405612Swnj 2415612Swnj /* 2425612Swnj * Mark the connection as being incapable of further input. 2435612Swnj */ 2445612Swnj case PRU_SHUTDOWN: 2455612Swnj socantsendmore(so); 2465612Swnj break; 2475612Swnj 2485612Swnj /* 2495612Swnj * Ship a packet out. The appropriate raw output 2505612Swnj * routine handles any massaging necessary. 2515612Swnj */ 2525612Swnj case PRU_SEND: 2538395Swnj if (nam) { 25412783Ssam if (rp->rcb_flags & RAW_FADDR) { 25512783Ssam error = EISCONN; 25613116Ssam break; 25712783Ssam } 2588395Swnj raw_connaddr(rp, nam); 25912783Ssam } else if ((rp->rcb_flags & RAW_FADDR) == 0) { 26012783Ssam error = ENOTCONN; 26113116Ssam break; 26212783Ssam } 26313451Ssam /* 26413451Ssam * Check for routing. If new foreign address, or 26513451Ssam * no route presently in use, try to allocate new 26613451Ssam * route. On failure, just hand packet to output 26713451Ssam * routine anyway in case it can handle it. 26813451Ssam */ 26913451Ssam if ((rp->rcb_flags & RAW_DONTROUTE) == 0) 27013451Ssam if (!equal(rp->rcb_faddr, rp->rcb_route.ro_dst) || 27113451Ssam rp->rcb_route.ro_rt == 0) { 27216773Sbloom if (rp->rcb_route.ro_rt) { 27316773Sbloom RTFREE(rp->rcb_route.ro_rt); 27416773Sbloom rp->rcb_route.ro_rt = NULL; 27516773Sbloom } 27613451Ssam rp->rcb_route.ro_dst = rp->rcb_faddr; 27713451Ssam rtalloc(&rp->rcb_route); 27813451Ssam } 2796505Ssam error = (*so->so_proto->pr_output)(m, so); 28012783Ssam m = NULL; 2818395Swnj if (nam) 2826509Ssam rp->rcb_flags &= ~RAW_FADDR; 2835612Swnj break; 2845612Swnj 2855612Swnj case PRU_ABORT: 2865612Swnj raw_disconnect(rp); 2875612Swnj sofree(so); 2885612Swnj soisdisconnected(so); 2895612Swnj break; 2905612Swnj 29116974Skarels case PRU_SENSE: 29216974Skarels /* 29316974Skarels * stat: don't bother with a blocksize. 29416974Skarels */ 29516974Skarels return (0); 29616974Skarels 2975612Swnj /* 2985612Swnj * Not supported. 2995612Swnj */ 30016773Sbloom case PRU_RCVOOB: 3015612Swnj case PRU_RCVD: 30216773Sbloom return(EOPNOTSUPP); 30316773Sbloom 30425221Skarels case PRU_LISTEN: 30516773Sbloom case PRU_ACCEPT: 3065612Swnj case PRU_SENDOOB: 3075612Swnj error = EOPNOTSUPP; 3085612Swnj break; 3095612Swnj 3106509Ssam case PRU_SOCKADDR: 3118723Sroot bcopy((caddr_t)&rp->rcb_laddr, mtod(nam, caddr_t), 3128395Swnj sizeof (struct sockaddr)); 3138395Swnj nam->m_len = sizeof (struct sockaddr); 3146509Ssam break; 3156509Ssam 31614122Ssam case PRU_PEERADDR: 31714122Ssam bcopy((caddr_t)&rp->rcb_faddr, mtod(nam, caddr_t), 31814122Ssam sizeof (struct sockaddr)); 31914122Ssam nam->m_len = sizeof (struct sockaddr); 32014122Ssam break; 32114122Ssam 3225612Swnj default: 3235612Swnj panic("raw_usrreq"); 3245612Swnj } 32512783Ssam release: 32612783Ssam if (m != NULL) 32712783Ssam m_freem(m); 3285612Swnj return (error); 3295121Swnj } 330