1*17037Sbloom /* raw_usrreq.c 6.5 84/08/28 */ 25121Swnj 3*17037Sbloom #include "param.h" 4*17037Sbloom #include "mbuf.h" 5*17037Sbloom #include "domain.h" 6*17037Sbloom #include "protosw.h" 7*17037Sbloom #include "socket.h" 8*17037Sbloom #include "socketvar.h" 9*17037Sbloom #include "errno.h" 1010890Ssam 11*17037Sbloom #include "if.h" 12*17037Sbloom #include "route.h" 13*17037Sbloom #include "netisr.h" 14*17037Sbloom #include "raw_cb.h" 155121Swnj 1610890Ssam #include "../vax/mtpr.h" 1710890Ssam 185121Swnj /* 195612Swnj * Initialize raw connection block q. 206211Swnj */ 215612Swnj raw_init() 225612Swnj { 236211Swnj 245612Swnj rawcb.rcb_next = rawcb.rcb_prev = &rawcb; 256211Swnj rawintrq.ifq_maxlen = IFQ_MAXLEN; 265612Swnj } 275612Swnj 285612Swnj /* 295121Swnj * Raw protocol interface. 305121Swnj */ 316529Ssam raw_input(m0, proto, src, dst) 325612Swnj struct mbuf *m0; 336509Ssam struct sockproto *proto; 346529Ssam struct sockaddr *src, *dst; 355121Swnj { 365612Swnj register struct mbuf *m; 375612Swnj struct raw_header *rh; 385121Swnj int s; 395121Swnj 405612Swnj /* 415612Swnj * Rip off an mbuf for a generic header. 425612Swnj */ 439638Ssam m = m_get(M_DONTWAIT, MT_HEADER); 445612Swnj if (m == 0) { 455612Swnj m_freem(m0); 465612Swnj return; 475612Swnj } 485612Swnj m->m_next = m0; 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; 9516987Skarels if (lproto->pr_domain->dom_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; 1157517Sroot if ((n = m_copy(m->m_next, 0, (int)M_COPYALL)) == 0) 1165612Swnj goto nospace; 11712783Ssam if (sbappendaddr(&last->so_rcv, &rh->raw_src, 11812783Ssam n, (struct mbuf *)0) == 0) { 1196509Ssam /* should notify about lost packet */ 1205646Ssam m_freem(n); 1215646Ssam goto nospace; 1225646Ssam } 1235612Swnj sorwakeup(last); 1245612Swnj } 1255612Swnj nospace: 1266509Ssam last = rp->rcb_socket; 1275612Swnj } 1286584Ssam if (last) { 1296584Ssam m = m_free(m); /* header */ 13012783Ssam if (sbappendaddr(&last->so_rcv, &rh->raw_src, 13112783Ssam m, (struct mbuf *)0) == 0) 1326584Ssam goto drop; 1336584Ssam sorwakeup(last); 1346584Ssam goto next; 1356584Ssam } 1365121Swnj drop: 1375121Swnj m_freem(m); 1385121Swnj goto next; 1395121Swnj } 1405121Swnj 1418636Sroot /*ARGSUSED*/ 1426584Ssam raw_ctlinput(cmd, arg) 1436584Ssam int cmd; 1446584Ssam caddr_t arg; 1456584Ssam { 1466591Ssam 1476591Ssam if (cmd < 0 || cmd > PRC_NCMDS) 1486591Ssam return; 1498636Sroot /* INCOMPLETE */ 1506584Ssam } 1516584Ssam 1525121Swnj /*ARGSUSED*/ 15312783Ssam raw_usrreq(so, req, m, nam, rights) 1545121Swnj struct socket *so; 1555121Swnj int req; 15612783Ssam struct mbuf *m, *nam, *rights; 1575121Swnj { 1585612Swnj register struct rawcb *rp = sotorawcb(so); 15912783Ssam register int error = 0; 1605121Swnj 16112783Ssam if (rights && rights->m_len) { 16212783Ssam error = EOPNOTSUPP; 16312783Ssam goto release; 16412783Ssam } 16512783Ssam if (rp == 0 && req != PRU_ATTACH) { 16612783Ssam error = EINVAL; 16712783Ssam goto release; 16812783Ssam } 1695612Swnj switch (req) { 1705612Swnj 1715612Swnj /* 1725612Swnj * Allocate a raw control block and fill in the 1735612Swnj * necessary info to allow packets to be routed to 1745612Swnj * the appropriate raw interface routine. 1755612Swnj */ 1765612Swnj case PRU_ATTACH: 17712783Ssam if ((so->so_state & SS_PRIV) == 0) { 17812783Ssam error = EACCES; 17913116Ssam break; 18012783Ssam } 18112783Ssam if (rp) { 18212783Ssam error = EINVAL; 18313116Ssam break; 18412783Ssam } 1858395Swnj error = raw_attach(so); 1865612Swnj break; 1875612Swnj 1885612Swnj /* 1895612Swnj * Destroy state just before socket deallocation. 1905612Swnj * Flush data or not depending on the options. 1915612Swnj */ 1925612Swnj case PRU_DETACH: 19312783Ssam if (rp == 0) { 19412783Ssam error = ENOTCONN; 19513116Ssam break; 19612783Ssam } 1975612Swnj raw_detach(rp); 1985612Swnj break; 1995612Swnj 2005612Swnj /* 2015612Swnj * If a socket isn't bound to a single address, 2025612Swnj * the raw input routine will hand it anything 2035612Swnj * within that protocol family (assuming there's 2045612Swnj * nothing else around it should go to). 2055612Swnj */ 2065612Swnj case PRU_CONNECT: 20712783Ssam if (rp->rcb_flags & RAW_FADDR) { 20812783Ssam error = EISCONN; 20913116Ssam break; 21012783Ssam } 2118395Swnj raw_connaddr(rp, nam); 2125612Swnj soisconnected(so); 2135612Swnj break; 2145612Swnj 21513116Ssam case PRU_CONNECT2: 21613116Ssam error = EOPNOTSUPP; 21713116Ssam goto release; 21813116Ssam 21912783Ssam case PRU_BIND: 22012783Ssam if (rp->rcb_flags & RAW_LADDR) { 22112783Ssam error = EINVAL; /* XXX */ 22213116Ssam break; 22312783Ssam } 22412783Ssam error = raw_bind(so, nam); 22512783Ssam break; 22612783Ssam 2275612Swnj case PRU_DISCONNECT: 22812783Ssam if ((rp->rcb_flags & RAW_FADDR) == 0) { 22912783Ssam error = ENOTCONN; 23013116Ssam break; 23112783Ssam } 23213451Ssam if (rp->rcb_route.ro_rt) 23313451Ssam rtfree(rp->rcb_route.ro_rt); 2345612Swnj raw_disconnect(rp); 2355612Swnj soisdisconnected(so); 2365612Swnj break; 2375612Swnj 2385612Swnj /* 2395612Swnj * Mark the connection as being incapable of further input. 2405612Swnj */ 2415612Swnj case PRU_SHUTDOWN: 2425612Swnj socantsendmore(so); 2435612Swnj break; 2445612Swnj 2455612Swnj /* 2465612Swnj * Ship a packet out. The appropriate raw output 2475612Swnj * routine handles any massaging necessary. 2485612Swnj */ 2495612Swnj case PRU_SEND: 2508395Swnj if (nam) { 25112783Ssam if (rp->rcb_flags & RAW_FADDR) { 25212783Ssam error = EISCONN; 25313116Ssam break; 25412783Ssam } 2558395Swnj raw_connaddr(rp, nam); 25612783Ssam } else if ((rp->rcb_flags & RAW_FADDR) == 0) { 25712783Ssam error = ENOTCONN; 25813116Ssam break; 25912783Ssam } 26013451Ssam /* 26113451Ssam * Check for routing. If new foreign address, or 26213451Ssam * no route presently in use, try to allocate new 26313451Ssam * route. On failure, just hand packet to output 26413451Ssam * routine anyway in case it can handle it. 26513451Ssam */ 26613451Ssam if ((rp->rcb_flags & RAW_DONTROUTE) == 0) 26713451Ssam if (!equal(rp->rcb_faddr, rp->rcb_route.ro_dst) || 26813451Ssam rp->rcb_route.ro_rt == 0) { 26916773Sbloom if (rp->rcb_route.ro_rt) { 27016773Sbloom RTFREE(rp->rcb_route.ro_rt); 27116773Sbloom rp->rcb_route.ro_rt = NULL; 27216773Sbloom } 27313451Ssam rp->rcb_route.ro_dst = rp->rcb_faddr; 27413451Ssam rtalloc(&rp->rcb_route); 27513451Ssam } 2766505Ssam error = (*so->so_proto->pr_output)(m, so); 27712783Ssam m = NULL; 2788395Swnj if (nam) 2796509Ssam rp->rcb_flags &= ~RAW_FADDR; 2805612Swnj break; 2815612Swnj 2825612Swnj case PRU_ABORT: 2835612Swnj raw_disconnect(rp); 2845612Swnj sofree(so); 2855612Swnj soisdisconnected(so); 2865612Swnj break; 2875612Swnj 28816974Skarels case PRU_SENSE: 28916974Skarels /* 29016974Skarels * stat: don't bother with a blocksize. 29116974Skarels */ 29216974Skarels return (0); 29316974Skarels 2945612Swnj /* 2955612Swnj * Not supported. 2965612Swnj */ 29716773Sbloom case PRU_CONTROL: 29816773Sbloom case PRU_RCVOOB: 2995612Swnj case PRU_RCVD: 30016773Sbloom return(EOPNOTSUPP); 30116773Sbloom 30216773Sbloom case PRU_ACCEPT: 3035612Swnj case PRU_SENDOOB: 3045612Swnj error = EOPNOTSUPP; 3055612Swnj break; 3065612Swnj 3076509Ssam case PRU_SOCKADDR: 3088723Sroot bcopy((caddr_t)&rp->rcb_laddr, mtod(nam, caddr_t), 3098395Swnj sizeof (struct sockaddr)); 3108395Swnj nam->m_len = sizeof (struct sockaddr); 3116509Ssam break; 3126509Ssam 31314122Ssam case PRU_PEERADDR: 31414122Ssam bcopy((caddr_t)&rp->rcb_faddr, mtod(nam, caddr_t), 31514122Ssam sizeof (struct sockaddr)); 31614122Ssam nam->m_len = sizeof (struct sockaddr); 31714122Ssam break; 31814122Ssam 3195612Swnj default: 3205612Swnj panic("raw_usrreq"); 3215612Swnj } 32212783Ssam release: 32312783Ssam if (m != NULL) 32412783Ssam m_freem(m); 3255612Swnj return (error); 3265121Swnj } 327