123186Smckusick /* 237322Skarels * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 332787Sbostic * All rights reserved. 423186Smckusick * 532787Sbostic * Redistribution and use in source and binary forms are permitted 634854Sbostic * provided that the above copyright notice and this paragraph are 734854Sbostic * duplicated in all such forms and that any documentation, 834854Sbostic * advertising materials, and other materials related to such 934854Sbostic * distribution and use acknowledge that the software was developed 1034854Sbostic * by the University of California, Berkeley. The name of the 1134854Sbostic * University may not be used to endorse or promote products derived 1234854Sbostic * from this software without specific prior written permission. 1334854Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434854Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534854Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1632787Sbostic * 17*39184Ssklower * @(#)raw_ip.c 7.6 (Berkeley) 09/20/89 1823186Smckusick */ 195123Swnj 2017062Sbloom #include "param.h" 2137322Skarels #include "malloc.h" 2217062Sbloom #include "mbuf.h" 2317062Sbloom #include "socket.h" 2417062Sbloom #include "protosw.h" 2517062Sbloom #include "socketvar.h" 2617062Sbloom #include "errno.h" 2710894Ssam 286509Ssam #include "../net/if.h" 2913455Ssam #include "../net/route.h" 3010894Ssam #include "../net/raw_cb.h" 3110894Ssam 3217062Sbloom #include "in.h" 3317062Sbloom #include "in_systm.h" 3417062Sbloom #include "ip.h" 3517062Sbloom #include "ip_var.h" 3637322Skarels #include "in_pcb.h" 375123Swnj 385123Swnj /* 395612Swnj * Raw interface to IP protocol. 405123Swnj */ 415612Swnj 4237322Skarels struct sockaddr_in ripdst = { sizeof(ripdst), AF_INET }; 4337322Skarels struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 4413455Ssam struct sockproto ripproto = { PF_INET }; 455612Swnj /* 465612Swnj * Setup generic address and protocol structures 475612Swnj * for raw_input routine, then pass them along with 485612Swnj * mbuf chain. 495612Swnj */ 505123Swnj rip_input(m) 515123Swnj struct mbuf *m; 525123Swnj { 535612Swnj register struct ip *ip = mtod(m, struct ip *); 545123Swnj 555612Swnj ripproto.sp_protocol = ip->ip_p; 565646Ssam ripdst.sin_addr = ip->ip_dst; 575646Ssam ripsrc.sin_addr = ip->ip_src; 58*39184Ssklower if (raw_input(m, &ripproto, (struct sockaddr *)&ripsrc, 59*39184Ssklower (struct sockaddr *)&ripdst) == 0) { 60*39184Ssklower ipstat.ips_noproto++; 61*39184Ssklower ipstat.ips_delivered--; 62*39184Ssklower } 635123Swnj } 645123Swnj 655612Swnj /* 665612Swnj * Generate IP header and pass packet to ip_output. 675612Swnj * Tack on options user may have setup with control call. 685612Swnj */ 6937322Skarels #define satosin(sa) ((struct sockaddr_in *)(sa)) 7037322Skarels rip_output(m, so) 7137322Skarels register struct mbuf *m; 725612Swnj struct socket *so; 735123Swnj { 745612Swnj register struct ip *ip; 7537322Skarels register struct raw_inpcb *rp = sotorawinpcb(so); 7637322Skarels register struct sockaddr_in *sin; 775123Swnj 785612Swnj /* 7937322Skarels * If the user handed us a complete IP packet, use it. 8037322Skarels * Otherwise, allocate an mbuf for a header and fill it in. 815612Swnj */ 8237322Skarels if (rp->rinp_flags & RINPF_HDRINCL) 8337322Skarels ip = mtod(m, struct ip *); 8437322Skarels else { 8537322Skarels M_PREPEND(m, sizeof(struct ip), M_WAIT); 8637322Skarels ip = mtod(m, struct ip *); 8737322Skarels ip->ip_tos = 0; 8837322Skarels ip->ip_off = 0; 8937322Skarels ip->ip_p = rp->rinp_rcb.rcb_proto.sp_protocol; 9037322Skarels ip->ip_len = m->m_pkthdr.len; 9137322Skarels if (sin = satosin(rp->rinp_rcb.rcb_laddr)) { 9237322Skarels ip->ip_src = sin->sin_addr; 9337322Skarels } else 9437322Skarels ip->ip_src.s_addr = 0; 9537322Skarels if (sin = satosin(rp->rinp_rcb.rcb_faddr)) 9637322Skarels ip->ip_dst = sin->sin_addr; 9737322Skarels ip->ip_ttl = MAXTTL; 985612Swnj } 9937322Skarels return (ip_output(m, 10037322Skarels (rp->rinp_flags & RINPF_HDRINCL)? (struct mbuf *)0: rp->rinp_options, 10137322Skarels &rp->rinp_route, 10226037Skarels (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST)); 1035123Swnj } 10426037Skarels 10526037Skarels /* 10626037Skarels * Raw IP socket option processing. 10726037Skarels */ 10826037Skarels rip_ctloutput(op, so, level, optname, m) 10926037Skarels int op; 11026037Skarels struct socket *so; 11126037Skarels int level, optname; 11226037Skarels struct mbuf **m; 11326037Skarels { 11426037Skarels int error = 0; 11537322Skarels register struct raw_inpcb *rp = sotorawinpcb(so); 11626037Skarels 11726037Skarels if (level != IPPROTO_IP) 11826037Skarels error = EINVAL; 11926037Skarels else switch (op) { 12026037Skarels 12126037Skarels case PRCO_SETOPT: 12226037Skarels switch (optname) { 12337322Skarels 12426037Skarels case IP_OPTIONS: 12537322Skarels return (ip_pcbopts(&rp->rinp_options, *m)); 12626037Skarels 12737322Skarels case IP_HDRINCL: 12837322Skarels if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) { 12937322Skarels error = EINVAL; 13037322Skarels break; 13137322Skarels } 13237322Skarels if (*mtod(*m, int *)) 13337322Skarels rp->rinp_flags |= RINPF_HDRINCL; 13437322Skarels else 13537322Skarels rp->rinp_flags &= ~RINPF_HDRINCL; 13637322Skarels break; 13737322Skarels 13826037Skarels default: 13926037Skarels error = EINVAL; 14026037Skarels break; 14126037Skarels } 14226037Skarels break; 14326037Skarels 14426037Skarels case PRCO_GETOPT: 14537322Skarels *m = m_get(M_WAIT, MT_SOOPTS); 14626037Skarels switch (optname) { 14737322Skarels 14826037Skarels case IP_OPTIONS: 14937322Skarels if (rp->rinp_options) { 15037322Skarels (*m)->m_len = rp->rinp_options->m_len; 15137322Skarels bcopy(mtod(rp->rinp_options, caddr_t), 15226386Skarels mtod(*m, caddr_t), (unsigned)(*m)->m_len); 15326037Skarels } else 15426037Skarels (*m)->m_len = 0; 15526037Skarels break; 15637322Skarels 15737322Skarels case IP_HDRINCL: 15837322Skarels (*m)->m_len = sizeof (int); 15937322Skarels *mtod(*m, int *) = rp->rinp_flags & RINPF_HDRINCL; 16037322Skarels break; 16137322Skarels 16226037Skarels default: 16326037Skarels error = EINVAL; 16437322Skarels m_freem(*m); 16537322Skarels *m = 0; 16626037Skarels break; 16726037Skarels } 16826037Skarels break; 16926037Skarels } 17031649Smckusick if (op == PRCO_SETOPT && *m) 17126386Skarels (void)m_free(*m); 17226037Skarels return (error); 17326037Skarels } 17437322Skarels 17537322Skarels /*ARGSUSED*/ 17637322Skarels rip_usrreq(so, req, m, nam, rights, control) 17737322Skarels register struct socket *so; 17837322Skarels int req; 17937322Skarels struct mbuf *m, *nam, *rights, *control; 18037322Skarels { 18137322Skarels register int error = 0; 18237322Skarels register struct raw_inpcb *rp = sotorawinpcb(so); 18337322Skarels 18437322Skarels switch (req) { 18537322Skarels 18637322Skarels case PRU_ATTACH: 18737322Skarels if (rp) 18837322Skarels panic("rip_attach"); 18937322Skarels MALLOC(rp, struct raw_inpcb *, sizeof *rp, M_PCB, M_WAITOK); 19037322Skarels if (rp == 0) 19137322Skarels return (ENOBUFS); 19237322Skarels bzero((caddr_t)rp, sizeof *rp); 19337322Skarels so->so_pcb = (caddr_t)rp; 19437322Skarels break; 19537322Skarels 19637322Skarels case PRU_DETACH: 19737322Skarels if (rp == 0) 19837322Skarels panic("rip_detach"); 19937322Skarels if (rp->rinp_options) 20037322Skarels m_freem(rp->rinp_options); 20137322Skarels if (rp->rinp_route.ro_rt) 20237322Skarels RTFREE(rp->rinp_route.ro_rt); 20337322Skarels if (rp->rinp_rcb.rcb_laddr) 20437322Skarels rp->rinp_rcb.rcb_laddr = 0; 20537322Skarels break; 20637322Skarels 20737322Skarels case PRU_BIND: 20837322Skarels { 20937322Skarels struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 21037322Skarels 21137322Skarels if (nam->m_len != sizeof(*addr)) 21237322Skarels return (EINVAL); 21337322Skarels if ((ifnet == 0) || 21437322Skarels ((addr->sin_family != AF_INET) && 21537322Skarels (addr->sin_family != AF_IMPLINK)) || 21637322Skarels (addr->sin_addr.s_addr && 21737322Skarels ifa_ifwithaddr((struct sockaddr *)addr) == 0)) 21837322Skarels return (EADDRNOTAVAIL); 21937322Skarels rp->rinp_rcb.rcb_laddr = (struct sockaddr *)&rp->rinp_laddr; 22037322Skarels rp->rinp_laddr = *addr; 22137322Skarels return (0); 22237322Skarels } 22337322Skarels case PRU_CONNECT: 22437322Skarels { 22537322Skarels struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 22637322Skarels 22737322Skarels if (nam->m_len != sizeof(*addr)) 22837322Skarels return (EINVAL); 22937322Skarels if (ifnet == 0) 23037322Skarels return (EADDRNOTAVAIL); 23137322Skarels if ((addr->sin_family != AF_INET) && 23237322Skarels (addr->sin_family != AF_IMPLINK)) 23337322Skarels return (EAFNOSUPPORT); 23437322Skarels rp->rinp_rcb.rcb_faddr = (struct sockaddr *)&rp->rinp_faddr; 23537322Skarels rp->rinp_laddr = *addr; 23637322Skarels soisconnected(so); 23737322Skarels return (0); 23837322Skarels } 23937322Skarels } 24037322Skarels error = raw_usrreq(so, req, m, nam, rights, control); 24137322Skarels 24237322Skarels if (error && (req == PRU_ATTACH) && so->so_pcb) 24337322Skarels free(so->so_pcb, M_PCB); 24437322Skarels return (error); 24537322Skarels } 246