1*7517Sroot /* raw_usrreq.c 4.18 82/07/24 */ 25121Swnj 35121Swnj #include "../h/param.h" 45121Swnj #include "../h/mbuf.h" 55612Swnj #include "../h/protosw.h" 65121Swnj #include "../h/socket.h" 75121Swnj #include "../h/socketvar.h" 85121Swnj #include "../h/mtpr.h" 95121Swnj #include "../net/in.h" 105121Swnj #include "../net/in_systm.h" 115121Swnj #include "../net/if.h" 125612Swnj #include "../net/raw_cb.h" 136509Ssam #include <errno.h> 145121Swnj 156211Swnj int rawqmaxlen = IFQ_MAXLEN; 166211Swnj 175121Swnj /* 185612Swnj * Initialize raw connection block q. 196211Swnj */ 205612Swnj raw_init() 215612Swnj { 226211Swnj 235612Swnj rawcb.rcb_next = rawcb.rcb_prev = &rawcb; 246211Swnj rawintrq.ifq_maxlen = IFQ_MAXLEN; 255612Swnj } 265612Swnj 275612Swnj /* 285121Swnj * Raw protocol interface. 295121Swnj */ 306529Ssam raw_input(m0, proto, src, dst) 315612Swnj struct mbuf *m0; 326509Ssam struct sockproto *proto; 336529Ssam struct sockaddr *src, *dst; 345121Swnj { 355612Swnj register struct mbuf *m; 365612Swnj struct raw_header *rh; 375121Swnj int s; 385121Swnj 395612Swnj /* 405612Swnj * Rip off an mbuf for a generic header. 415612Swnj */ 425612Swnj m = m_get(M_DONTWAIT); 435612Swnj if (m == 0) { 445612Swnj m_freem(m0); 455612Swnj return; 465612Swnj } 475612Swnj m->m_next = m0; 485612Swnj m->m_off = MMINOFF; 495612Swnj m->m_len = sizeof(struct raw_header); 505612Swnj rh = mtod(m, struct raw_header *); 516509Ssam rh->raw_dst = *dst; 526509Ssam rh->raw_src = *src; 536509Ssam rh->raw_proto = *proto; 545612Swnj 555612Swnj /* 565612Swnj * Header now contains enough info to decide 575612Swnj * which socket to place packet in (if any). 585612Swnj * Queue it up for the raw protocol process 595612Swnj * running at software interrupt level. 605612Swnj */ 615121Swnj s = splimp(); 626211Swnj if (IF_QFULL(&rawintrq)) 636211Swnj m_freem(m); 646211Swnj else 656211Swnj IF_ENQUEUE(&rawintrq, m); 665121Swnj splx(s); 676263Swnj schednetisr(NETISR_RAW); 685121Swnj } 695121Swnj 705612Swnj /* 715612Swnj * Raw protocol input routine. Process packets entered 725612Swnj * into the queue at interrupt time. Find the socket 735612Swnj * associated with the packet(s) and move them over. If 745612Swnj * nothing exists for this packet, drop it. 755612Swnj */ 765121Swnj rawintr() 775121Swnj { 785121Swnj int s; 795121Swnj struct mbuf *m; 805612Swnj register struct rawcb *rp; 816509Ssam register struct protosw *lproto; 826529Ssam register struct raw_header *rh; 835612Swnj struct socket *last; 845121Swnj 855121Swnj next: 865121Swnj s = splimp(); 875121Swnj IF_DEQUEUE(&rawintrq, m); 885121Swnj splx(s); 895121Swnj if (m == 0) 905121Swnj return; 916509Ssam rh = mtod(m, struct raw_header *); 925612Swnj last = 0; 935612Swnj for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) { 946509Ssam lproto = rp->rcb_socket->so_proto; 956509Ssam if (lproto->pr_family != rh->raw_proto.sp_family) 965612Swnj continue; 976509Ssam if (lproto->pr_protocol && 986509Ssam lproto->pr_protocol != rh->raw_proto.sp_protocol) 995612Swnj continue; 1005612Swnj /* 1015612Swnj * We assume the lower level routines have 1025612Swnj * placed the address in a canonical format 1036509Ssam * suitable for a structure comparison. 1045612Swnj */ 1056529Ssam #define equal(a1, a2) \ 1066529Ssam (bcmp((caddr_t)&(a1), (caddr_t)&(a2), sizeof (struct sockaddr)) == 0) 1076509Ssam if ((rp->rcb_flags & RAW_LADDR) && 1086529Ssam !equal(rp->rcb_laddr, rh->raw_dst)) 1095612Swnj continue; 1106509Ssam if ((rp->rcb_flags & RAW_FADDR) && 1116529Ssam !equal(rp->rcb_faddr, rh->raw_src)) 1126509Ssam continue; 1135612Swnj if (last) { 1145612Swnj struct mbuf *n; 115*7517Sroot if ((n = m_copy(m->m_next, 0, (int)M_COPYALL)) == 0) 1165612Swnj goto nospace; 1176509Ssam if (sbappendaddr(&last->so_rcv, &rh->raw_src, n)==0) { 1186509Ssam /* should notify about lost packet */ 1195646Ssam m_freem(n); 1205646Ssam goto nospace; 1215646Ssam } 1225612Swnj sorwakeup(last); 1235612Swnj } 1245612Swnj nospace: 1256509Ssam last = rp->rcb_socket; 1265612Swnj } 1276584Ssam if (last) { 1286584Ssam m = m_free(m); /* header */ 1296584Ssam if (sbappendaddr(&last->so_rcv, &rh->raw_src, m) == 0) 1306584Ssam goto drop; 1316584Ssam sorwakeup(last); 1326584Ssam goto next; 1336584Ssam } 1345121Swnj drop: 1355121Swnj m_freem(m); 1365121Swnj goto next; 1375121Swnj } 1385121Swnj 1396584Ssam raw_ctlinput(cmd, arg) 1406584Ssam int cmd; 1416584Ssam caddr_t arg; 1426584Ssam { 1436591Ssam 1446591Ssam if (cmd < 0 || cmd > PRC_NCMDS) 1456591Ssam return; 1466584Ssam } 1476584Ssam 1485121Swnj /*ARGSUSED*/ 1495121Swnj raw_usrreq(so, req, m, addr) 1505121Swnj struct socket *so; 1515121Swnj int req; 1525121Swnj struct mbuf *m; 1535121Swnj caddr_t addr; 1545121Swnj { 1555612Swnj register struct rawcb *rp = sotorawcb(so); 1565612Swnj int error = 0; 1575121Swnj 1585612Swnj if (rp == 0 && req != PRU_ATTACH) 1595612Swnj return (EINVAL); 1605121Swnj 1615612Swnj switch (req) { 1625612Swnj 1635612Swnj /* 1645612Swnj * Allocate a raw control block and fill in the 1655612Swnj * necessary info to allow packets to be routed to 1665612Swnj * the appropriate raw interface routine. 1675612Swnj */ 1685612Swnj case PRU_ATTACH: 1696211Swnj if ((so->so_state & SS_PRIV) == 0) 1706584Ssam return (EACCES); 1715612Swnj if (rp) 1726211Swnj return (EINVAL); 1735612Swnj error = raw_attach(so, (struct sockaddr *)addr); 1745612Swnj break; 1755612Swnj 1765612Swnj /* 1775612Swnj * Destroy state just before socket deallocation. 1785612Swnj * Flush data or not depending on the options. 1795612Swnj */ 1805612Swnj case PRU_DETACH: 1815612Swnj if (rp == 0) 1825612Swnj return (ENOTCONN); 1835612Swnj raw_detach(rp); 1845612Swnj break; 1855612Swnj 1865612Swnj /* 1875612Swnj * If a socket isn't bound to a single address, 1885612Swnj * the raw input routine will hand it anything 1895612Swnj * within that protocol family (assuming there's 1905612Swnj * nothing else around it should go to). 1915612Swnj */ 1925612Swnj case PRU_CONNECT: 1936509Ssam if (rp->rcb_flags & RAW_FADDR) 1945612Swnj return (EISCONN); 1955612Swnj raw_connaddr(rp, (struct sockaddr *)addr); 1965612Swnj soisconnected(so); 1975612Swnj break; 1985612Swnj 1995612Swnj case PRU_DISCONNECT: 2006509Ssam if ((rp->rcb_flags & RAW_FADDR) == 0) 2015612Swnj return (ENOTCONN); 2025612Swnj raw_disconnect(rp); 2035612Swnj soisdisconnected(so); 2045612Swnj break; 2055612Swnj 2065612Swnj /* 2075612Swnj * Mark the connection as being incapable of further input. 2085612Swnj */ 2095612Swnj case PRU_SHUTDOWN: 2105612Swnj socantsendmore(so); 2115612Swnj break; 2125612Swnj 2135612Swnj /* 2145612Swnj * Ship a packet out. The appropriate raw output 2155612Swnj * routine handles any massaging necessary. 2165612Swnj */ 2175612Swnj case PRU_SEND: 2185612Swnj if (addr) { 2196509Ssam if (rp->rcb_flags & RAW_FADDR) 2205612Swnj return (EISCONN); 2215612Swnj raw_connaddr(rp, (struct sockaddr *)addr); 2226509Ssam } else if ((rp->rcb_flags & RAW_FADDR) == 0) 2235612Swnj return (ENOTCONN); 2246505Ssam error = (*so->so_proto->pr_output)(m, so); 2255612Swnj if (addr) 2266509Ssam rp->rcb_flags &= ~RAW_FADDR; 2275612Swnj break; 2285612Swnj 2295612Swnj case PRU_ABORT: 2305612Swnj raw_disconnect(rp); 2315612Swnj sofree(so); 2325612Swnj soisdisconnected(so); 2335612Swnj break; 2345612Swnj 2355612Swnj /* 2365612Swnj * Not supported. 2375612Swnj */ 2385612Swnj case PRU_ACCEPT: 2395612Swnj case PRU_RCVD: 2405612Swnj case PRU_CONTROL: 2415612Swnj case PRU_SENSE: 2425612Swnj case PRU_RCVOOB: 2435612Swnj case PRU_SENDOOB: 2445612Swnj error = EOPNOTSUPP; 2455612Swnj break; 2465612Swnj 2476509Ssam case PRU_SOCKADDR: 2486509Ssam bcopy(addr, (caddr_t)&rp->rcb_laddr, sizeof (struct sockaddr)); 2496509Ssam break; 2506509Ssam 2515612Swnj default: 2525612Swnj panic("raw_usrreq"); 2535612Swnj } 2545612Swnj return (error); 2555121Swnj } 256