123186Smckusick /* 237322Skarels * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 332787Sbostic * All rights reserved. 423186Smckusick * 5*44482Sbostic * %sccs.include.redist.c% 632787Sbostic * 7*44482Sbostic * @(#)raw_ip.c 7.7 (Berkeley) 06/28/90 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" 1710894Ssam 186509Ssam #include "../net/if.h" 1913455Ssam #include "../net/route.h" 2010894Ssam #include "../net/raw_cb.h" 2110894Ssam 2217062Sbloom #include "in.h" 2317062Sbloom #include "in_systm.h" 2417062Sbloom #include "ip.h" 2517062Sbloom #include "ip_var.h" 2637322Skarels #include "in_pcb.h" 275123Swnj 285123Swnj /* 295612Swnj * Raw interface to IP protocol. 305123Swnj */ 315612Swnj 3237322Skarels struct sockaddr_in ripdst = { sizeof(ripdst), AF_INET }; 3337322Skarels struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 3413455Ssam struct sockproto ripproto = { PF_INET }; 355612Swnj /* 365612Swnj * Setup generic address and protocol structures 375612Swnj * for raw_input routine, then pass them along with 385612Swnj * mbuf chain. 395612Swnj */ 405123Swnj rip_input(m) 415123Swnj struct mbuf *m; 425123Swnj { 435612Swnj register struct ip *ip = mtod(m, struct ip *); 445123Swnj 455612Swnj ripproto.sp_protocol = ip->ip_p; 465646Ssam ripdst.sin_addr = ip->ip_dst; 475646Ssam ripsrc.sin_addr = ip->ip_src; 4839184Ssklower if (raw_input(m, &ripproto, (struct sockaddr *)&ripsrc, 4939184Ssklower (struct sockaddr *)&ripdst) == 0) { 5039184Ssklower ipstat.ips_noproto++; 5139184Ssklower ipstat.ips_delivered--; 5239184Ssklower } 535123Swnj } 545123Swnj 555612Swnj /* 565612Swnj * Generate IP header and pass packet to ip_output. 575612Swnj * Tack on options user may have setup with control call. 585612Swnj */ 5937322Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 6037322Skarels rip_output(m, so) 6137322Skarels register struct mbuf *m; 625612Swnj struct socket *so; 635123Swnj { 645612Swnj register struct ip *ip; 6537322Skarels register struct raw_inpcb *rp = sotorawinpcb(so); 6637322Skarels register struct sockaddr_in *sin; 675123Swnj 685612Swnj /* 6937322Skarels * If the user handed us a complete IP packet, use it. 7037322Skarels * Otherwise, allocate an mbuf for a header and fill it in. 715612Swnj */ 7237322Skarels if (rp->rinp_flags & RINPF_HDRINCL) 7337322Skarels ip = mtod(m, struct ip *); 7437322Skarels else { 7537322Skarels M_PREPEND(m, sizeof(struct ip), M_WAIT); 7637322Skarels ip = mtod(m, struct ip *); 7737322Skarels ip->ip_tos = 0; 7837322Skarels ip->ip_off = 0; 7937322Skarels ip->ip_p = rp->rinp_rcb.rcb_proto.sp_protocol; 8037322Skarels ip->ip_len = m->m_pkthdr.len; 8137322Skarels if (sin = satosin(rp->rinp_rcb.rcb_laddr)) { 8237322Skarels ip->ip_src = sin->sin_addr; 8337322Skarels } else 8437322Skarels ip->ip_src.s_addr = 0; 8537322Skarels if (sin = satosin(rp->rinp_rcb.rcb_faddr)) 8637322Skarels ip->ip_dst = sin->sin_addr; 8737322Skarels ip->ip_ttl = MAXTTL; 885612Swnj } 8937322Skarels return (ip_output(m, 9037322Skarels (rp->rinp_flags & RINPF_HDRINCL)? (struct mbuf *)0: rp->rinp_options, 9137322Skarels &rp->rinp_route, 9226037Skarels (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST)); 935123Swnj } 9426037Skarels 9526037Skarels /* 9626037Skarels * Raw IP socket option processing. 9726037Skarels */ 9826037Skarels rip_ctloutput(op, so, level, optname, m) 9926037Skarels int op; 10026037Skarels struct socket *so; 10126037Skarels int level, optname; 10226037Skarels struct mbuf **m; 10326037Skarels { 10426037Skarels int error = 0; 10537322Skarels register struct raw_inpcb *rp = sotorawinpcb(so); 10626037Skarels 10726037Skarels if (level != IPPROTO_IP) 10826037Skarels error = EINVAL; 10926037Skarels else switch (op) { 11026037Skarels 11126037Skarels case PRCO_SETOPT: 11226037Skarels switch (optname) { 11337322Skarels 11426037Skarels case IP_OPTIONS: 11537322Skarels return (ip_pcbopts(&rp->rinp_options, *m)); 11626037Skarels 11737322Skarels case IP_HDRINCL: 11837322Skarels if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) { 11937322Skarels error = EINVAL; 12037322Skarels break; 12137322Skarels } 12237322Skarels if (*mtod(*m, int *)) 12337322Skarels rp->rinp_flags |= RINPF_HDRINCL; 12437322Skarels else 12537322Skarels rp->rinp_flags &= ~RINPF_HDRINCL; 12637322Skarels break; 12737322Skarels 12826037Skarels default: 12926037Skarels error = EINVAL; 13026037Skarels break; 13126037Skarels } 13226037Skarels break; 13326037Skarels 13426037Skarels case PRCO_GETOPT: 13537322Skarels *m = m_get(M_WAIT, MT_SOOPTS); 13626037Skarels switch (optname) { 13737322Skarels 13826037Skarels case IP_OPTIONS: 13937322Skarels if (rp->rinp_options) { 14037322Skarels (*m)->m_len = rp->rinp_options->m_len; 14137322Skarels bcopy(mtod(rp->rinp_options, caddr_t), 14226386Skarels mtod(*m, caddr_t), (unsigned)(*m)->m_len); 14326037Skarels } else 14426037Skarels (*m)->m_len = 0; 14526037Skarels break; 14637322Skarels 14737322Skarels case IP_HDRINCL: 14837322Skarels (*m)->m_len = sizeof (int); 14937322Skarels *mtod(*m, int *) = rp->rinp_flags & RINPF_HDRINCL; 15037322Skarels break; 15137322Skarels 15226037Skarels default: 15326037Skarels error = EINVAL; 15437322Skarels m_freem(*m); 15537322Skarels *m = 0; 15626037Skarels break; 15726037Skarels } 15826037Skarels break; 15926037Skarels } 16031649Smckusick if (op == PRCO_SETOPT && *m) 16126386Skarels (void)m_free(*m); 16226037Skarels return (error); 16326037Skarels } 16437322Skarels 16537322Skarels /*ARGSUSED*/ 16637322Skarels rip_usrreq(so, req, m, nam, rights, control) 16737322Skarels register struct socket *so; 16837322Skarels int req; 16937322Skarels struct mbuf *m, *nam, *rights, *control; 17037322Skarels { 17137322Skarels register int error = 0; 17237322Skarels register struct raw_inpcb *rp = sotorawinpcb(so); 17337322Skarels 17437322Skarels switch (req) { 17537322Skarels 17637322Skarels case PRU_ATTACH: 17737322Skarels if (rp) 17837322Skarels panic("rip_attach"); 17937322Skarels MALLOC(rp, struct raw_inpcb *, sizeof *rp, M_PCB, M_WAITOK); 18037322Skarels if (rp == 0) 18137322Skarels return (ENOBUFS); 18237322Skarels bzero((caddr_t)rp, sizeof *rp); 18337322Skarels so->so_pcb = (caddr_t)rp; 18437322Skarels break; 18537322Skarels 18637322Skarels case PRU_DETACH: 18737322Skarels if (rp == 0) 18837322Skarels panic("rip_detach"); 18937322Skarels if (rp->rinp_options) 19037322Skarels m_freem(rp->rinp_options); 19137322Skarels if (rp->rinp_route.ro_rt) 19237322Skarels RTFREE(rp->rinp_route.ro_rt); 19337322Skarels if (rp->rinp_rcb.rcb_laddr) 19437322Skarels rp->rinp_rcb.rcb_laddr = 0; 19537322Skarels break; 19637322Skarels 19737322Skarels case PRU_BIND: 19837322Skarels { 19937322Skarels struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 20037322Skarels 20137322Skarels if (nam->m_len != sizeof(*addr)) 20237322Skarels return (EINVAL); 20337322Skarels if ((ifnet == 0) || 20437322Skarels ((addr->sin_family != AF_INET) && 20537322Skarels (addr->sin_family != AF_IMPLINK)) || 20637322Skarels (addr->sin_addr.s_addr && 20737322Skarels ifa_ifwithaddr((struct sockaddr *)addr) == 0)) 20837322Skarels return (EADDRNOTAVAIL); 20937322Skarels rp->rinp_rcb.rcb_laddr = (struct sockaddr *)&rp->rinp_laddr; 21037322Skarels rp->rinp_laddr = *addr; 21137322Skarels return (0); 21237322Skarels } 21337322Skarels case PRU_CONNECT: 21437322Skarels { 21537322Skarels struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 21637322Skarels 21737322Skarels if (nam->m_len != sizeof(*addr)) 21837322Skarels return (EINVAL); 21937322Skarels if (ifnet == 0) 22037322Skarels return (EADDRNOTAVAIL); 22137322Skarels if ((addr->sin_family != AF_INET) && 22237322Skarels (addr->sin_family != AF_IMPLINK)) 22337322Skarels return (EAFNOSUPPORT); 22437322Skarels rp->rinp_rcb.rcb_faddr = (struct sockaddr *)&rp->rinp_faddr; 22537322Skarels rp->rinp_laddr = *addr; 22637322Skarels soisconnected(so); 22737322Skarels return (0); 22837322Skarels } 22937322Skarels } 23037322Skarels error = raw_usrreq(so, req, m, nam, rights, control); 23137322Skarels 23237322Skarels if (error && (req == PRU_ATTACH) && so->so_pcb) 23337322Skarels free(so->so_pcb, M_PCB); 23437322Skarels return (error); 23537322Skarels } 236