123186Smckusick /* 237322Skarels * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 332787Sbostic * All rights reserved. 423186Smckusick * 544482Sbostic * %sccs.include.redist.c% 632787Sbostic * 7*54716Ssklower * @(#)raw_ip.c 7.9 (Berkeley) 07/06/92 823186Smckusick */ 95123Swnj 1017062Sbloom #include "param.h" 1137322Skarels #include "malloc.h" 1217062Sbloom #include "mbuf.h" 1317062Sbloom #include "socket.h" 1417062Sbloom #include "protosw.h" 1517062Sbloom #include "socketvar.h" 1617062Sbloom #include "errno.h" 17*54716Ssklower #include "systm.h" 1810894Ssam 196509Ssam #include "../net/if.h" 2013455Ssam #include "../net/route.h" 2110894Ssam 2217062Sbloom #include "in.h" 2317062Sbloom #include "in_systm.h" 2417062Sbloom #include "ip.h" 2517062Sbloom #include "ip_var.h" 26*54716Ssklower #include "ip_mroute.h" 2737322Skarels #include "in_pcb.h" 285123Swnj 29*54716Ssklower struct inpcb rawinpcb; 30*54716Ssklower 315123Swnj /* 32*54716Ssklower * Nominal space allocated to a raw ip socket. 33*54716Ssklower */ 34*54716Ssklower #define RIPSNDQ 8192 35*54716Ssklower #define RIPRCVQ 8192 36*54716Ssklower 37*54716Ssklower /* 385612Swnj * Raw interface to IP protocol. 395123Swnj */ 405612Swnj 41*54716Ssklower /* 42*54716Ssklower * Initialize raw connection block q. 43*54716Ssklower */ 44*54716Ssklower rip_init() 45*54716Ssklower { 46*54716Ssklower 47*54716Ssklower rawinpcb.inp_next = rawinpcb.inp_prev = &rawinpcb; 48*54716Ssklower } 49*54716Ssklower 5037322Skarels struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 515612Swnj /* 525612Swnj * Setup generic address and protocol structures 535612Swnj * for raw_input routine, then pass them along with 545612Swnj * mbuf chain. 555612Swnj */ 565123Swnj rip_input(m) 575123Swnj struct mbuf *m; 585123Swnj { 595612Swnj register struct ip *ip = mtod(m, struct ip *); 60*54716Ssklower register struct inpcb *inp; 61*54716Ssklower struct socket *last = 0; 625123Swnj 635646Ssam ripsrc.sin_addr = ip->ip_src; 64*54716Ssklower for (inp = rawinpcb.inp_next; inp != &rawinpcb; inp = inp->inp_next) { 65*54716Ssklower if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p) 66*54716Ssklower continue; 67*54716Ssklower if (inp->inp_laddr.s_addr && 68*54716Ssklower inp->inp_laddr.s_addr == ip->ip_dst.s_addr) 69*54716Ssklower continue; 70*54716Ssklower if (inp->inp_faddr.s_addr && 71*54716Ssklower inp->inp_faddr.s_addr == ip->ip_src.s_addr) 72*54716Ssklower continue; 73*54716Ssklower if (last) { 74*54716Ssklower struct mbuf *n; 75*54716Ssklower if (n = m_copy(m, 0, (int)M_COPYALL)) { 76*54716Ssklower if (sbappendaddr(&last->so_rcv, &ripsrc, 77*54716Ssklower n, (struct mbuf *)0) == 0) 78*54716Ssklower /* should notify about lost packet */ 79*54716Ssklower m_freem(n); 80*54716Ssklower else 81*54716Ssklower sorwakeup(last); 82*54716Ssklower } 83*54716Ssklower } 84*54716Ssklower last = inp->inp_socket; 85*54716Ssklower } 86*54716Ssklower if (last) { 87*54716Ssklower if (sbappendaddr(&last->so_rcv, &ripsrc, 88*54716Ssklower m, (struct mbuf *)0) == 0) 89*54716Ssklower m_freem(m); 90*54716Ssklower else 91*54716Ssklower sorwakeup(last); 92*54716Ssklower } else { 93*54716Ssklower m_freem(m); 9439184Ssklower ipstat.ips_noproto++; 9539184Ssklower ipstat.ips_delivered--; 9639184Ssklower } 975123Swnj } 985123Swnj 995612Swnj /* 1005612Swnj * Generate IP header and pass packet to ip_output. 1015612Swnj * Tack on options user may have setup with control call. 1025612Swnj */ 103*54716Ssklower rip_output(m, so, dst) 10437322Skarels register struct mbuf *m; 1055612Swnj struct socket *so; 106*54716Ssklower u_long dst; 1075123Swnj { 1085612Swnj register struct ip *ip; 109*54716Ssklower register struct inpcb *inp = sotoinpcb(so); 11037322Skarels register struct sockaddr_in *sin; 1115123Swnj 1125612Swnj /* 11337322Skarels * If the user handed us a complete IP packet, use it. 11437322Skarels * Otherwise, allocate an mbuf for a header and fill it in. 1155612Swnj */ 116*54716Ssklower if ((inp->inp_flags & INP_HDRINCL) == 0) { 11737322Skarels M_PREPEND(m, sizeof(struct ip), M_WAIT); 11837322Skarels ip = mtod(m, struct ip *); 11937322Skarels ip->ip_tos = 0; 12037322Skarels ip->ip_off = 0; 121*54716Ssklower ip->ip_p = inp->inp_ip.ip_p; 12237322Skarels ip->ip_len = m->m_pkthdr.len; 123*54716Ssklower ip->ip_src = inp->inp_laddr; 124*54716Ssklower ip->ip_dst.s_addr = dst; 12537322Skarels ip->ip_ttl = MAXTTL; 1265612Swnj } 12737322Skarels return (ip_output(m, 128*54716Ssklower (inp->inp_flags & INP_HDRINCL)? (struct mbuf *)0: inp->inp_options, 129*54716Ssklower &inp->inp_route, 130*54716Ssklower (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST 131*54716Ssklower #ifdef MULTICAST 132*54716Ssklower , inp->inp_moptions 133*54716Ssklower #endif 134*54716Ssklower )); 1355123Swnj } 13626037Skarels 13726037Skarels /* 13826037Skarels * Raw IP socket option processing. 13926037Skarels */ 14026037Skarels rip_ctloutput(op, so, level, optname, m) 14126037Skarels int op; 14226037Skarels struct socket *so; 14326037Skarels int level, optname; 14426037Skarels struct mbuf **m; 14526037Skarels { 146*54716Ssklower register struct inpcb *inp = sotoinpcb(so); 147*54716Ssklower register int error; 14826037Skarels 14926037Skarels if (level != IPPROTO_IP) 150*54716Ssklower return (EINVAL); 15126037Skarels 152*54716Ssklower switch (optname) { 15337322Skarels 154*54716Ssklower case IP_HDRINCL: 155*54716Ssklower if (op == PRCO_SETOPT || op == PRCO_GETOPT) { 156*54716Ssklower if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) 157*54716Ssklower return (EINVAL); 158*54716Ssklower if (op == PRCO_SETOPT) { 159*54716Ssklower if (*mtod(*m, int *)) 160*54716Ssklower inp->inp_flags |= INP_HDRINCL; 161*54716Ssklower else 162*54716Ssklower inp->inp_flags &= ~INP_HDRINCL; 163*54716Ssklower (void)m_free(*m); 164*54716Ssklower } else { 165*54716Ssklower (*m)->m_len = sizeof (int); 166*54716Ssklower *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; 16737322Skarels } 168*54716Ssklower return (0); 16926037Skarels } 17026037Skarels break; 17126037Skarels 172*54716Ssklower case DVMRP_INIT: 173*54716Ssklower case DVMRP_DONE: 174*54716Ssklower case DVMRP_ADD_VIF: 175*54716Ssklower case DVMRP_DEL_VIF: 176*54716Ssklower case DVMRP_ADD_LGRP: 177*54716Ssklower case DVMRP_DEL_LGRP: 178*54716Ssklower case DVMRP_ADD_MRT: 179*54716Ssklower case DVMRP_DEL_MRT: 180*54716Ssklower #ifdef MROUTING 181*54716Ssklower if (op == PRCO_SETOPT) { 182*54716Ssklower error = ip_mrouter_cmd(optname, so, *m); 183*54716Ssklower if (*m) 184*54716Ssklower (void)m_free(*m); 185*54716Ssklower } else 18626037Skarels error = EINVAL; 187*54716Ssklower return (error); 188*54716Ssklower #else 189*54716Ssklower if (op == PRCO_SETOPT && *m) 190*54716Ssklower (void)m_free(*m); 191*54716Ssklower return (EOPNOTSUPP); 192*54716Ssklower #endif 19326037Skarels } 194*54716Ssklower return (ip_ctloutput(op, so, level, optname, m)); 19526037Skarels } 19637322Skarels 197*54716Ssklower u_long rip_sendspace = RIPSNDQ; 198*54716Ssklower u_long rip_recvspace = RIPRCVQ; 199*54716Ssklower 20037322Skarels /*ARGSUSED*/ 201*54716Ssklower rip_usrreq(so, req, m, nam, control) 20237322Skarels register struct socket *so; 20337322Skarels int req; 204*54716Ssklower struct mbuf *m, *nam, *control; 20537322Skarels { 20637322Skarels register int error = 0; 207*54716Ssklower register struct inpcb *inp = sotoinpcb(so); 208*54716Ssklower #if defined(MULTICAST) && defined(MROUTING) 209*54716Ssklower extern struct socket *ip_mrouter; 210*54716Ssklower #endif 21137322Skarels 21237322Skarels switch (req) { 21337322Skarels 21437322Skarels case PRU_ATTACH: 215*54716Ssklower if (inp) 21637322Skarels panic("rip_attach"); 217*54716Ssklower if ((so->so_state & SS_PRIV) == 0) { 218*54716Ssklower error = EACCES; 219*54716Ssklower break; 220*54716Ssklower } 221*54716Ssklower if ((error = soreserve(so, rip_sendspace, rip_recvspace)) || 222*54716Ssklower (error = in_pcballoc(so, &rawinpcb))) 223*54716Ssklower break; 224*54716Ssklower inp = (struct inpcb *)so->so_pcb; 225*54716Ssklower inp->inp_ip.ip_p = (int)nam; 22637322Skarels break; 22737322Skarels 228*54716Ssklower case PRU_DISCONNECT: 229*54716Ssklower if ((so->so_state & SS_ISCONNECTED) == 0) { 230*54716Ssklower error = ENOTCONN; 231*54716Ssklower break; 232*54716Ssklower } 233*54716Ssklower /* FALLTHROUGH */ 234*54716Ssklower case PRU_ABORT: 235*54716Ssklower soisdisconnected(so); 236*54716Ssklower /* FALLTHROUGH */ 23737322Skarels case PRU_DETACH: 238*54716Ssklower if (inp == 0) 23937322Skarels panic("rip_detach"); 240*54716Ssklower #if defined(MULTICAST) && defined(MROUTING) 241*54716Ssklower if (so == ip_mrouter) 242*54716Ssklower ip_mrouter_done(); 243*54716Ssklower #endif 244*54716Ssklower in_pcbdetach(inp); 24537322Skarels break; 24637322Skarels 24737322Skarels case PRU_BIND: 24837322Skarels { 24937322Skarels struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 25037322Skarels 251*54716Ssklower if (nam->m_len != sizeof(*addr)) { 252*54716Ssklower error = EINVAL; 253*54716Ssklower break; 254*54716Ssklower } 25537322Skarels if ((ifnet == 0) || 25637322Skarels ((addr->sin_family != AF_INET) && 25737322Skarels (addr->sin_family != AF_IMPLINK)) || 25837322Skarels (addr->sin_addr.s_addr && 259*54716Ssklower ifa_ifwithaddr((struct sockaddr *)addr) == 0)) { 260*54716Ssklower error = EADDRNOTAVAIL; 261*54716Ssklower break; 262*54716Ssklower } 263*54716Ssklower inp->inp_laddr = addr->sin_addr; 264*54716Ssklower break; 26537322Skarels } 26637322Skarels case PRU_CONNECT: 26737322Skarels { 26837322Skarels struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 26937322Skarels 270*54716Ssklower if (nam->m_len != sizeof(*addr)) { 271*54716Ssklower error = EINVAL; 272*54716Ssklower break; 273*54716Ssklower } 274*54716Ssklower if (ifnet == 0) { 275*54716Ssklower error = EADDRNOTAVAIL; 276*54716Ssklower break; 277*54716Ssklower } 27837322Skarels if ((addr->sin_family != AF_INET) && 279*54716Ssklower (addr->sin_family != AF_IMPLINK)) { 280*54716Ssklower error = EAFNOSUPPORT; 281*54716Ssklower break; 282*54716Ssklower } 283*54716Ssklower inp->inp_faddr = addr->sin_addr; 28437322Skarels soisconnected(so); 285*54716Ssklower break; 286*54716Ssklower } 287*54716Ssklower 288*54716Ssklower case PRU_CONNECT2: 289*54716Ssklower error = EOPNOTSUPP; 290*54716Ssklower break; 291*54716Ssklower 292*54716Ssklower /* 293*54716Ssklower * Mark the connection as being incapable of further input. 294*54716Ssklower */ 295*54716Ssklower case PRU_SHUTDOWN: 296*54716Ssklower socantsendmore(so); 297*54716Ssklower break; 298*54716Ssklower 299*54716Ssklower /* 300*54716Ssklower * Ship a packet out. The appropriate raw output 301*54716Ssklower * routine handles any massaging necessary. 302*54716Ssklower */ 303*54716Ssklower case PRU_SEND: 304*54716Ssklower { 305*54716Ssklower register u_long dst; 306*54716Ssklower 307*54716Ssklower if (so->so_state & SS_ISCONNECTED) { 308*54716Ssklower if (nam) { 309*54716Ssklower error = EISCONN; 310*54716Ssklower break; 311*54716Ssklower } 312*54716Ssklower dst = inp->inp_faddr.s_addr; 313*54716Ssklower } else { 314*54716Ssklower if (nam == NULL) { 315*54716Ssklower error = ENOTCONN; 316*54716Ssklower break; 317*54716Ssklower } 318*54716Ssklower dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; 319*54716Ssklower } 320*54716Ssklower error = rip_output(m, so, dst); 321*54716Ssklower m = NULL; 322*54716Ssklower break; 323*54716Ssklower } 324*54716Ssklower 325*54716Ssklower case PRU_SENSE: 326*54716Ssklower /* 327*54716Ssklower * stat: don't bother with a blocksize. 328*54716Ssklower */ 32937322Skarels return (0); 330*54716Ssklower 331*54716Ssklower /* 332*54716Ssklower * Not supported. 333*54716Ssklower */ 334*54716Ssklower case PRU_RCVOOB: 335*54716Ssklower case PRU_RCVD: 336*54716Ssklower case PRU_LISTEN: 337*54716Ssklower case PRU_ACCEPT: 338*54716Ssklower case PRU_SENDOOB: 339*54716Ssklower error = EOPNOTSUPP; 340*54716Ssklower break; 341*54716Ssklower 342*54716Ssklower case PRU_SOCKADDR: 343*54716Ssklower in_setsockaddr(inp, nam); 344*54716Ssklower break; 345*54716Ssklower 346*54716Ssklower case PRU_PEERADDR: 347*54716Ssklower in_setpeeraddr(inp, nam); 348*54716Ssklower break; 349*54716Ssklower 350*54716Ssklower default: 351*54716Ssklower panic("rip_usrreq"); 35237322Skarels } 353*54716Ssklower if (m != NULL) 354*54716Ssklower m_freem(m); 35537322Skarels return (error); 35637322Skarels } 357