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