1 /* $NetBSD: raw_ip.c,v 1.46 1999/09/13 12:15:55 itojun 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 extern u_char ip_protox[]; 99 extern struct protosw inetsw[]; 100 struct inpcbtable rawcbtable; 101 102 int rip_bind __P((struct inpcb *, struct mbuf *)); 103 int rip_connect __P((struct inpcb *, struct mbuf *)); 104 void rip_disconnect __P((struct inpcb *)); 105 106 /* 107 * Nominal space allocated to a raw ip socket. 108 */ 109 #define RIPSNDQ 8192 110 #define RIPRCVQ 8192 111 112 /* 113 * Raw interface to IP protocol. 114 */ 115 116 /* 117 * Initialize raw connection block q. 118 */ 119 void 120 rip_init() 121 { 122 123 in_pcbinit(&rawcbtable, 1, 1); 124 } 125 126 static struct sockaddr_in ripsrc = { sizeof(ripsrc), AF_INET }; 127 128 /* 129 * Setup generic address and protocol structures 130 * for raw_input routine, then pass them along with 131 * mbuf chain. 132 */ 133 void 134 #if __STDC__ 135 rip_input(struct mbuf *m, ...) 136 #else 137 rip_input(m, va_alist) 138 struct mbuf *m; 139 va_dcl 140 #endif 141 { 142 int off, proto; 143 register struct ip *ip = mtod(m, struct ip *); 144 register struct inpcb *inp; 145 struct inpcb *last = 0; 146 struct mbuf *opts = 0; 147 struct sockaddr_in ripsrc; 148 va_list ap; 149 150 va_start(ap, m); 151 off = va_arg(ap, int); 152 proto = va_arg(ap, int); 153 va_end(ap); 154 155 ripsrc.sin_family = AF_INET; 156 ripsrc.sin_len = sizeof(struct sockaddr_in); 157 ripsrc.sin_addr = ip->ip_src; 158 ripsrc.sin_port = 0; 159 bzero((caddr_t)ripsrc.sin_zero, sizeof(ripsrc.sin_zero)); 160 161 /* 162 * XXX Compatibility: programs using raw IP expect ip_len 163 * XXX to have the header length subtracted. 164 */ 165 ip->ip_len -= ip->ip_hl << 2; 166 167 for (inp = rawcbtable.inpt_queue.cqh_first; 168 inp != (struct inpcb *)&rawcbtable.inpt_queue; 169 inp = inp->inp_queue.cqe_next) { 170 if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != proto) 171 continue; 172 if (!in_nullhost(inp->inp_laddr) && 173 !in_hosteq(inp->inp_laddr, ip->ip_dst)) 174 continue; 175 if (!in_nullhost(inp->inp_faddr) && 176 !in_hosteq(inp->inp_faddr, ip->ip_src)) 177 continue; 178 if (last) { 179 struct mbuf *n; 180 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { 181 if (last->inp_flags & INP_CONTROLOPTS || 182 last->inp_socket->so_options & SO_TIMESTAMP) 183 ip_savecontrol(last, &opts, ip, n); 184 if (sbappendaddr(&last->inp_socket->so_rcv, 185 sintosa(&ripsrc), n, opts) == 0) { 186 /* should notify about lost packet */ 187 m_freem(n); 188 if (opts) 189 m_freem(opts); 190 } else 191 sorwakeup(last->inp_socket); 192 opts = NULL; 193 } 194 } 195 last = inp; 196 } 197 if (last) { 198 if (last->inp_flags & INP_CONTROLOPTS || 199 last->inp_socket->so_options & SO_TIMESTAMP) 200 ip_savecontrol(last, &opts, ip, m); 201 if (sbappendaddr(&last->inp_socket->so_rcv, 202 sintosa(&ripsrc), m, opts) == 0) { 203 m_freem(m); 204 if (opts) 205 m_freem(opts); 206 } else 207 sorwakeup(last->inp_socket); 208 } else { 209 if (inetsw[ip_protox[ip->ip_p]].pr_input == rip_input) { 210 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL,0,0); 211 ipstat.ips_noproto++; 212 ipstat.ips_delivered--; 213 } else 214 m_freem(m); 215 } 216 return; 217 } 218 219 /* 220 * Generate IP header and pass packet to ip_output. 221 * Tack on options user may have setup with control call. 222 */ 223 int 224 #if __STDC__ 225 rip_output(struct mbuf *m, ...) 226 #else 227 rip_output(m, va_alist) 228 struct mbuf *m; 229 va_dcl 230 #endif 231 { 232 register struct inpcb *inp; 233 register struct ip *ip; 234 struct mbuf *opts; 235 int flags; 236 va_list ap; 237 238 va_start(ap, m); 239 inp = va_arg(ap, struct inpcb *); 240 va_end(ap); 241 242 flags = 243 (inp->inp_socket->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST 244 | IP_RETURNMTU; 245 246 /* 247 * If the user handed us a complete IP packet, use it. 248 * Otherwise, allocate an mbuf for a header and fill it in. 249 */ 250 if ((inp->inp_flags & INP_HDRINCL) == 0) { 251 if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) { 252 m_freem(m); 253 return (EMSGSIZE); 254 } 255 M_PREPEND(m, sizeof(struct ip), M_WAIT); 256 ip = mtod(m, struct ip *); 257 ip->ip_tos = 0; 258 ip->ip_off = 0; 259 ip->ip_p = inp->inp_ip.ip_p; 260 ip->ip_len = m->m_pkthdr.len; 261 ip->ip_src = inp->inp_laddr; 262 ip->ip_dst = inp->inp_faddr; 263 ip->ip_ttl = MAXTTL; 264 opts = inp->inp_options; 265 } else { 266 if (m->m_pkthdr.len > IP_MAXPACKET) { 267 m_freem(m); 268 return (EMSGSIZE); 269 } 270 ip = mtod(m, struct ip *); 271 if (m->m_pkthdr.len != ip->ip_len) { 272 m_freem(m); 273 return (EINVAL); 274 } 275 if (ip->ip_id == 0) 276 ip->ip_id = htons(ip_id++); 277 opts = NULL; 278 /* XXX prevent ip_output from overwriting header fields */ 279 flags |= IP_RAWOUTPUT; 280 ipstat.ips_rawout++; 281 } 282 #ifdef IPSEC 283 m->m_pkthdr.rcvif = (struct ifnet *)inp->inp_socket; /*XXX*/ 284 #endif /*IPSEC*/ 285 return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions, &inp->inp_errormtu)); 286 } 287 288 /* 289 * Raw IP socket option processing. 290 */ 291 int 292 rip_ctloutput(op, so, level, optname, m) 293 int op; 294 struct socket *so; 295 int level, optname; 296 struct mbuf **m; 297 { 298 register struct inpcb *inp = sotoinpcb(so); 299 int error = 0; 300 301 if (level != IPPROTO_IP) { 302 error = ENOPROTOOPT; 303 if (op == PRCO_SETOPT && *m != 0) 304 (void) m_free(*m); 305 } else switch (op) { 306 307 case PRCO_SETOPT: 308 switch (optname) { 309 case IP_HDRINCL: 310 if (*m == 0 || (*m)->m_len < sizeof (int)) 311 error = EINVAL; 312 else { 313 if (*mtod(*m, int *)) 314 inp->inp_flags |= INP_HDRINCL; 315 else 316 inp->inp_flags &= ~INP_HDRINCL; 317 } 318 if (*m != 0) 319 (void) m_free(*m); 320 break; 321 322 #ifdef MROUTING 323 case MRT_INIT: 324 case MRT_DONE: 325 case MRT_ADD_VIF: 326 case MRT_DEL_VIF: 327 case MRT_ADD_MFC: 328 case MRT_DEL_MFC: 329 case MRT_ASSERT: 330 error = ip_mrouter_set(so, optname, m); 331 break; 332 #endif 333 334 default: 335 error = ip_ctloutput(op, so, level, optname, m); 336 break; 337 } 338 break; 339 340 case PRCO_GETOPT: 341 switch (optname) { 342 case IP_HDRINCL: 343 *m = m_get(M_WAIT, M_SOOPTS); 344 (*m)->m_len = sizeof (int); 345 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL ? 1 : 0; 346 break; 347 348 #ifdef MROUTING 349 case MRT_VERSION: 350 case MRT_ASSERT: 351 error = ip_mrouter_get(so, optname, m); 352 break; 353 #endif 354 355 default: 356 error = ip_ctloutput(op, so, level, optname, m); 357 break; 358 } 359 break; 360 } 361 return (error); 362 } 363 364 int 365 rip_bind(inp, nam) 366 struct inpcb *inp; 367 struct mbuf *nam; 368 { 369 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 370 371 if (nam->m_len != sizeof(*addr)) 372 return (EINVAL); 373 if (ifnet.tqh_first == 0) 374 return (EADDRNOTAVAIL); 375 if (addr->sin_family != AF_INET && 376 addr->sin_family != AF_IMPLINK) 377 return (EAFNOSUPPORT); 378 if (!in_nullhost(addr->sin_addr) && 379 ifa_ifwithaddr(sintosa(addr)) == 0) 380 return (EADDRNOTAVAIL); 381 inp->inp_laddr = addr->sin_addr; 382 return (0); 383 } 384 385 int 386 rip_connect(inp, nam) 387 struct inpcb *inp; 388 struct mbuf *nam; 389 { 390 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 391 392 if (nam->m_len != sizeof(*addr)) 393 return (EINVAL); 394 if (ifnet.tqh_first == 0) 395 return (EADDRNOTAVAIL); 396 if (addr->sin_family != AF_INET && 397 addr->sin_family != AF_IMPLINK) 398 return (EAFNOSUPPORT); 399 inp->inp_faddr = addr->sin_addr; 400 return (0); 401 } 402 403 void 404 rip_disconnect(inp) 405 struct inpcb *inp; 406 { 407 408 inp->inp_faddr = zeroin_addr; 409 } 410 411 u_long rip_sendspace = RIPSNDQ; 412 u_long rip_recvspace = RIPRCVQ; 413 414 /*ARGSUSED*/ 415 int 416 rip_usrreq(so, req, m, nam, control, p) 417 register struct socket *so; 418 int req; 419 struct mbuf *m, *nam, *control; 420 struct proc *p; 421 { 422 register struct inpcb *inp; 423 int s; 424 register int error = 0; 425 #ifdef MROUTING 426 extern struct socket *ip_mrouter; 427 #endif 428 429 if (req == PRU_CONTROL) 430 return (in_control(so, (long)m, (caddr_t)nam, 431 (struct ifnet *)control, p)); 432 433 s = splsoftnet(); 434 inp = sotoinpcb(so); 435 #ifdef DIAGNOSTIC 436 if (req != PRU_SEND && req != PRU_SENDOOB && control) 437 panic("rip_usrreq: unexpected control mbuf"); 438 #endif 439 if (inp == 0 && req != PRU_ATTACH) { 440 error = EINVAL; 441 goto release; 442 } 443 444 switch (req) { 445 446 case PRU_ATTACH: 447 if (inp != 0) { 448 error = EISCONN; 449 break; 450 } 451 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))) { 452 error = EACCES; 453 break; 454 } 455 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 456 error = soreserve(so, rip_sendspace, rip_recvspace); 457 if (error) 458 break; 459 } 460 error = in_pcballoc(so, &rawcbtable); 461 if (error) 462 break; 463 inp = sotoinpcb(so); 464 inp->inp_ip.ip_p = (long)nam; 465 #ifdef IPSEC 466 if ((error = ipsec_init_policy(&inp->inp_sp)) != 0) 467 in_pcbdetach(inp); 468 #endif /*IPSEC*/ 469 break; 470 471 case PRU_DETACH: 472 #ifdef MROUTING 473 if (so == ip_mrouter) 474 ip_mrouter_done(); 475 #endif 476 in_pcbdetach(inp); 477 break; 478 479 case PRU_BIND: 480 error = rip_bind(inp, nam); 481 break; 482 483 case PRU_LISTEN: 484 error = EOPNOTSUPP; 485 break; 486 487 case PRU_CONNECT: 488 error = rip_connect(inp, nam); 489 if (error) 490 break; 491 soisconnected(so); 492 break; 493 494 case PRU_CONNECT2: 495 error = EOPNOTSUPP; 496 break; 497 498 case PRU_DISCONNECT: 499 soisdisconnected(so); 500 rip_disconnect(inp); 501 break; 502 503 /* 504 * Mark the connection as being incapable of further input. 505 */ 506 case PRU_SHUTDOWN: 507 socantsendmore(so); 508 break; 509 510 case PRU_RCVD: 511 error = EOPNOTSUPP; 512 break; 513 514 /* 515 * Ship a packet out. The appropriate raw output 516 * routine handles any massaging necessary. 517 */ 518 case PRU_SEND: 519 if (control && control->m_len) { 520 m_freem(control); 521 m_freem(m); 522 error = EINVAL; 523 break; 524 } 525 { 526 if (nam) { 527 if ((so->so_state & SS_ISCONNECTED) != 0) { 528 error = EISCONN; 529 goto die; 530 } 531 error = rip_connect(inp, nam); 532 if (error) { 533 die: 534 m_freem(m); 535 break; 536 } 537 } else { 538 if ((so->so_state & SS_ISCONNECTED) == 0) { 539 error = ENOTCONN; 540 goto die; 541 } 542 } 543 error = rip_output(m, inp); 544 if (nam) 545 rip_disconnect(inp); 546 } 547 break; 548 549 case PRU_SENSE: 550 /* 551 * stat: don't bother with a blocksize. 552 */ 553 splx(s); 554 return (0); 555 556 case PRU_RCVOOB: 557 error = EOPNOTSUPP; 558 break; 559 560 case PRU_SENDOOB: 561 m_freem(control); 562 m_freem(m); 563 error = EOPNOTSUPP; 564 break; 565 566 case PRU_SOCKADDR: 567 in_setsockaddr(inp, nam); 568 break; 569 570 case PRU_PEERADDR: 571 in_setpeeraddr(inp, nam); 572 break; 573 574 default: 575 panic("rip_usrreq"); 576 } 577 578 release: 579 splx(s); 580 return (error); 581 } 582