1 /* 2 * Copyright (c) 1982, 1986, 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94 34 * $Id: raw_ip.c,v 1.14 1995/02/07 02:53:14 wollman Exp $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/malloc.h> 39 #include <sys/mbuf.h> 40 #include <sys/socket.h> 41 #include <sys/protosw.h> 42 #include <sys/socketvar.h> 43 #include <sys/errno.h> 44 #include <sys/systm.h> 45 46 #include <net/if.h> 47 #include <net/route.h> 48 49 #include <netinet/in.h> 50 #include <netinet/in_systm.h> 51 #include <netinet/ip.h> 52 #include <netinet/ip_var.h> 53 #include <netinet/ip_mroute.h> 54 #include <netinet/in_pcb.h> 55 56 #include <netinet/ip_fw.h> 57 58 struct inpcb rawinpcb; 59 60 /* 61 * Nominal space allocated to a raw ip socket. 62 */ 63 #define RIPSNDQ 8192 64 #define RIPRCVQ 8192 65 66 /* 67 * Raw interface to IP protocol. 68 */ 69 70 /* 71 * Initialize raw connection block q. 72 */ 73 void 74 rip_init() 75 { 76 77 rawinpcb.inp_next = rawinpcb.inp_prev = &rawinpcb; 78 } 79 80 struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 81 /* 82 * Setup generic address and protocol structures 83 * for raw_input routine, then pass them along with 84 * mbuf chain. 85 */ 86 void 87 rip_input(m) 88 struct mbuf *m; 89 { 90 register struct ip *ip = mtod(m, struct ip *); 91 register struct inpcb *inp; 92 struct socket *last = 0; 93 94 ripsrc.sin_addr = ip->ip_src; 95 for (inp = rawinpcb.inp_next; inp != &rawinpcb; inp = inp->inp_next) { 96 if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != ip->ip_p) 97 continue; 98 if (inp->inp_laddr.s_addr && 99 inp->inp_laddr.s_addr == ip->ip_dst.s_addr) 100 continue; 101 if (inp->inp_faddr.s_addr && 102 inp->inp_faddr.s_addr == ip->ip_src.s_addr) 103 continue; 104 if (last) { 105 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 106 if (n) { 107 if (sbappendaddr(&last->so_rcv, 108 (struct sockaddr *)&ripsrc, n, 109 (struct mbuf *)0) == 0) 110 /* should notify about lost packet */ 111 m_freem(n); 112 else 113 sorwakeup(last); 114 } 115 } 116 last = inp->inp_socket; 117 } 118 if (last) { 119 if (sbappendaddr(&last->so_rcv, (struct sockaddr *)&ripsrc, 120 m, (struct mbuf *)0) == 0) 121 m_freem(m); 122 else 123 sorwakeup(last); 124 } else { 125 m_freem(m); 126 ipstat.ips_noproto++; 127 ipstat.ips_delivered--; 128 } 129 } 130 131 /* 132 * Generate IP header and pass packet to ip_output. 133 * Tack on options user may have setup with control call. 134 */ 135 int 136 rip_output(m, so, dst) 137 register struct mbuf *m; 138 struct socket *so; 139 u_long dst; 140 { 141 register struct ip *ip; 142 register struct inpcb *inp = sotoinpcb(so); 143 struct mbuf *opts; 144 int flags = (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST; 145 146 /* 147 * If the user handed us a complete IP packet, use it. 148 * Otherwise, allocate an mbuf for a header and fill it in. 149 */ 150 if ((inp->inp_flags & INP_HDRINCL) == 0) { 151 M_PREPEND(m, sizeof(struct ip), M_WAIT); 152 ip = mtod(m, struct ip *); 153 ip->ip_tos = 0; 154 ip->ip_off = 0; 155 ip->ip_p = inp->inp_ip.ip_p; 156 ip->ip_len = m->m_pkthdr.len; 157 ip->ip_src = inp->inp_laddr; 158 ip->ip_dst.s_addr = dst; 159 ip->ip_ttl = MAXTTL; 160 opts = inp->inp_options; 161 } else { 162 ip = mtod(m, struct ip *); 163 if (ip->ip_id == 0) 164 ip->ip_id = htons(ip_id++); 165 opts = NULL; 166 /* XXX prevent ip_output from overwriting header fields */ 167 flags |= IP_RAWOUTPUT; 168 ipstat.ips_rawout++; 169 } 170 return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions)); 171 } 172 173 /* 174 * Raw IP socket option processing. 175 */ 176 int 177 rip_ctloutput(op, so, level, optname, m) 178 int op; 179 struct socket *so; 180 int level, optname; 181 struct mbuf **m; 182 { 183 register struct inpcb *inp = sotoinpcb(so); 184 register int error; 185 186 if (level != IPPROTO_IP) { 187 if (op == PRCO_SETOPT && *m) 188 (void)m_free(*m); 189 return (EINVAL); 190 } 191 192 switch (optname) { 193 194 case IP_HDRINCL: 195 if (op == PRCO_SETOPT || op == PRCO_GETOPT) { 196 if (m == 0 || *m == 0 || (*m)->m_len < sizeof (int)) 197 return (EINVAL); 198 if (op == PRCO_SETOPT) { 199 if (*mtod(*m, int *)) 200 inp->inp_flags |= INP_HDRINCL; 201 else 202 inp->inp_flags &= ~INP_HDRINCL; 203 (void)m_free(*m); 204 } else { 205 (*m)->m_len = sizeof (int); 206 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL; 207 } 208 return (0); 209 } 210 break; 211 212 case IP_FW_ADD: 213 case IP_FW_DEL: 214 case IP_FW_FLUSH: 215 case IP_FW_POLICY: 216 if (ip_fw_ctl_ptr==NULL) { 217 if (*m) 218 (void)m_free(*m); 219 return(EINVAL); 220 } 221 222 if (op == PRCO_SETOPT) { 223 error=(*ip_fw_ctl_ptr)(optname, *m); 224 if (*m) 225 (void)m_free(*m); 226 } 227 else 228 error=EINVAL; 229 return(error); 230 231 case IP_ACCT_DEL: 232 case IP_ACCT_ADD: 233 case IP_ACCT_CLR: 234 case IP_ACCT_FLUSH: 235 case IP_ACCT_ZERO: 236 if (ip_acct_ctl_ptr==NULL) { 237 if (*m) 238 (void)m_free(*m); 239 return(EINVAL); 240 } 241 242 op = PRCO_SETOPT; 243 if (op) { 244 error=(*ip_acct_ctl_ptr)(optname, *m); 245 if (*m) 246 (void)m_free(*m); 247 } 248 else 249 error=EINVAL; 250 return(error); 251 252 case IP_RSVP_ON: 253 return ip_rsvp_init(so); 254 break; 255 256 case IP_RSVP_OFF: 257 return ip_rsvp_done(); 258 break; 259 260 case DVMRP_INIT: 261 case DVMRP_DONE: 262 case DVMRP_ADD_VIF: 263 case DVMRP_DEL_VIF: 264 case DVMRP_ADD_MFC: 265 case DVMRP_DEL_MFC: 266 if (op == PRCO_SETOPT) { 267 error = ip_mrouter_cmd(optname, so, *m); 268 if (*m) 269 (void)m_free(*m); 270 } else 271 error = EINVAL; 272 return (error); 273 } 274 return (ip_ctloutput(op, so, level, optname, m)); 275 } 276 277 u_long rip_sendspace = RIPSNDQ; 278 u_long rip_recvspace = RIPRCVQ; 279 280 /*ARGSUSED*/ 281 int 282 rip_usrreq(so, req, m, nam, control) 283 register struct socket *so; 284 int req; 285 struct mbuf *m, *nam, *control; 286 { 287 register int error = 0; 288 register struct inpcb *inp = sotoinpcb(so); 289 switch (req) { 290 291 case PRU_ATTACH: 292 if (inp) 293 panic("rip_attach"); 294 if ((so->so_state & SS_PRIV) == 0) { 295 error = EACCES; 296 break; 297 } 298 if ((error = soreserve(so, rip_sendspace, rip_recvspace)) || 299 (error = in_pcballoc(so, &rawinpcb))) 300 break; 301 inp = (struct inpcb *)so->so_pcb; 302 inp->inp_ip.ip_p = (int)nam; 303 break; 304 305 case PRU_DISCONNECT: 306 if ((so->so_state & SS_ISCONNECTED) == 0) { 307 error = ENOTCONN; 308 break; 309 } 310 /* FALLTHROUGH */ 311 case PRU_ABORT: 312 soisdisconnected(so); 313 /* FALLTHROUGH */ 314 case PRU_DETACH: 315 if (inp == 0) 316 panic("rip_detach"); 317 if (so == ip_mrouter) 318 ip_mrouter_done(); 319 if (so == ip_rsvpd) 320 ip_rsvp_done(); 321 in_pcbdetach(inp); 322 break; 323 324 case PRU_BIND: 325 { 326 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 327 328 if (nam->m_len != sizeof(*addr)) { 329 error = EINVAL; 330 break; 331 } 332 if ((ifnet == 0) || 333 ((addr->sin_family != AF_INET) && 334 (addr->sin_family != AF_IMPLINK)) || 335 (addr->sin_addr.s_addr && 336 ifa_ifwithaddr((struct sockaddr *)addr) == 0)) { 337 error = EADDRNOTAVAIL; 338 break; 339 } 340 inp->inp_laddr = addr->sin_addr; 341 break; 342 } 343 case PRU_CONNECT: 344 { 345 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 346 347 if (nam->m_len != sizeof(*addr)) { 348 error = EINVAL; 349 break; 350 } 351 if (ifnet == 0) { 352 error = EADDRNOTAVAIL; 353 break; 354 } 355 if ((addr->sin_family != AF_INET) && 356 (addr->sin_family != AF_IMPLINK)) { 357 error = EAFNOSUPPORT; 358 break; 359 } 360 inp->inp_faddr = addr->sin_addr; 361 soisconnected(so); 362 break; 363 } 364 365 case PRU_CONNECT2: 366 error = EOPNOTSUPP; 367 break; 368 369 /* 370 * Mark the connection as being incapable of further input. 371 */ 372 case PRU_SHUTDOWN: 373 socantsendmore(so); 374 break; 375 376 /* 377 * Ship a packet out. The appropriate raw output 378 * routine handles any massaging necessary. 379 */ 380 case PRU_SEND: 381 { 382 register u_long dst; 383 384 if (so->so_state & SS_ISCONNECTED) { 385 if (nam) { 386 error = EISCONN; 387 break; 388 } 389 dst = inp->inp_faddr.s_addr; 390 } else { 391 if (nam == NULL) { 392 error = ENOTCONN; 393 break; 394 } 395 dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; 396 } 397 error = rip_output(m, so, dst); 398 m = NULL; 399 break; 400 } 401 402 case PRU_SENSE: 403 /* 404 * stat: don't bother with a blocksize. 405 */ 406 return (0); 407 408 /* 409 * Not supported. 410 */ 411 case PRU_RCVOOB: 412 case PRU_RCVD: 413 case PRU_LISTEN: 414 case PRU_ACCEPT: 415 case PRU_SENDOOB: 416 error = EOPNOTSUPP; 417 break; 418 419 case PRU_SOCKADDR: 420 in_setsockaddr(inp, nam); 421 break; 422 423 case PRU_PEERADDR: 424 in_setpeeraddr(inp, nam); 425 break; 426 427 default: 428 panic("rip_usrreq"); 429 } 430 if (m != NULL) 431 m_freem(m); 432 return (error); 433 } 434