123186Smckusick /* 229146Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 3*32787Sbostic * All rights reserved. 423186Smckusick * 5*32787Sbostic * Redistribution and use in source and binary forms are permitted 6*32787Sbostic * provided that this notice is preserved and that due credit is given 7*32787Sbostic * to the University of California at Berkeley. The name of the University 8*32787Sbostic * may not be used to endorse or promote products derived from this 9*32787Sbostic * software without specific prior written permission. This software 10*32787Sbostic * is provided ``as is'' without express or implied warranty. 11*32787Sbostic * 12*32787Sbostic * @(#)raw_ip.c 7.3 (Berkeley) 12/07/87 1323186Smckusick */ 145123Swnj 1517062Sbloom #include "param.h" 1617062Sbloom #include "mbuf.h" 1717062Sbloom #include "socket.h" 1817062Sbloom #include "protosw.h" 1917062Sbloom #include "socketvar.h" 2017062Sbloom #include "errno.h" 2110894Ssam 226509Ssam #include "../net/if.h" 2313455Ssam #include "../net/route.h" 2410894Ssam #include "../net/raw_cb.h" 2510894Ssam 2617062Sbloom #include "in.h" 2717062Sbloom #include "in_systm.h" 2817062Sbloom #include "ip.h" 2917062Sbloom #include "ip_var.h" 305123Swnj 315123Swnj /* 325612Swnj * Raw interface to IP protocol. 335123Swnj */ 345612Swnj 3513455Ssam struct sockaddr_in ripdst = { AF_INET }; 3613455Ssam struct sockaddr_in ripsrc = { AF_INET }; 3713455Ssam struct sockproto ripproto = { PF_INET }; 385612Swnj /* 395612Swnj * Setup generic address and protocol structures 405612Swnj * for raw_input routine, then pass them along with 415612Swnj * mbuf chain. 425612Swnj */ 435123Swnj rip_input(m) 445123Swnj struct mbuf *m; 455123Swnj { 465612Swnj register struct ip *ip = mtod(m, struct ip *); 475123Swnj 485612Swnj ripproto.sp_protocol = ip->ip_p; 495646Ssam ripdst.sin_addr = ip->ip_dst; 505646Ssam ripsrc.sin_addr = ip->ip_src; 516529Ssam raw_input(m, &ripproto, (struct sockaddr *)&ripsrc, 526529Ssam (struct sockaddr *)&ripdst); 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 */ 595612Swnj rip_output(m0, so) 605612Swnj struct mbuf *m0; 615612Swnj struct socket *so; 625123Swnj { 635612Swnj register struct mbuf *m; 645612Swnj register struct ip *ip; 656509Ssam int len = 0, error; 666509Ssam struct rawcb *rp = sotorawcb(so); 677156Swnj struct sockaddr_in *sin; 685123Swnj 695612Swnj /* 705612Swnj * Calculate data length and get an mbuf 715612Swnj * for IP header. 725612Swnj */ 735612Swnj for (m = m0; m; m = m->m_next) 745612Swnj len += m->m_len; 759642Ssam m = m_get(M_DONTWAIT, MT_HEADER); 765612Swnj if (m == 0) { 776509Ssam error = ENOBUFS; 786509Ssam goto bad; 795612Swnj } 805612Swnj 815612Swnj /* 825612Swnj * Fill in IP header as needed. 835612Swnj */ 845612Swnj m->m_off = MMAXOFF - sizeof(struct ip); 855612Swnj m->m_len = sizeof(struct ip); 865612Swnj m->m_next = m0; 875612Swnj ip = mtod(m, struct ip *); 8816798Skarels ip->ip_tos = 0; 8915714Skarels ip->ip_off = 0; 9021770Skarels ip->ip_p = rp->rcb_proto.sp_protocol; 915612Swnj ip->ip_len = sizeof(struct ip) + len; 927156Swnj if (rp->rcb_flags & RAW_LADDR) { 937156Swnj sin = (struct sockaddr_in *)&rp->rcb_laddr; 947156Swnj if (sin->sin_family != AF_INET) { 956509Ssam error = EAFNOSUPPORT; 966509Ssam goto bad; 976509Ssam } 987156Swnj ip->ip_src.s_addr = sin->sin_addr.s_addr; 997156Swnj } else 1007156Swnj ip->ip_src.s_addr = 0; 1017156Swnj ip->ip_dst = ((struct sockaddr_in *)&rp->rcb_faddr)->sin_addr; 1025612Swnj ip->ip_ttl = MAXTTL; 10326037Skarels return (ip_output(m, rp->rcb_options, &rp->rcb_route, 10426037Skarels (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST)); 1056509Ssam bad: 1066509Ssam m_freem(m); 1076509Ssam return (error); 1085123Swnj } 10926037Skarels 11026037Skarels /* 11126037Skarels * Raw IP socket option processing. 11226037Skarels */ 11326037Skarels rip_ctloutput(op, so, level, optname, m) 11426037Skarels int op; 11526037Skarels struct socket *so; 11626037Skarels int level, optname; 11726037Skarels struct mbuf **m; 11826037Skarels { 11926037Skarels int error = 0; 12026037Skarels register struct rawcb *rp = sotorawcb(so); 12126037Skarels 12226037Skarels if (level != IPPROTO_IP) 12326037Skarels error = EINVAL; 12426037Skarels else switch (op) { 12526037Skarels 12626037Skarels case PRCO_SETOPT: 12726037Skarels switch (optname) { 12826037Skarels case IP_OPTIONS: 12926037Skarels return (ip_pcbopts(&rp->rcb_options, *m)); 13026037Skarels 13126037Skarels default: 13226037Skarels error = EINVAL; 13326037Skarels break; 13426037Skarels } 13526037Skarels break; 13626037Skarels 13726037Skarels case PRCO_GETOPT: 13826037Skarels switch (optname) { 13926037Skarels case IP_OPTIONS: 14026037Skarels *m = m_get(M_WAIT, MT_SOOPTS); 14126037Skarels if (rp->rcb_options) { 14226037Skarels (*m)->m_off = rp->rcb_options->m_off; 14326037Skarels (*m)->m_len = rp->rcb_options->m_len; 14426037Skarels bcopy(mtod(rp->rcb_options, caddr_t), 14526386Skarels mtod(*m, caddr_t), (unsigned)(*m)->m_len); 14626037Skarels } else 14726037Skarels (*m)->m_len = 0; 14826037Skarels break; 14926037Skarels default: 15026037Skarels error = EINVAL; 15126037Skarels break; 15226037Skarels } 15326037Skarels break; 15426037Skarels } 15531649Smckusick if (op == PRCO_SETOPT && *m) 15626386Skarels (void)m_free(*m); 15726037Skarels return (error); 15826037Skarels } 159