1 /* 2 * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)raw_ip.c 7.8 (Berkeley) 07/25/90 8 */ 9 10 #include "param.h" 11 #include "malloc.h" 12 #include "mbuf.h" 13 #include "socket.h" 14 #include "protosw.h" 15 #include "socketvar.h" 16 #include "errno.h" 17 18 #include "../net/if.h" 19 #include "../net/route.h" 20 #include "../net/raw_cb.h" 21 22 #include "in.h" 23 #include "in_systm.h" 24 #include "ip.h" 25 #include "ip_var.h" 26 #include "in_pcb.h" 27 28 /* 29 * Raw interface to IP protocol. 30 */ 31 32 struct sockaddr_in ripdst = { sizeof(ripdst), AF_INET }; 33 struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 34 struct sockproto ripproto = { PF_INET }; 35 /* 36 * Setup generic address and protocol structures 37 * for raw_input routine, then pass them along with 38 * mbuf chain. 39 */ 40 rip_input(m) 41 struct mbuf *m; 42 { 43 register struct ip *ip = mtod(m, struct ip *); 44 45 ripproto.sp_protocol = ip->ip_p; 46 ripdst.sin_addr = ip->ip_dst; 47 ripsrc.sin_addr = ip->ip_src; 48 if (raw_input(m, &ripproto, (struct sockaddr *)&ripsrc, 49 (struct sockaddr *)&ripdst) == 0) { 50 ipstat.ips_noproto++; 51 ipstat.ips_delivered--; 52 } 53 } 54 55 /* 56 * Generate IP header and pass packet to ip_output. 57 * Tack on options user may have setup with control call. 58 */ 59 #define satosin(sa) ((struct sockaddr_in *)(sa)) 60 rip_output(m, so) 61 register struct mbuf *m; 62 struct socket *so; 63 { 64 register struct ip *ip; 65 register struct raw_inpcb *rp = sotorawinpcb(so); 66 register struct sockaddr_in *sin; 67 68 /* 69 * If the user handed us a complete IP packet, use it. 70 * Otherwise, allocate an mbuf for a header and fill it in. 71 */ 72 if (rp->rinp_flags & RINPF_HDRINCL) 73 ip = mtod(m, struct ip *); 74 else { 75 M_PREPEND(m, sizeof(struct ip), M_WAIT); 76 ip = mtod(m, struct ip *); 77 ip->ip_tos = 0; 78 ip->ip_off = 0; 79 ip->ip_p = rp->rinp_rcb.rcb_proto.sp_protocol; 80 ip->ip_len = m->m_pkthdr.len; 81 if (sin = satosin(rp->rinp_rcb.rcb_laddr)) { 82 ip->ip_src = sin->sin_addr; 83 } else 84 ip->ip_src.s_addr = 0; 85 if (sin = satosin(rp->rinp_rcb.rcb_faddr)) 86 ip->ip_dst = sin->sin_addr; 87 ip->ip_ttl = MAXTTL; 88 } 89 return (ip_output(m, 90 (rp->rinp_flags & RINPF_HDRINCL)? (struct mbuf *)0: rp->rinp_options, 91 &rp->rinp_route, 92 (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST)); 93 } 94 95 /* 96 * Raw IP socket option processing. 97 */ 98 rip_ctloutput(op, so, level, optname, m) 99 int op; 100 struct socket *so; 101 int level, optname; 102 struct mbuf **m; 103 { 104 int error = 0; 105 register struct raw_inpcb *rp = sotorawinpcb(so); 106 107 if (level != IPPROTO_IP) 108 error = EINVAL; 109 else switch (op) { 110 111 case PRCO_SETOPT: 112 switch (optname) { 113 114 case IP_OPTIONS: 115 return (ip_pcbopts(&rp->rinp_options, *m)); 116 117 case IP_HDRINCL: 118 if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) { 119 error = EINVAL; 120 break; 121 } 122 if (*mtod(*m, int *)) 123 rp->rinp_flags |= RINPF_HDRINCL; 124 else 125 rp->rinp_flags &= ~RINPF_HDRINCL; 126 break; 127 128 default: 129 error = EINVAL; 130 break; 131 } 132 break; 133 134 case PRCO_GETOPT: 135 *m = m_get(M_WAIT, MT_SOOPTS); 136 switch (optname) { 137 138 case IP_OPTIONS: 139 if (rp->rinp_options) { 140 (*m)->m_len = rp->rinp_options->m_len; 141 bcopy(mtod(rp->rinp_options, caddr_t), 142 mtod(*m, caddr_t), (unsigned)(*m)->m_len); 143 } else 144 (*m)->m_len = 0; 145 break; 146 147 case IP_HDRINCL: 148 (*m)->m_len = sizeof (int); 149 *mtod(*m, int *) = rp->rinp_flags & RINPF_HDRINCL; 150 break; 151 152 default: 153 error = EINVAL; 154 m_freem(*m); 155 *m = 0; 156 break; 157 } 158 break; 159 } 160 if (op == PRCO_SETOPT && *m) 161 (void)m_free(*m); 162 return (error); 163 } 164 165 /*ARGSUSED*/ 166 rip_usrreq(so, req, m, nam, rights, control) 167 register struct socket *so; 168 int req; 169 struct mbuf *m, *nam, *rights, *control; 170 { 171 register int error = 0; 172 register struct raw_inpcb *rp = sotorawinpcb(so); 173 174 switch (req) { 175 176 case PRU_ATTACH: 177 if (rp) 178 panic("rip_attach"); 179 MALLOC(rp, struct raw_inpcb *, sizeof *rp, M_PCB, M_WAITOK); 180 if (rp == 0) 181 return (ENOBUFS); 182 bzero((caddr_t)rp, sizeof *rp); 183 so->so_pcb = (caddr_t)rp; 184 break; 185 186 case PRU_DETACH: 187 if (rp == 0) 188 panic("rip_detach"); 189 if (rp->rinp_options) 190 m_freem(rp->rinp_options); 191 if (rp->rinp_route.ro_rt) 192 RTFREE(rp->rinp_route.ro_rt); 193 if (rp->rinp_rcb.rcb_laddr) 194 rp->rinp_rcb.rcb_laddr = 0; 195 break; 196 197 case PRU_BIND: 198 { 199 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 200 201 if (nam->m_len != sizeof(*addr)) 202 return (EINVAL); 203 if ((ifnet == 0) || 204 ((addr->sin_family != AF_INET) && 205 (addr->sin_family != AF_IMPLINK)) || 206 (addr->sin_addr.s_addr && 207 ifa_ifwithaddr((struct sockaddr *)addr) == 0)) 208 return (EADDRNOTAVAIL); 209 rp->rinp_rcb.rcb_laddr = (struct sockaddr *)&rp->rinp_laddr; 210 rp->rinp_laddr = *addr; 211 return (0); 212 } 213 case PRU_CONNECT: 214 { 215 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 216 217 if (nam->m_len != sizeof(*addr)) 218 return (EINVAL); 219 if (ifnet == 0) 220 return (EADDRNOTAVAIL); 221 if ((addr->sin_family != AF_INET) && 222 (addr->sin_family != AF_IMPLINK)) 223 return (EAFNOSUPPORT); 224 rp->rinp_rcb.rcb_faddr = (struct sockaddr *)&rp->rinp_faddr; 225 rp->rinp_faddr = *addr; 226 soisconnected(so); 227 return (0); 228 } 229 } 230 error = raw_usrreq(so, req, m, nam, rights, control); 231 232 if (error && (req == PRU_ATTACH) && so->so_pcb) 233 free(so->so_pcb, M_PCB); 234 return (error); 235 } 236