123162Smckusick /* 229068Smckusick * Copyright (c) 1980, 1986 Regents of the University of California. 3*33183Sbostic * All rights reserved. 423162Smckusick * 5*33183Sbostic * Redistribution and use in source and binary forms are permitted 6*33183Sbostic * provided that this notice is preserved and that due credit is given 7*33183Sbostic * to the University of California at Berkeley. The name of the University 8*33183Sbostic * may not be used to endorse or promote products derived from this 9*33183Sbostic * software without specific prior written permission. This software 10*33183Sbostic * is provided ``as is'' without express or implied warranty. 11*33183Sbostic * 12*33183Sbostic * @(#)raw_usrreq.c 7.3 (Berkeley) 12/30/87 1323162Smckusick */ 145121Swnj 1517037Sbloom #include "param.h" 1617037Sbloom #include "mbuf.h" 1717037Sbloom #include "domain.h" 1817037Sbloom #include "protosw.h" 1917037Sbloom #include "socket.h" 2017037Sbloom #include "socketvar.h" 2117037Sbloom #include "errno.h" 2210890Ssam 2317037Sbloom #include "if.h" 2417037Sbloom #include "route.h" 2517037Sbloom #include "netisr.h" 2617037Sbloom #include "raw_cb.h" 275121Swnj 2829922Skarels #include "../machine/mtpr.h" 2910890Ssam 305121Swnj /* 315612Swnj * Initialize raw connection block q. 326211Swnj */ 335612Swnj raw_init() 345612Swnj { 356211Swnj 365612Swnj rawcb.rcb_next = rawcb.rcb_prev = &rawcb; 376211Swnj rawintrq.ifq_maxlen = IFQ_MAXLEN; 385612Swnj } 395612Swnj 405612Swnj /* 415121Swnj * Raw protocol interface. 425121Swnj */ 436529Ssam raw_input(m0, proto, src, dst) 445612Swnj struct mbuf *m0; 456509Ssam struct sockproto *proto; 466529Ssam struct sockaddr *src, *dst; 475121Swnj { 485612Swnj register struct mbuf *m; 495612Swnj struct raw_header *rh; 505121Swnj int s; 515121Swnj 525612Swnj /* 535612Swnj * Rip off an mbuf for a generic header. 545612Swnj */ 559638Ssam m = m_get(M_DONTWAIT, MT_HEADER); 565612Swnj if (m == 0) { 575612Swnj m_freem(m0); 585612Swnj return; 595612Swnj } 605612Swnj m->m_next = m0; 615612Swnj m->m_len = sizeof(struct raw_header); 625612Swnj rh = mtod(m, struct raw_header *); 636509Ssam rh->raw_dst = *dst; 646509Ssam rh->raw_src = *src; 656509Ssam rh->raw_proto = *proto; 665612Swnj 675612Swnj /* 685612Swnj * Header now contains enough info to decide 695612Swnj * which socket to place packet in (if any). 705612Swnj * Queue it up for the raw protocol process 715612Swnj * running at software interrupt level. 725612Swnj */ 735121Swnj s = splimp(); 746211Swnj if (IF_QFULL(&rawintrq)) 756211Swnj m_freem(m); 766211Swnj else 776211Swnj IF_ENQUEUE(&rawintrq, m); 785121Swnj splx(s); 796263Swnj schednetisr(NETISR_RAW); 805121Swnj } 815121Swnj 825612Swnj /* 835612Swnj * Raw protocol input routine. Process packets entered 845612Swnj * into the queue at interrupt time. Find the socket 855612Swnj * associated with the packet(s) and move them over. If 865612Swnj * nothing exists for this packet, drop it. 875612Swnj */ 885121Swnj rawintr() 895121Swnj { 905121Swnj int s; 915121Swnj struct mbuf *m; 925612Swnj register struct rawcb *rp; 936529Ssam register struct raw_header *rh; 945612Swnj struct socket *last; 955121Swnj 965121Swnj next: 975121Swnj s = splimp(); 985121Swnj IF_DEQUEUE(&rawintrq, m); 995121Swnj splx(s); 1005121Swnj if (m == 0) 1015121Swnj return; 1026509Ssam rh = mtod(m, struct raw_header *); 1035612Swnj last = 0; 1045612Swnj for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) { 10521769Skarels if (rp->rcb_proto.sp_family != rh->raw_proto.sp_family) 1065612Swnj continue; 10721769Skarels if (rp->rcb_proto.sp_protocol && 10821769Skarels rp->rcb_proto.sp_protocol != rh->raw_proto.sp_protocol) 1095612Swnj continue; 1105612Swnj /* 1115612Swnj * We assume the lower level routines have 1125612Swnj * placed the address in a canonical format 1136509Ssam * suitable for a structure comparison. 1145612Swnj */ 1156529Ssam #define equal(a1, a2) \ 1166529Ssam (bcmp((caddr_t)&(a1), (caddr_t)&(a2), sizeof (struct sockaddr)) == 0) 1176509Ssam if ((rp->rcb_flags & RAW_LADDR) && 1186529Ssam !equal(rp->rcb_laddr, rh->raw_dst)) 1195612Swnj continue; 1206509Ssam if ((rp->rcb_flags & RAW_FADDR) && 1216529Ssam !equal(rp->rcb_faddr, rh->raw_src)) 1226509Ssam continue; 1235612Swnj if (last) { 1245612Swnj struct mbuf *n; 12521531Skarels if (n = m_copy(m->m_next, 0, (int)M_COPYALL)) { 12621531Skarels if (sbappendaddr(&last->so_rcv, &rh->raw_src, 12721531Skarels n, (struct mbuf *)0) == 0) 12821531Skarels /* should notify about lost packet */ 12921531Skarels m_freem(n); 13021531Skarels else 13121531Skarels sorwakeup(last); 1325646Ssam } 1335612Swnj } 1346509Ssam last = rp->rcb_socket; 1355612Swnj } 1366584Ssam if (last) { 13712783Ssam if (sbappendaddr(&last->so_rcv, &rh->raw_src, 13821531Skarels m->m_next, (struct mbuf *)0) == 0) 13921531Skarels m_freem(m->m_next); 14021531Skarels else 14121531Skarels sorwakeup(last); 14221531Skarels (void) m_free(m); /* header */ 14321531Skarels } else 14421531Skarels m_freem(m); 1455121Swnj goto next; 1465121Swnj } 1475121Swnj 1488636Sroot /*ARGSUSED*/ 1496584Ssam raw_ctlinput(cmd, arg) 1506584Ssam int cmd; 15126379Skarels struct sockaddr *arg; 1526584Ssam { 1536591Ssam 1546591Ssam if (cmd < 0 || cmd > PRC_NCMDS) 1556591Ssam return; 1568636Sroot /* INCOMPLETE */ 1576584Ssam } 1586584Ssam 1595121Swnj /*ARGSUSED*/ 16012783Ssam raw_usrreq(so, req, m, nam, rights) 1615121Swnj struct socket *so; 1625121Swnj int req; 16312783Ssam struct mbuf *m, *nam, *rights; 1645121Swnj { 1655612Swnj register struct rawcb *rp = sotorawcb(so); 16612783Ssam register int error = 0; 1675121Swnj 16825501Skarels if (req == PRU_CONTROL) 16925501Skarels return (EOPNOTSUPP); 17012783Ssam if (rights && rights->m_len) { 17112783Ssam error = EOPNOTSUPP; 17212783Ssam goto release; 17312783Ssam } 17412783Ssam if (rp == 0 && req != PRU_ATTACH) { 17512783Ssam error = EINVAL; 17612783Ssam goto release; 17712783Ssam } 1785612Swnj switch (req) { 1795612Swnj 1805612Swnj /* 1815612Swnj * Allocate a raw control block and fill in the 1825612Swnj * necessary info to allow packets to be routed to 1835612Swnj * the appropriate raw interface routine. 1845612Swnj */ 1855612Swnj case PRU_ATTACH: 18612783Ssam if ((so->so_state & SS_PRIV) == 0) { 18712783Ssam error = EACCES; 18813116Ssam break; 18912783Ssam } 19012783Ssam if (rp) { 19112783Ssam error = EINVAL; 19213116Ssam break; 19312783Ssam } 19421769Skarels error = raw_attach(so, (int)nam); 1955612Swnj break; 1965612Swnj 1975612Swnj /* 1985612Swnj * Destroy state just before socket deallocation. 1995612Swnj * Flush data or not depending on the options. 2005612Swnj */ 2015612Swnj case PRU_DETACH: 20212783Ssam if (rp == 0) { 20312783Ssam error = ENOTCONN; 20413116Ssam break; 20512783Ssam } 2065612Swnj raw_detach(rp); 2075612Swnj break; 2085612Swnj 2095612Swnj /* 2105612Swnj * If a socket isn't bound to a single address, 2115612Swnj * the raw input routine will hand it anything 2125612Swnj * within that protocol family (assuming there's 2135612Swnj * nothing else around it should go to). 2145612Swnj */ 2155612Swnj case PRU_CONNECT: 21612783Ssam if (rp->rcb_flags & RAW_FADDR) { 21712783Ssam error = EISCONN; 21813116Ssam break; 21912783Ssam } 2208395Swnj raw_connaddr(rp, nam); 2215612Swnj soisconnected(so); 2225612Swnj break; 2235612Swnj 22413116Ssam case PRU_CONNECT2: 22513116Ssam error = EOPNOTSUPP; 22613116Ssam goto release; 22713116Ssam 22812783Ssam case PRU_BIND: 22912783Ssam if (rp->rcb_flags & RAW_LADDR) { 23012783Ssam error = EINVAL; /* XXX */ 23113116Ssam break; 23212783Ssam } 23312783Ssam error = raw_bind(so, nam); 23412783Ssam break; 23512783Ssam 2365612Swnj case PRU_DISCONNECT: 23712783Ssam if ((rp->rcb_flags & RAW_FADDR) == 0) { 23812783Ssam error = ENOTCONN; 23913116Ssam break; 24012783Ssam } 2415612Swnj raw_disconnect(rp); 2425612Swnj soisdisconnected(so); 2435612Swnj break; 2445612Swnj 2455612Swnj /* 2465612Swnj * Mark the connection as being incapable of further input. 2475612Swnj */ 2485612Swnj case PRU_SHUTDOWN: 2495612Swnj socantsendmore(so); 2505612Swnj break; 2515612Swnj 2525612Swnj /* 2535612Swnj * Ship a packet out. The appropriate raw output 2545612Swnj * routine handles any massaging necessary. 2555612Swnj */ 2565612Swnj case PRU_SEND: 2578395Swnj if (nam) { 25812783Ssam if (rp->rcb_flags & RAW_FADDR) { 25912783Ssam error = EISCONN; 26013116Ssam break; 26112783Ssam } 2628395Swnj raw_connaddr(rp, nam); 26312783Ssam } else if ((rp->rcb_flags & RAW_FADDR) == 0) { 26412783Ssam error = ENOTCONN; 26513116Ssam break; 26612783Ssam } 2676505Ssam error = (*so->so_proto->pr_output)(m, so); 26812783Ssam m = NULL; 2698395Swnj if (nam) 2706509Ssam rp->rcb_flags &= ~RAW_FADDR; 2715612Swnj break; 2725612Swnj 2735612Swnj case PRU_ABORT: 2745612Swnj raw_disconnect(rp); 2755612Swnj sofree(so); 2765612Swnj soisdisconnected(so); 2775612Swnj break; 2785612Swnj 27916974Skarels case PRU_SENSE: 28016974Skarels /* 28116974Skarels * stat: don't bother with a blocksize. 28216974Skarels */ 28316974Skarels return (0); 28416974Skarels 2855612Swnj /* 2865612Swnj * Not supported. 2875612Swnj */ 28816773Sbloom case PRU_RCVOOB: 2895612Swnj case PRU_RCVD: 29016773Sbloom return(EOPNOTSUPP); 29116773Sbloom 29225221Skarels case PRU_LISTEN: 29316773Sbloom case PRU_ACCEPT: 2945612Swnj case PRU_SENDOOB: 2955612Swnj error = EOPNOTSUPP; 2965612Swnj break; 2975612Swnj 2986509Ssam case PRU_SOCKADDR: 2998723Sroot bcopy((caddr_t)&rp->rcb_laddr, mtod(nam, caddr_t), 3008395Swnj sizeof (struct sockaddr)); 3018395Swnj nam->m_len = sizeof (struct sockaddr); 3026509Ssam break; 3036509Ssam 30414122Ssam case PRU_PEERADDR: 30514122Ssam bcopy((caddr_t)&rp->rcb_faddr, mtod(nam, caddr_t), 30614122Ssam sizeof (struct sockaddr)); 30714122Ssam nam->m_len = sizeof (struct sockaddr); 30814122Ssam break; 30914122Ssam 3105612Swnj default: 3115612Swnj panic("raw_usrreq"); 3125612Swnj } 31312783Ssam release: 31412783Ssam if (m != NULL) 31512783Ssam m_freem(m); 3165612Swnj return (error); 3175121Swnj } 318