1 /* $NetBSD: raw_ip.c,v 1.53 2000/03/30 13:25:04 augustss Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1982, 1986, 1988, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. All advertising materials mentioning features or use of this software 45 * must display the following acknowledgement: 46 * This product includes software developed by the University of 47 * California, Berkeley and its contributors. 48 * 4. Neither the name of the University nor the names of its contributors 49 * may be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 * 64 * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95 65 */ 66 67 #include "opt_ipsec.h" 68 #include "opt_mrouting.h" 69 70 #include <sys/param.h> 71 #include <sys/malloc.h> 72 #include <sys/mbuf.h> 73 #include <sys/socket.h> 74 #include <sys/protosw.h> 75 #include <sys/socketvar.h> 76 #include <sys/errno.h> 77 #include <sys/systm.h> 78 #include <sys/proc.h> 79 80 #include <net/if.h> 81 #include <net/route.h> 82 83 #include <netinet/in.h> 84 #include <netinet/in_systm.h> 85 #include <netinet/ip.h> 86 #include <netinet/ip_var.h> 87 #include <netinet/ip_mroute.h> 88 #include <netinet/ip_icmp.h> 89 #include <netinet/in_pcb.h> 90 #include <netinet/in_var.h> 91 92 #include <machine/stdarg.h> 93 94 #ifdef IPSEC 95 #include <netinet6/ipsec.h> 96 #endif /*IPSEC*/ 97 98 struct inpcbtable rawcbtable; 99 100 int rip_bind __P((struct inpcb *, struct mbuf *)); 101 int rip_connect __P((struct inpcb *, struct mbuf *)); 102 void rip_disconnect __P((struct inpcb *)); 103 104 /* 105 * Nominal space allocated to a raw ip socket. 106 */ 107 #define RIPSNDQ 8192 108 #define RIPRCVQ 8192 109 110 /* 111 * Raw interface to IP protocol. 112 */ 113 114 /* 115 * Initialize raw connection block q. 116 */ 117 void 118 rip_init() 119 { 120 121 in_pcbinit(&rawcbtable, 1, 1); 122 } 123 124 static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 125 126 /* 127 * Setup generic address and protocol structures 128 * for raw_input routine, then pass them along with 129 * mbuf chain. 130 */ 131 void 132 #if __STDC__ 133 rip_input(struct mbuf *m, ...) 134 #else 135 rip_input(m, va_alist) 136 struct mbuf *m; 137 va_dcl 138 #endif 139 { 140 int off, proto; 141 struct ip *ip = mtod(m, struct ip *); 142 struct inpcb *inp; 143 struct inpcb *last = 0; 144 struct mbuf *opts = 0; 145 struct sockaddr_in ripsrc; 146 va_list ap; 147 148 va_start(ap, m); 149 off = va_arg(ap, int); 150 proto = va_arg(ap, int); 151 va_end(ap); 152 153 ripsrc.sin_family = AF_INET; 154 ripsrc.sin_len = sizeof(struct sockaddr_in); 155 ripsrc.sin_addr = ip->ip_src; 156 ripsrc.sin_port = 0; 157 bzero((caddr_t)ripsrc.sin_zero, sizeof(ripsrc.sin_zero)); 158 159 /* 160 * XXX Compatibility: programs using raw IP expect ip_len 161 * XXX to have the header length subtracted. 162 */ 163 ip->ip_len -= ip->ip_hl << 2; 164 165 for (inp = rawcbtable.inpt_queue.cqh_first; 166 inp != (struct inpcb *)&rawcbtable.inpt_queue; 167 inp = inp->inp_queue.cqe_next) { 168 if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != proto) 169 continue; 170 if (!in_nullhost(inp->inp_laddr) && 171 !in_hosteq(inp->inp_laddr, ip->ip_dst)) 172 continue; 173 if (!in_nullhost(inp->inp_faddr) && 174 !in_hosteq(inp->inp_faddr, ip->ip_src)) 175 continue; 176 if (last) { 177 struct mbuf *n; 178 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { 179 if (last->inp_flags & INP_CONTROLOPTS || 180 last->inp_socket->so_options & SO_TIMESTAMP) 181 ip_savecontrol(last, &opts, ip, n); 182 if (sbappendaddr(&last->inp_socket->so_rcv, 183 sintosa(&ripsrc), n, opts) == 0) { 184 /* should notify about lost packet */ 185 m_freem(n); 186 if (opts) 187 m_freem(opts); 188 } else 189 sorwakeup(last->inp_socket); 190 opts = NULL; 191 } 192 } 193 last = inp; 194 } 195 if (last) { 196 if (last->inp_flags & INP_CONTROLOPTS || 197 last->inp_socket->so_options & SO_TIMESTAMP) 198 ip_savecontrol(last, &opts, ip, m); 199 if (sbappendaddr(&last->inp_socket->so_rcv, 200 sintosa(&ripsrc), m, opts) == 0) { 201 m_freem(m); 202 if (opts) 203 m_freem(opts); 204 } else 205 sorwakeup(last->inp_socket); 206 } else { 207 if (inetsw[ip_protox[ip->ip_p]].pr_input == rip_input) { 208 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 209 0, 0); 210 ipstat.ips_noproto++; 211 ipstat.ips_delivered--; 212 } else 213 m_freem(m); 214 } 215 return; 216 } 217 218 /* 219 * Generate IP header and pass packet to ip_output. 220 * Tack on options user may have setup with control call. 221 */ 222 int 223 #if __STDC__ 224 rip_output(struct mbuf *m, ...) 225 #else 226 rip_output(m, va_alist) 227 struct mbuf *m; 228 va_dcl 229 #endif 230 { 231 struct inpcb *inp; 232 struct ip *ip; 233 struct mbuf *opts; 234 int flags; 235 va_list ap; 236 237 va_start(ap, m); 238 inp = va_arg(ap, struct inpcb *); 239 va_end(ap); 240 241 flags = 242 (inp->inp_socket->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST 243 | IP_RETURNMTU; 244 245 /* 246 * If the user handed us a complete IP packet, use it. 247 * Otherwise, allocate an mbuf for a header and fill it in. 248 */ 249 if ((inp->inp_flags & INP_HDRINCL) == 0) { 250 if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) { 251 m_freem(m); 252 return (EMSGSIZE); 253 } 254 M_PREPEND(m, sizeof(struct ip), M_WAIT); 255 ip = mtod(m, struct ip *); 256 ip->ip_tos = 0; 257 ip->ip_off = 0; 258 ip->ip_p = inp->inp_ip.ip_p; 259 ip->ip_len = m->m_pkthdr.len; 260 ip->ip_src = inp->inp_laddr; 261 ip->ip_dst = inp->inp_faddr; 262 ip->ip_ttl = MAXTTL; 263 opts = inp->inp_options; 264 } else { 265 if (m->m_pkthdr.len > IP_MAXPACKET) { 266 m_freem(m); 267 return (EMSGSIZE); 268 } 269 ip = mtod(m, struct ip *); 270 if (m->m_pkthdr.len != ip->ip_len) { 271 m_freem(m); 272 return (EINVAL); 273 } 274 if (ip->ip_id == 0) 275 ip->ip_id = htons(ip_id++); 276 opts = NULL; 277 /* XXX prevent ip_output from overwriting header fields */ 278 flags |= IP_RAWOUTPUT; 279 ipstat.ips_rawout++; 280 } 281 #ifdef IPSEC 282 ipsec_setsocket(m, inp->inp_socket); 283 #endif /*IPSEC*/ 284 return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions, &inp->inp_errormtu)); 285 } 286 287 /* 288 * Raw IP socket option processing. 289 */ 290 int 291 rip_ctloutput(op, so, level, optname, m) 292 int op; 293 struct socket *so; 294 int level, optname; 295 struct mbuf **m; 296 { 297 struct inpcb *inp = sotoinpcb(so); 298 int error = 0; 299 300 if (level != IPPROTO_IP) { 301 error = ENOPROTOOPT; 302 if (op == PRCO_SETOPT && *m != 0) 303 (void) m_free(*m); 304 } else switch (op) { 305 306 case PRCO_SETOPT: 307 switch (optname) { 308 case IP_HDRINCL: 309 if (*m == 0 || (*m)->m_len < sizeof (int)) 310 error = EINVAL; 311 else { 312 if (*mtod(*m, int *)) 313 inp->inp_flags |= INP_HDRINCL; 314 else 315 inp->inp_flags &= ~INP_HDRINCL; 316 } 317 if (*m != 0) 318 (void) m_free(*m); 319 break; 320 321 #ifdef MROUTING 322 case MRT_INIT: 323 case MRT_DONE: 324 case MRT_ADD_VIF: 325 case MRT_DEL_VIF: 326 case MRT_ADD_MFC: 327 case MRT_DEL_MFC: 328 case MRT_ASSERT: 329 error = ip_mrouter_set(so, optname, m); 330 break; 331 #endif 332 333 default: 334 error = ip_ctloutput(op, so, level, optname, m); 335 break; 336 } 337 break; 338 339 case PRCO_GETOPT: 340 switch (optname) { 341 case IP_HDRINCL: 342 *m = m_get(M_WAIT, M_SOOPTS); 343 (*m)->m_len = sizeof (int); 344 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL ? 1 : 0; 345 break; 346 347 #ifdef MROUTING 348 case MRT_VERSION: 349 case MRT_ASSERT: 350 error = ip_mrouter_get(so, optname, m); 351 break; 352 #endif 353 354 default: 355 error = ip_ctloutput(op, so, level, optname, m); 356 break; 357 } 358 break; 359 } 360 return (error); 361 } 362 363 int 364 rip_bind(inp, nam) 365 struct inpcb *inp; 366 struct mbuf *nam; 367 { 368 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 369 370 if (nam->m_len != sizeof(*addr)) 371 return (EINVAL); 372 if (ifnet.tqh_first == 0) 373 return (EADDRNOTAVAIL); 374 if (addr->sin_family != AF_INET && 375 addr->sin_family != AF_IMPLINK) 376 return (EAFNOSUPPORT); 377 if (!in_nullhost(addr->sin_addr) && 378 ifa_ifwithaddr(sintosa(addr)) == 0) 379 return (EADDRNOTAVAIL); 380 inp->inp_laddr = addr->sin_addr; 381 return (0); 382 } 383 384 int 385 rip_connect(inp, nam) 386 struct inpcb *inp; 387 struct mbuf *nam; 388 { 389 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 390 391 if (nam->m_len != sizeof(*addr)) 392 return (EINVAL); 393 if (ifnet.tqh_first == 0) 394 return (EADDRNOTAVAIL); 395 if (addr->sin_family != AF_INET && 396 addr->sin_family != AF_IMPLINK) 397 return (EAFNOSUPPORT); 398 inp->inp_faddr = addr->sin_addr; 399 return (0); 400 } 401 402 void 403 rip_disconnect(inp) 404 struct inpcb *inp; 405 { 406 407 inp->inp_faddr = zeroin_addr; 408 } 409 410 u_long rip_sendspace = RIPSNDQ; 411 u_long rip_recvspace = RIPRCVQ; 412 413 /*ARGSUSED*/ 414 int 415 rip_usrreq(so, req, m, nam, control, p) 416 struct socket *so; 417 int req; 418 struct mbuf *m, *nam, *control; 419 struct proc *p; 420 { 421 struct inpcb *inp; 422 int s; 423 int error = 0; 424 #ifdef MROUTING 425 extern struct socket *ip_mrouter; 426 #endif 427 428 if (req == PRU_CONTROL) 429 return (in_control(so, (long)m, (caddr_t)nam, 430 (struct ifnet *)control, p)); 431 432 if (req == PRU_PURGEIF) { 433 in_purgeif((struct ifnet *)control); 434 in_pcbpurgeif(&rawcbtable, (struct ifnet *)control); 435 return (0); 436 } 437 438 s = splsoftnet(); 439 inp = sotoinpcb(so); 440 #ifdef DIAGNOSTIC 441 if (req != PRU_SEND && req != PRU_SENDOOB && control) 442 panic("rip_usrreq: unexpected control mbuf"); 443 #endif 444 if (inp == 0 && req != PRU_ATTACH) { 445 error = EINVAL; 446 goto release; 447 } 448 449 switch (req) { 450 451 case PRU_ATTACH: 452 if (inp != 0) { 453 error = EISCONN; 454 break; 455 } 456 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))) { 457 error = EACCES; 458 break; 459 } 460 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 461 error = soreserve(so, rip_sendspace, rip_recvspace); 462 if (error) 463 break; 464 } 465 error = in_pcballoc(so, &rawcbtable); 466 if (error) 467 break; 468 inp = sotoinpcb(so); 469 inp->inp_ip.ip_p = (long)nam; 470 #ifdef IPSEC 471 error = ipsec_init_policy(so, &inp->inp_sp); 472 if (error != 0) { 473 in_pcbdetach(inp); 474 break; 475 } 476 #endif /*IPSEC*/ 477 break; 478 479 case PRU_DETACH: 480 #ifdef MROUTING 481 if (so == ip_mrouter) 482 ip_mrouter_done(); 483 #endif 484 in_pcbdetach(inp); 485 break; 486 487 case PRU_BIND: 488 error = rip_bind(inp, nam); 489 break; 490 491 case PRU_LISTEN: 492 error = EOPNOTSUPP; 493 break; 494 495 case PRU_CONNECT: 496 error = rip_connect(inp, nam); 497 if (error) 498 break; 499 soisconnected(so); 500 break; 501 502 case PRU_CONNECT2: 503 error = EOPNOTSUPP; 504 break; 505 506 case PRU_DISCONNECT: 507 soisdisconnected(so); 508 rip_disconnect(inp); 509 break; 510 511 /* 512 * Mark the connection as being incapable of further input. 513 */ 514 case PRU_SHUTDOWN: 515 socantsendmore(so); 516 break; 517 518 case PRU_RCVD: 519 error = EOPNOTSUPP; 520 break; 521 522 /* 523 * Ship a packet out. The appropriate raw output 524 * routine handles any massaging necessary. 525 */ 526 case PRU_SEND: 527 if (control && control->m_len) { 528 m_freem(control); 529 m_freem(m); 530 error = EINVAL; 531 break; 532 } 533 { 534 if (nam) { 535 if ((so->so_state & SS_ISCONNECTED) != 0) { 536 error = EISCONN; 537 goto die; 538 } 539 error = rip_connect(inp, nam); 540 if (error) { 541 die: 542 m_freem(m); 543 break; 544 } 545 } else { 546 if ((so->so_state & SS_ISCONNECTED) == 0) { 547 error = ENOTCONN; 548 goto die; 549 } 550 } 551 error = rip_output(m, inp); 552 if (nam) 553 rip_disconnect(inp); 554 } 555 break; 556 557 case PRU_SENSE: 558 /* 559 * stat: don't bother with a blocksize. 560 */ 561 splx(s); 562 return (0); 563 564 case PRU_RCVOOB: 565 error = EOPNOTSUPP; 566 break; 567 568 case PRU_SENDOOB: 569 m_freem(control); 570 m_freem(m); 571 error = EOPNOTSUPP; 572 break; 573 574 case PRU_SOCKADDR: 575 in_setsockaddr(inp, nam); 576 break; 577 578 case PRU_PEERADDR: 579 in_setpeeraddr(inp, nam); 580 break; 581 582 default: 583 panic("rip_usrreq"); 584 } 585 586 release: 587 splx(s); 588 return (error); 589 } 590