1*16974Skarels /* raw_usrreq.c 6.3 84/08/20 */ 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" 810890Ssam #include "../h/errno.h" 910890Ssam 105121Swnj #include "../net/if.h" 1113451Ssam #include "../net/route.h" 128395Swnj #include "../net/netisr.h" 135612Swnj #include "../net/raw_cb.h" 145121Swnj 1510890Ssam #include "../vax/mtpr.h" 1610890Ssam 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 */ 429638Ssam m = m_get(M_DONTWAIT, MT_HEADER); 435612Swnj if (m == 0) { 445612Swnj m_freem(m0); 455612Swnj return; 465612Swnj } 475612Swnj m->m_next = m0; 485612Swnj m->m_len = sizeof(struct raw_header); 495612Swnj rh = mtod(m, struct raw_header *); 506509Ssam rh->raw_dst = *dst; 516509Ssam rh->raw_src = *src; 526509Ssam rh->raw_proto = *proto; 535612Swnj 545612Swnj /* 555612Swnj * Header now contains enough info to decide 565612Swnj * which socket to place packet in (if any). 575612Swnj * Queue it up for the raw protocol process 585612Swnj * running at software interrupt level. 595612Swnj */ 605121Swnj s = splimp(); 616211Swnj if (IF_QFULL(&rawintrq)) 626211Swnj m_freem(m); 636211Swnj else 646211Swnj IF_ENQUEUE(&rawintrq, m); 655121Swnj splx(s); 666263Swnj schednetisr(NETISR_RAW); 675121Swnj } 685121Swnj 695612Swnj /* 705612Swnj * Raw protocol input routine. Process packets entered 715612Swnj * into the queue at interrupt time. Find the socket 725612Swnj * associated with the packet(s) and move them over. If 735612Swnj * nothing exists for this packet, drop it. 745612Swnj */ 755121Swnj rawintr() 765121Swnj { 775121Swnj int s; 785121Swnj struct mbuf *m; 795612Swnj register struct rawcb *rp; 806509Ssam register struct protosw *lproto; 816529Ssam register struct raw_header *rh; 825612Swnj struct socket *last; 835121Swnj 845121Swnj next: 855121Swnj s = splimp(); 865121Swnj IF_DEQUEUE(&rawintrq, m); 875121Swnj splx(s); 885121Swnj if (m == 0) 895121Swnj return; 906509Ssam rh = mtod(m, struct raw_header *); 915612Swnj last = 0; 925612Swnj for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) { 936509Ssam lproto = rp->rcb_socket->so_proto; 946509Ssam if (lproto->pr_family != rh->raw_proto.sp_family) 955612Swnj continue; 966509Ssam if (lproto->pr_protocol && 976509Ssam lproto->pr_protocol != rh->raw_proto.sp_protocol) 985612Swnj continue; 995612Swnj /* 1005612Swnj * We assume the lower level routines have 1015612Swnj * placed the address in a canonical format 1026509Ssam * suitable for a structure comparison. 1035612Swnj */ 1046529Ssam #define equal(a1, a2) \ 1056529Ssam (bcmp((caddr_t)&(a1), (caddr_t)&(a2), sizeof (struct sockaddr)) == 0) 1066509Ssam if ((rp->rcb_flags & RAW_LADDR) && 1076529Ssam !equal(rp->rcb_laddr, rh->raw_dst)) 1085612Swnj continue; 1096509Ssam if ((rp->rcb_flags & RAW_FADDR) && 1106529Ssam !equal(rp->rcb_faddr, rh->raw_src)) 1116509Ssam continue; 1125612Swnj if (last) { 1135612Swnj struct mbuf *n; 1147517Sroot if ((n = m_copy(m->m_next, 0, (int)M_COPYALL)) == 0) 1155612Swnj goto nospace; 11612783Ssam if (sbappendaddr(&last->so_rcv, &rh->raw_src, 11712783Ssam n, (struct mbuf *)0) == 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 */ 12912783Ssam if (sbappendaddr(&last->so_rcv, &rh->raw_src, 13012783Ssam m, (struct mbuf *)0) == 0) 1316584Ssam goto drop; 1326584Ssam sorwakeup(last); 1336584Ssam goto next; 1346584Ssam } 1355121Swnj drop: 1365121Swnj m_freem(m); 1375121Swnj goto next; 1385121Swnj } 1395121Swnj 1408636Sroot /*ARGSUSED*/ 1416584Ssam raw_ctlinput(cmd, arg) 1426584Ssam int cmd; 1436584Ssam caddr_t arg; 1446584Ssam { 1456591Ssam 1466591Ssam if (cmd < 0 || cmd > PRC_NCMDS) 1476591Ssam return; 1488636Sroot /* INCOMPLETE */ 1496584Ssam } 1506584Ssam 1515121Swnj /*ARGSUSED*/ 15212783Ssam raw_usrreq(so, req, m, nam, rights) 1535121Swnj struct socket *so; 1545121Swnj int req; 15512783Ssam struct mbuf *m, *nam, *rights; 1565121Swnj { 1575612Swnj register struct rawcb *rp = sotorawcb(so); 15812783Ssam register int error = 0; 1595121Swnj 16012783Ssam if (rights && rights->m_len) { 16112783Ssam error = EOPNOTSUPP; 16212783Ssam goto release; 16312783Ssam } 16412783Ssam if (rp == 0 && req != PRU_ATTACH) { 16512783Ssam error = EINVAL; 16612783Ssam goto release; 16712783Ssam } 1685612Swnj switch (req) { 1695612Swnj 1705612Swnj /* 1715612Swnj * Allocate a raw control block and fill in the 1725612Swnj * necessary info to allow packets to be routed to 1735612Swnj * the appropriate raw interface routine. 1745612Swnj */ 1755612Swnj case PRU_ATTACH: 17612783Ssam if ((so->so_state & SS_PRIV) == 0) { 17712783Ssam error = EACCES; 17813116Ssam break; 17912783Ssam } 18012783Ssam if (rp) { 18112783Ssam error = EINVAL; 18213116Ssam break; 18312783Ssam } 1848395Swnj error = raw_attach(so); 1855612Swnj break; 1865612Swnj 1875612Swnj /* 1885612Swnj * Destroy state just before socket deallocation. 1895612Swnj * Flush data or not depending on the options. 1905612Swnj */ 1915612Swnj case PRU_DETACH: 19212783Ssam if (rp == 0) { 19312783Ssam error = ENOTCONN; 19413116Ssam break; 19512783Ssam } 1965612Swnj raw_detach(rp); 1975612Swnj break; 1985612Swnj 1995612Swnj /* 2005612Swnj * If a socket isn't bound to a single address, 2015612Swnj * the raw input routine will hand it anything 2025612Swnj * within that protocol family (assuming there's 2035612Swnj * nothing else around it should go to). 2045612Swnj */ 2055612Swnj case PRU_CONNECT: 20612783Ssam if (rp->rcb_flags & RAW_FADDR) { 20712783Ssam error = EISCONN; 20813116Ssam break; 20912783Ssam } 2108395Swnj raw_connaddr(rp, nam); 2115612Swnj soisconnected(so); 2125612Swnj break; 2135612Swnj 21413116Ssam case PRU_CONNECT2: 21513116Ssam error = EOPNOTSUPP; 21613116Ssam goto release; 21713116Ssam 21812783Ssam case PRU_BIND: 21912783Ssam if (rp->rcb_flags & RAW_LADDR) { 22012783Ssam error = EINVAL; /* XXX */ 22113116Ssam break; 22212783Ssam } 22312783Ssam error = raw_bind(so, nam); 22412783Ssam break; 22512783Ssam 2265612Swnj case PRU_DISCONNECT: 22712783Ssam if ((rp->rcb_flags & RAW_FADDR) == 0) { 22812783Ssam error = ENOTCONN; 22913116Ssam break; 23012783Ssam } 23113451Ssam if (rp->rcb_route.ro_rt) 23213451Ssam rtfree(rp->rcb_route.ro_rt); 2335612Swnj raw_disconnect(rp); 2345612Swnj soisdisconnected(so); 2355612Swnj break; 2365612Swnj 2375612Swnj /* 2385612Swnj * Mark the connection as being incapable of further input. 2395612Swnj */ 2405612Swnj case PRU_SHUTDOWN: 2415612Swnj socantsendmore(so); 2425612Swnj break; 2435612Swnj 2445612Swnj /* 2455612Swnj * Ship a packet out. The appropriate raw output 2465612Swnj * routine handles any massaging necessary. 2475612Swnj */ 2485612Swnj case PRU_SEND: 2498395Swnj if (nam) { 25012783Ssam if (rp->rcb_flags & RAW_FADDR) { 25112783Ssam error = EISCONN; 25213116Ssam break; 25312783Ssam } 2548395Swnj raw_connaddr(rp, nam); 25512783Ssam } else if ((rp->rcb_flags & RAW_FADDR) == 0) { 25612783Ssam error = ENOTCONN; 25713116Ssam break; 25812783Ssam } 25913451Ssam /* 26013451Ssam * Check for routing. If new foreign address, or 26113451Ssam * no route presently in use, try to allocate new 26213451Ssam * route. On failure, just hand packet to output 26313451Ssam * routine anyway in case it can handle it. 26413451Ssam */ 26513451Ssam if ((rp->rcb_flags & RAW_DONTROUTE) == 0) 26613451Ssam if (!equal(rp->rcb_faddr, rp->rcb_route.ro_dst) || 26713451Ssam rp->rcb_route.ro_rt == 0) { 26816773Sbloom if (rp->rcb_route.ro_rt) { 26916773Sbloom RTFREE(rp->rcb_route.ro_rt); 27016773Sbloom rp->rcb_route.ro_rt = NULL; 27116773Sbloom } 27213451Ssam rp->rcb_route.ro_dst = rp->rcb_faddr; 27313451Ssam rtalloc(&rp->rcb_route); 27413451Ssam } 2756505Ssam error = (*so->so_proto->pr_output)(m, so); 27612783Ssam m = NULL; 2778395Swnj if (nam) 2786509Ssam rp->rcb_flags &= ~RAW_FADDR; 2795612Swnj break; 2805612Swnj 2815612Swnj case PRU_ABORT: 2825612Swnj raw_disconnect(rp); 2835612Swnj sofree(so); 2845612Swnj soisdisconnected(so); 2855612Swnj break; 2865612Swnj 287*16974Skarels case PRU_SENSE: 288*16974Skarels /* 289*16974Skarels * stat: don't bother with a blocksize. 290*16974Skarels */ 291*16974Skarels return (0); 292*16974Skarels 2935612Swnj /* 2945612Swnj * Not supported. 2955612Swnj */ 29616773Sbloom case PRU_CONTROL: 29716773Sbloom case PRU_RCVOOB: 2985612Swnj case PRU_RCVD: 29916773Sbloom return(EOPNOTSUPP); 30016773Sbloom 30116773Sbloom case PRU_ACCEPT: 3025612Swnj case PRU_SENDOOB: 3035612Swnj error = EOPNOTSUPP; 3045612Swnj break; 3055612Swnj 3066509Ssam case PRU_SOCKADDR: 3078723Sroot bcopy((caddr_t)&rp->rcb_laddr, mtod(nam, caddr_t), 3088395Swnj sizeof (struct sockaddr)); 3098395Swnj nam->m_len = sizeof (struct sockaddr); 3106509Ssam break; 3116509Ssam 31214122Ssam case PRU_PEERADDR: 31314122Ssam bcopy((caddr_t)&rp->rcb_faddr, mtod(nam, caddr_t), 31414122Ssam sizeof (struct sockaddr)); 31514122Ssam nam->m_len = sizeof (struct sockaddr); 31614122Ssam break; 31714122Ssam 3185612Swnj default: 3195612Swnj panic("raw_usrreq"); 3205612Swnj } 32112783Ssam release: 32212783Ssam if (m != NULL) 32312783Ssam m_freem(m); 3245612Swnj return (error); 3255121Swnj } 326