123162Smckusick /* 229068Smckusick * Copyright (c) 1980, 1986 Regents of the University of California. 333183Sbostic * All rights reserved. 423162Smckusick * 533183Sbostic * Redistribution and use in source and binary forms are permitted 6*34844Sbostic * provided that the above copyright notice and this paragraph are 7*34844Sbostic * duplicated in all such forms and that any documentation, 8*34844Sbostic * advertising materials, and other materials related to such 9*34844Sbostic * distribution and use acknowledge that the software was developed 10*34844Sbostic * by the University of California, Berkeley. The name of the 11*34844Sbostic * University may not be used to endorse or promote products derived 12*34844Sbostic * from this software without specific prior written permission. 13*34844Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*34844Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*34844Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633183Sbostic * 17*34844Sbostic * @(#)raw_usrreq.c 7.4 (Berkeley) 06/27/88 1823162Smckusick */ 195121Swnj 2017037Sbloom #include "param.h" 2117037Sbloom #include "mbuf.h" 2217037Sbloom #include "domain.h" 2317037Sbloom #include "protosw.h" 2417037Sbloom #include "socket.h" 2517037Sbloom #include "socketvar.h" 2617037Sbloom #include "errno.h" 2710890Ssam 2817037Sbloom #include "if.h" 2917037Sbloom #include "route.h" 3017037Sbloom #include "netisr.h" 3117037Sbloom #include "raw_cb.h" 325121Swnj 3329922Skarels #include "../machine/mtpr.h" 3410890Ssam 355121Swnj /* 365612Swnj * Initialize raw connection block q. 376211Swnj */ 385612Swnj raw_init() 395612Swnj { 406211Swnj 415612Swnj rawcb.rcb_next = rawcb.rcb_prev = &rawcb; 426211Swnj rawintrq.ifq_maxlen = IFQ_MAXLEN; 435612Swnj } 445612Swnj 455612Swnj /* 465121Swnj * Raw protocol interface. 475121Swnj */ 486529Ssam raw_input(m0, proto, src, dst) 495612Swnj struct mbuf *m0; 506509Ssam struct sockproto *proto; 516529Ssam struct sockaddr *src, *dst; 525121Swnj { 535612Swnj register struct mbuf *m; 545612Swnj struct raw_header *rh; 555121Swnj int s; 565121Swnj 575612Swnj /* 585612Swnj * Rip off an mbuf for a generic header. 595612Swnj */ 609638Ssam m = m_get(M_DONTWAIT, MT_HEADER); 615612Swnj if (m == 0) { 625612Swnj m_freem(m0); 635612Swnj return; 645612Swnj } 655612Swnj m->m_next = m0; 665612Swnj m->m_len = sizeof(struct raw_header); 675612Swnj rh = mtod(m, struct raw_header *); 686509Ssam rh->raw_dst = *dst; 696509Ssam rh->raw_src = *src; 706509Ssam rh->raw_proto = *proto; 715612Swnj 725612Swnj /* 735612Swnj * Header now contains enough info to decide 745612Swnj * which socket to place packet in (if any). 755612Swnj * Queue it up for the raw protocol process 765612Swnj * running at software interrupt level. 775612Swnj */ 785121Swnj s = splimp(); 796211Swnj if (IF_QFULL(&rawintrq)) 806211Swnj m_freem(m); 816211Swnj else 826211Swnj IF_ENQUEUE(&rawintrq, m); 835121Swnj splx(s); 846263Swnj schednetisr(NETISR_RAW); 855121Swnj } 865121Swnj 875612Swnj /* 885612Swnj * Raw protocol input routine. Process packets entered 895612Swnj * into the queue at interrupt time. Find the socket 905612Swnj * associated with the packet(s) and move them over. If 915612Swnj * nothing exists for this packet, drop it. 925612Swnj */ 935121Swnj rawintr() 945121Swnj { 955121Swnj int s; 965121Swnj struct mbuf *m; 975612Swnj register struct rawcb *rp; 986529Ssam register struct raw_header *rh; 995612Swnj struct socket *last; 1005121Swnj 1015121Swnj next: 1025121Swnj s = splimp(); 1035121Swnj IF_DEQUEUE(&rawintrq, m); 1045121Swnj splx(s); 1055121Swnj if (m == 0) 1065121Swnj return; 1076509Ssam rh = mtod(m, struct raw_header *); 1085612Swnj last = 0; 1095612Swnj for (rp = rawcb.rcb_next; rp != &rawcb; rp = rp->rcb_next) { 11021769Skarels if (rp->rcb_proto.sp_family != rh->raw_proto.sp_family) 1115612Swnj continue; 11221769Skarels if (rp->rcb_proto.sp_protocol && 11321769Skarels rp->rcb_proto.sp_protocol != rh->raw_proto.sp_protocol) 1145612Swnj continue; 1155612Swnj /* 1165612Swnj * We assume the lower level routines have 1175612Swnj * placed the address in a canonical format 1186509Ssam * suitable for a structure comparison. 1195612Swnj */ 1206529Ssam #define equal(a1, a2) \ 1216529Ssam (bcmp((caddr_t)&(a1), (caddr_t)&(a2), sizeof (struct sockaddr)) == 0) 1226509Ssam if ((rp->rcb_flags & RAW_LADDR) && 1236529Ssam !equal(rp->rcb_laddr, rh->raw_dst)) 1245612Swnj continue; 1256509Ssam if ((rp->rcb_flags & RAW_FADDR) && 1266529Ssam !equal(rp->rcb_faddr, rh->raw_src)) 1276509Ssam continue; 1285612Swnj if (last) { 1295612Swnj struct mbuf *n; 13021531Skarels if (n = m_copy(m->m_next, 0, (int)M_COPYALL)) { 13121531Skarels if (sbappendaddr(&last->so_rcv, &rh->raw_src, 13221531Skarels n, (struct mbuf *)0) == 0) 13321531Skarels /* should notify about lost packet */ 13421531Skarels m_freem(n); 13521531Skarels else 13621531Skarels sorwakeup(last); 1375646Ssam } 1385612Swnj } 1396509Ssam last = rp->rcb_socket; 1405612Swnj } 1416584Ssam if (last) { 14212783Ssam if (sbappendaddr(&last->so_rcv, &rh->raw_src, 14321531Skarels m->m_next, (struct mbuf *)0) == 0) 14421531Skarels m_freem(m->m_next); 14521531Skarels else 14621531Skarels sorwakeup(last); 14721531Skarels (void) m_free(m); /* header */ 14821531Skarels } else 14921531Skarels m_freem(m); 1505121Swnj goto next; 1515121Swnj } 1525121Swnj 1538636Sroot /*ARGSUSED*/ 1546584Ssam raw_ctlinput(cmd, arg) 1556584Ssam int cmd; 15626379Skarels struct sockaddr *arg; 1576584Ssam { 1586591Ssam 1596591Ssam if (cmd < 0 || cmd > PRC_NCMDS) 1606591Ssam return; 1618636Sroot /* INCOMPLETE */ 1626584Ssam } 1636584Ssam 1645121Swnj /*ARGSUSED*/ 16512783Ssam raw_usrreq(so, req, m, nam, rights) 1665121Swnj struct socket *so; 1675121Swnj int req; 16812783Ssam struct mbuf *m, *nam, *rights; 1695121Swnj { 1705612Swnj register struct rawcb *rp = sotorawcb(so); 17112783Ssam register int error = 0; 1725121Swnj 17325501Skarels if (req == PRU_CONTROL) 17425501Skarels return (EOPNOTSUPP); 17512783Ssam if (rights && rights->m_len) { 17612783Ssam error = EOPNOTSUPP; 17712783Ssam goto release; 17812783Ssam } 17912783Ssam if (rp == 0 && req != PRU_ATTACH) { 18012783Ssam error = EINVAL; 18112783Ssam goto release; 18212783Ssam } 1835612Swnj switch (req) { 1845612Swnj 1855612Swnj /* 1865612Swnj * Allocate a raw control block and fill in the 1875612Swnj * necessary info to allow packets to be routed to 1885612Swnj * the appropriate raw interface routine. 1895612Swnj */ 1905612Swnj case PRU_ATTACH: 19112783Ssam if ((so->so_state & SS_PRIV) == 0) { 19212783Ssam error = EACCES; 19313116Ssam break; 19412783Ssam } 19512783Ssam if (rp) { 19612783Ssam error = EINVAL; 19713116Ssam break; 19812783Ssam } 19921769Skarels error = raw_attach(so, (int)nam); 2005612Swnj break; 2015612Swnj 2025612Swnj /* 2035612Swnj * Destroy state just before socket deallocation. 2045612Swnj * Flush data or not depending on the options. 2055612Swnj */ 2065612Swnj case PRU_DETACH: 20712783Ssam if (rp == 0) { 20812783Ssam error = ENOTCONN; 20913116Ssam break; 21012783Ssam } 2115612Swnj raw_detach(rp); 2125612Swnj break; 2135612Swnj 2145612Swnj /* 2155612Swnj * If a socket isn't bound to a single address, 2165612Swnj * the raw input routine will hand it anything 2175612Swnj * within that protocol family (assuming there's 2185612Swnj * nothing else around it should go to). 2195612Swnj */ 2205612Swnj case PRU_CONNECT: 22112783Ssam if (rp->rcb_flags & RAW_FADDR) { 22212783Ssam error = EISCONN; 22313116Ssam break; 22412783Ssam } 2258395Swnj raw_connaddr(rp, nam); 2265612Swnj soisconnected(so); 2275612Swnj break; 2285612Swnj 22913116Ssam case PRU_CONNECT2: 23013116Ssam error = EOPNOTSUPP; 23113116Ssam goto release; 23213116Ssam 23312783Ssam case PRU_BIND: 23412783Ssam if (rp->rcb_flags & RAW_LADDR) { 23512783Ssam error = EINVAL; /* XXX */ 23613116Ssam break; 23712783Ssam } 23812783Ssam error = raw_bind(so, nam); 23912783Ssam break; 24012783Ssam 2415612Swnj case PRU_DISCONNECT: 24212783Ssam if ((rp->rcb_flags & RAW_FADDR) == 0) { 24312783Ssam error = ENOTCONN; 24413116Ssam break; 24512783Ssam } 2465612Swnj raw_disconnect(rp); 2475612Swnj soisdisconnected(so); 2485612Swnj break; 2495612Swnj 2505612Swnj /* 2515612Swnj * Mark the connection as being incapable of further input. 2525612Swnj */ 2535612Swnj case PRU_SHUTDOWN: 2545612Swnj socantsendmore(so); 2555612Swnj break; 2565612Swnj 2575612Swnj /* 2585612Swnj * Ship a packet out. The appropriate raw output 2595612Swnj * routine handles any massaging necessary. 2605612Swnj */ 2615612Swnj case PRU_SEND: 2628395Swnj if (nam) { 26312783Ssam if (rp->rcb_flags & RAW_FADDR) { 26412783Ssam error = EISCONN; 26513116Ssam break; 26612783Ssam } 2678395Swnj raw_connaddr(rp, nam); 26812783Ssam } else if ((rp->rcb_flags & RAW_FADDR) == 0) { 26912783Ssam error = ENOTCONN; 27013116Ssam break; 27112783Ssam } 2726505Ssam error = (*so->so_proto->pr_output)(m, so); 27312783Ssam m = NULL; 2748395Swnj if (nam) 2756509Ssam rp->rcb_flags &= ~RAW_FADDR; 2765612Swnj break; 2775612Swnj 2785612Swnj case PRU_ABORT: 2795612Swnj raw_disconnect(rp); 2805612Swnj sofree(so); 2815612Swnj soisdisconnected(so); 2825612Swnj break; 2835612Swnj 28416974Skarels case PRU_SENSE: 28516974Skarels /* 28616974Skarels * stat: don't bother with a blocksize. 28716974Skarels */ 28816974Skarels return (0); 28916974Skarels 2905612Swnj /* 2915612Swnj * Not supported. 2925612Swnj */ 29316773Sbloom case PRU_RCVOOB: 2945612Swnj case PRU_RCVD: 29516773Sbloom return(EOPNOTSUPP); 29616773Sbloom 29725221Skarels case PRU_LISTEN: 29816773Sbloom case PRU_ACCEPT: 2995612Swnj case PRU_SENDOOB: 3005612Swnj error = EOPNOTSUPP; 3015612Swnj break; 3025612Swnj 3036509Ssam case PRU_SOCKADDR: 3048723Sroot bcopy((caddr_t)&rp->rcb_laddr, mtod(nam, caddr_t), 3058395Swnj sizeof (struct sockaddr)); 3068395Swnj nam->m_len = sizeof (struct sockaddr); 3076509Ssam break; 3086509Ssam 30914122Ssam case PRU_PEERADDR: 31014122Ssam bcopy((caddr_t)&rp->rcb_faddr, mtod(nam, caddr_t), 31114122Ssam sizeof (struct sockaddr)); 31214122Ssam nam->m_len = sizeof (struct sockaddr); 31314122Ssam break; 31414122Ssam 3155612Swnj default: 3165612Swnj panic("raw_usrreq"); 3175612Swnj } 31812783Ssam release: 31912783Ssam if (m != NULL) 32012783Ssam m_freem(m); 3215612Swnj return (error); 3225121Swnj } 323