1 /* $NetBSD: raw_ip.c,v 1.47 1999/12/13 15:17:20 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, 211 0, 0); 212 ipstat.ips_noproto++; 213 ipstat.ips_delivered--; 214 } else 215 m_freem(m); 216 } 217 return; 218 } 219 220 /* 221 * Generate IP header and pass packet to ip_output. 222 * Tack on options user may have setup with control call. 223 */ 224 int 225 #if __STDC__ 226 rip_output(struct mbuf *m, ...) 227 #else 228 rip_output(m, va_alist) 229 struct mbuf *m; 230 va_dcl 231 #endif 232 { 233 register struct inpcb *inp; 234 register struct ip *ip; 235 struct mbuf *opts; 236 int flags; 237 va_list ap; 238 239 va_start(ap, m); 240 inp = va_arg(ap, struct inpcb *); 241 va_end(ap); 242 243 flags = 244 (inp->inp_socket->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST 245 | IP_RETURNMTU; 246 247 /* 248 * If the user handed us a complete IP packet, use it. 249 * Otherwise, allocate an mbuf for a header and fill it in. 250 */ 251 if ((inp->inp_flags & INP_HDRINCL) == 0) { 252 if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) { 253 m_freem(m); 254 return (EMSGSIZE); 255 } 256 M_PREPEND(m, sizeof(struct ip), M_WAIT); 257 ip = mtod(m, struct ip *); 258 ip->ip_tos = 0; 259 ip->ip_off = 0; 260 ip->ip_p = inp->inp_ip.ip_p; 261 ip->ip_len = m->m_pkthdr.len; 262 ip->ip_src = inp->inp_laddr; 263 ip->ip_dst = inp->inp_faddr; 264 ip->ip_ttl = MAXTTL; 265 opts = inp->inp_options; 266 } else { 267 if (m->m_pkthdr.len > IP_MAXPACKET) { 268 m_freem(m); 269 return (EMSGSIZE); 270 } 271 ip = mtod(m, struct ip *); 272 if (m->m_pkthdr.len != ip->ip_len) { 273 m_freem(m); 274 return (EINVAL); 275 } 276 if (ip->ip_id == 0) 277 ip->ip_id = htons(ip_id++); 278 opts = NULL; 279 /* XXX prevent ip_output from overwriting header fields */ 280 flags |= IP_RAWOUTPUT; 281 ipstat.ips_rawout++; 282 } 283 #ifdef IPSEC 284 m->m_pkthdr.rcvif = (struct ifnet *)inp->inp_socket; /*XXX*/ 285 #endif /*IPSEC*/ 286 return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions, &inp->inp_errormtu)); 287 } 288 289 /* 290 * Raw IP socket option processing. 291 */ 292 int 293 rip_ctloutput(op, so, level, optname, m) 294 int op; 295 struct socket *so; 296 int level, optname; 297 struct mbuf **m; 298 { 299 register struct inpcb *inp = sotoinpcb(so); 300 int error = 0; 301 302 if (level != IPPROTO_IP) { 303 error = ENOPROTOOPT; 304 if (op == PRCO_SETOPT && *m != 0) 305 (void) m_free(*m); 306 } else switch (op) { 307 308 case PRCO_SETOPT: 309 switch (optname) { 310 case IP_HDRINCL: 311 if (*m == 0 || (*m)->m_len < sizeof (int)) 312 error = EINVAL; 313 else { 314 if (*mtod(*m, int *)) 315 inp->inp_flags |= INP_HDRINCL; 316 else 317 inp->inp_flags &= ~INP_HDRINCL; 318 } 319 if (*m != 0) 320 (void) m_free(*m); 321 break; 322 323 #ifdef MROUTING 324 case MRT_INIT: 325 case MRT_DONE: 326 case MRT_ADD_VIF: 327 case MRT_DEL_VIF: 328 case MRT_ADD_MFC: 329 case MRT_DEL_MFC: 330 case MRT_ASSERT: 331 error = ip_mrouter_set(so, optname, m); 332 break; 333 #endif 334 335 default: 336 error = ip_ctloutput(op, so, level, optname, m); 337 break; 338 } 339 break; 340 341 case PRCO_GETOPT: 342 switch (optname) { 343 case IP_HDRINCL: 344 *m = m_get(M_WAIT, M_SOOPTS); 345 (*m)->m_len = sizeof (int); 346 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL ? 1 : 0; 347 break; 348 349 #ifdef MROUTING 350 case MRT_VERSION: 351 case MRT_ASSERT: 352 error = ip_mrouter_get(so, optname, m); 353 break; 354 #endif 355 356 default: 357 error = ip_ctloutput(op, so, level, optname, m); 358 break; 359 } 360 break; 361 } 362 return (error); 363 } 364 365 int 366 rip_bind(inp, nam) 367 struct inpcb *inp; 368 struct mbuf *nam; 369 { 370 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 371 372 if (nam->m_len != sizeof(*addr)) 373 return (EINVAL); 374 if (ifnet.tqh_first == 0) 375 return (EADDRNOTAVAIL); 376 if (addr->sin_family != AF_INET && 377 addr->sin_family != AF_IMPLINK) 378 return (EAFNOSUPPORT); 379 if (!in_nullhost(addr->sin_addr) && 380 ifa_ifwithaddr(sintosa(addr)) == 0) 381 return (EADDRNOTAVAIL); 382 inp->inp_laddr = addr->sin_addr; 383 return (0); 384 } 385 386 int 387 rip_connect(inp, nam) 388 struct inpcb *inp; 389 struct mbuf *nam; 390 { 391 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 392 393 if (nam->m_len != sizeof(*addr)) 394 return (EINVAL); 395 if (ifnet.tqh_first == 0) 396 return (EADDRNOTAVAIL); 397 if (addr->sin_family != AF_INET && 398 addr->sin_family != AF_IMPLINK) 399 return (EAFNOSUPPORT); 400 inp->inp_faddr = addr->sin_addr; 401 return (0); 402 } 403 404 void 405 rip_disconnect(inp) 406 struct inpcb *inp; 407 { 408 409 inp->inp_faddr = zeroin_addr; 410 } 411 412 u_long rip_sendspace = RIPSNDQ; 413 u_long rip_recvspace = RIPRCVQ; 414 415 /*ARGSUSED*/ 416 int 417 rip_usrreq(so, req, m, nam, control, p) 418 register struct socket *so; 419 int req; 420 struct mbuf *m, *nam, *control; 421 struct proc *p; 422 { 423 register struct inpcb *inp; 424 int s; 425 register int error = 0; 426 #ifdef MROUTING 427 extern struct socket *ip_mrouter; 428 #endif 429 430 if (req == PRU_CONTROL) 431 return (in_control(so, (long)m, (caddr_t)nam, 432 (struct ifnet *)control, p)); 433 434 s = splsoftnet(); 435 inp = sotoinpcb(so); 436 #ifdef DIAGNOSTIC 437 if (req != PRU_SEND && req != PRU_SENDOOB && control) 438 panic("rip_usrreq: unexpected control mbuf"); 439 #endif 440 if (inp == 0 && req != PRU_ATTACH) { 441 error = EINVAL; 442 goto release; 443 } 444 445 switch (req) { 446 447 case PRU_ATTACH: 448 if (inp != 0) { 449 error = EISCONN; 450 break; 451 } 452 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))) { 453 error = EACCES; 454 break; 455 } 456 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 457 error = soreserve(so, rip_sendspace, rip_recvspace); 458 if (error) 459 break; 460 } 461 error = in_pcballoc(so, &rawcbtable); 462 if (error) 463 break; 464 inp = sotoinpcb(so); 465 inp->inp_ip.ip_p = (long)nam; 466 #ifdef IPSEC 467 error = ipsec_init_policy(&inp->inp_sp); 468 if (error != 0) { 469 in_pcbdetach(inp); 470 break; 471 } 472 #endif /*IPSEC*/ 473 break; 474 475 case PRU_DETACH: 476 #ifdef MROUTING 477 if (so == ip_mrouter) 478 ip_mrouter_done(); 479 #endif 480 in_pcbdetach(inp); 481 break; 482 483 case PRU_BIND: 484 error = rip_bind(inp, nam); 485 break; 486 487 case PRU_LISTEN: 488 error = EOPNOTSUPP; 489 break; 490 491 case PRU_CONNECT: 492 error = rip_connect(inp, nam); 493 if (error) 494 break; 495 soisconnected(so); 496 break; 497 498 case PRU_CONNECT2: 499 error = EOPNOTSUPP; 500 break; 501 502 case PRU_DISCONNECT: 503 soisdisconnected(so); 504 rip_disconnect(inp); 505 break; 506 507 /* 508 * Mark the connection as being incapable of further input. 509 */ 510 case PRU_SHUTDOWN: 511 socantsendmore(so); 512 break; 513 514 case PRU_RCVD: 515 error = EOPNOTSUPP; 516 break; 517 518 /* 519 * Ship a packet out. The appropriate raw output 520 * routine handles any massaging necessary. 521 */ 522 case PRU_SEND: 523 if (control && control->m_len) { 524 m_freem(control); 525 m_freem(m); 526 error = EINVAL; 527 break; 528 } 529 { 530 if (nam) { 531 if ((so->so_state & SS_ISCONNECTED) != 0) { 532 error = EISCONN; 533 goto die; 534 } 535 error = rip_connect(inp, nam); 536 if (error) { 537 die: 538 m_freem(m); 539 break; 540 } 541 } else { 542 if ((so->so_state & SS_ISCONNECTED) == 0) { 543 error = ENOTCONN; 544 goto die; 545 } 546 } 547 error = rip_output(m, inp); 548 if (nam) 549 rip_disconnect(inp); 550 } 551 break; 552 553 case PRU_SENSE: 554 /* 555 * stat: don't bother with a blocksize. 556 */ 557 splx(s); 558 return (0); 559 560 case PRU_RCVOOB: 561 error = EOPNOTSUPP; 562 break; 563 564 case PRU_SENDOOB: 565 m_freem(control); 566 m_freem(m); 567 error = EOPNOTSUPP; 568 break; 569 570 case PRU_SOCKADDR: 571 in_setsockaddr(inp, nam); 572 break; 573 574 case PRU_PEERADDR: 575 in_setpeeraddr(inp, nam); 576 break; 577 578 default: 579 panic("rip_usrreq"); 580 } 581 582 release: 583 splx(s); 584 return (error); 585 } 586