1 /* $NetBSD: raw_ip.c,v 1.86 2005/03/11 06:16:16 atatat 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. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 * 60 * @(#)raw_ip.c 8.7 (Berkeley) 5/15/95 61 */ 62 63 #include <sys/cdefs.h> 64 __KERNEL_RCSID(0, "$NetBSD: raw_ip.c,v 1.86 2005/03/11 06:16:16 atatat Exp $"); 65 66 #include "opt_inet.h" 67 #include "opt_ipsec.h" 68 #include "opt_mrouting.h" 69 70 #include <sys/param.h> 71 #include <sys/sysctl.h> 72 #include <sys/malloc.h> 73 #include <sys/mbuf.h> 74 #include <sys/socket.h> 75 #include <sys/protosw.h> 76 #include <sys/socketvar.h> 77 #include <sys/errno.h> 78 #include <sys/systm.h> 79 #include <sys/proc.h> 80 81 #include <net/if.h> 82 #include <net/route.h> 83 84 #include <netinet/in.h> 85 #include <netinet/in_systm.h> 86 #include <netinet/ip.h> 87 #include <netinet/ip_var.h> 88 #include <netinet/ip_mroute.h> 89 #include <netinet/ip_icmp.h> 90 #include <netinet/in_pcb.h> 91 #include <netinet/in_var.h> 92 93 #include <machine/stdarg.h> 94 95 #ifdef IPSEC 96 #include <netinet6/ipsec.h> 97 #endif /*IPSEC*/ 98 99 #ifdef FAST_IPSEC 100 #include <netipsec/ipsec.h> 101 #include <netipsec/ipsec_var.h> /* XXX ipsecstat namespace */ 102 #endif /* FAST_IPSEC*/ 103 104 struct inpcbtable rawcbtable; 105 106 int rip_pcbnotify(struct inpcbtable *, struct in_addr, 107 struct in_addr, int, int, void (*)(struct inpcb *, int)); 108 int rip_bind(struct inpcb *, struct mbuf *); 109 int rip_connect(struct inpcb *, struct mbuf *); 110 void rip_disconnect(struct inpcb *); 111 112 /* 113 * Nominal space allocated to a raw ip socket. 114 */ 115 #define RIPSNDQ 8192 116 #define RIPRCVQ 8192 117 118 /* 119 * Raw interface to IP protocol. 120 */ 121 122 /* 123 * Initialize raw connection block q. 124 */ 125 void 126 rip_init(void) 127 { 128 129 in_pcbinit(&rawcbtable, 1, 1); 130 } 131 132 /* 133 * Setup generic address and protocol structures 134 * for raw_input routine, then pass them along with 135 * mbuf chain. 136 */ 137 void 138 rip_input(struct mbuf *m, ...) 139 { 140 int proto; 141 struct ip *ip = mtod(m, struct ip *); 142 struct inpcb_hdr *inph; 143 struct inpcb *inp; 144 struct inpcb *last = 0; 145 struct mbuf *opts = 0; 146 struct sockaddr_in ripsrc; 147 va_list ap; 148 149 va_start(ap, m); 150 (void)va_arg(ap, int); /* ignore value, advance ap */ 151 proto = va_arg(ap, int); 152 va_end(ap); 153 154 ripsrc.sin_family = AF_INET; 155 ripsrc.sin_len = sizeof(struct sockaddr_in); 156 ripsrc.sin_addr = ip->ip_src; 157 ripsrc.sin_port = 0; 158 bzero((caddr_t)ripsrc.sin_zero, sizeof(ripsrc.sin_zero)); 159 160 /* 161 * XXX Compatibility: programs using raw IP expect ip_len 162 * XXX to have the header length subtracted, and in host order. 163 * XXX ip_off is also expected to be host order. 164 */ 165 ip->ip_len = ntohs(ip->ip_len) - (ip->ip_hl << 2); 166 NTOHS(ip->ip_off); 167 168 CIRCLEQ_FOREACH(inph, &rawcbtable.inpt_queue, inph_queue) { 169 inp = (struct inpcb *)inph; 170 if (inp->inp_af != AF_INET) 171 continue; 172 if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != proto) 173 continue; 174 if (!in_nullhost(inp->inp_laddr) && 175 !in_hosteq(inp->inp_laddr, ip->ip_dst)) 176 continue; 177 if (!in_nullhost(inp->inp_faddr) && 178 !in_hosteq(inp->inp_faddr, ip->ip_src)) 179 continue; 180 if (last) { 181 struct mbuf *n; 182 183 #if defined(IPSEC) || defined(FAST_IPSEC) 184 /* check AH/ESP integrity. */ 185 if (ipsec4_in_reject_so(m, last->inp_socket)) { 186 ipsecstat.in_polvio++; 187 /* do not inject data to pcb */ 188 } else 189 #endif /*IPSEC*/ 190 if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { 191 if (last->inp_flags & INP_CONTROLOPTS || 192 last->inp_socket->so_options & SO_TIMESTAMP) 193 ip_savecontrol(last, &opts, ip, n); 194 if (sbappendaddr(&last->inp_socket->so_rcv, 195 sintosa(&ripsrc), n, opts) == 0) { 196 /* should notify about lost packet */ 197 m_freem(n); 198 if (opts) 199 m_freem(opts); 200 } else 201 sorwakeup(last->inp_socket); 202 opts = NULL; 203 } 204 } 205 last = inp; 206 } 207 #if defined(IPSEC) || defined(FAST_IPSEC) 208 /* check AH/ESP integrity. */ 209 if (last && ipsec4_in_reject_so(m, last->inp_socket)) { 210 m_freem(m); 211 ipsecstat.in_polvio++; 212 ipstat.ips_delivered--; 213 /* do not inject data to pcb */ 214 } else 215 #endif /*IPSEC*/ 216 if (last) { 217 if (last->inp_flags & INP_CONTROLOPTS || 218 last->inp_socket->so_options & SO_TIMESTAMP) 219 ip_savecontrol(last, &opts, ip, m); 220 if (sbappendaddr(&last->inp_socket->so_rcv, 221 sintosa(&ripsrc), m, opts) == 0) { 222 m_freem(m); 223 if (opts) 224 m_freem(opts); 225 } else 226 sorwakeup(last->inp_socket); 227 } else { 228 if (inetsw[ip_protox[ip->ip_p]].pr_input == rip_input) { 229 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 230 0, 0); 231 ipstat.ips_noproto++; 232 ipstat.ips_delivered--; 233 } else 234 m_freem(m); 235 } 236 return; 237 } 238 239 int 240 rip_pcbnotify(struct inpcbtable *table, 241 struct in_addr faddr, struct in_addr laddr, int proto, int errno, 242 void (*notify)(struct inpcb *, int)) 243 { 244 struct inpcb *inp, *ninp; 245 int nmatch; 246 247 nmatch = 0; 248 for (inp = (struct inpcb *)CIRCLEQ_FIRST(&table->inpt_queue); 249 inp != (struct inpcb *)&table->inpt_queue; 250 inp = ninp) { 251 ninp = (struct inpcb *)inp->inp_queue.cqe_next; 252 if (inp->inp_af != AF_INET) 253 continue; 254 if (inp->inp_ip.ip_p && inp->inp_ip.ip_p != proto) 255 continue; 256 if (in_hosteq(inp->inp_faddr, faddr) && 257 in_hosteq(inp->inp_laddr, laddr)) { 258 (*notify)(inp, errno); 259 nmatch++; 260 } 261 } 262 263 return nmatch; 264 } 265 266 void * 267 rip_ctlinput(int cmd, struct sockaddr *sa, void *v) 268 { 269 struct ip *ip = v; 270 void (*notify)(struct inpcb *, int) = in_rtchange; 271 int errno; 272 273 if (sa->sa_family != AF_INET || 274 sa->sa_len != sizeof(struct sockaddr_in)) 275 return NULL; 276 if ((unsigned)cmd >= PRC_NCMDS) 277 return NULL; 278 errno = inetctlerrmap[cmd]; 279 if (PRC_IS_REDIRECT(cmd)) 280 notify = in_rtchange, ip = 0; 281 else if (cmd == PRC_HOSTDEAD) 282 ip = 0; 283 else if (errno == 0) 284 return NULL; 285 if (ip) { 286 rip_pcbnotify(&rawcbtable, satosin(sa)->sin_addr, 287 ip->ip_src, ip->ip_p, errno, notify); 288 289 /* XXX mapped address case */ 290 } else 291 in_pcbnotifyall(&rawcbtable, satosin(sa)->sin_addr, errno, 292 notify); 293 return NULL; 294 } 295 296 /* 297 * Generate IP header and pass packet to ip_output. 298 * Tack on options user may have setup with control call. 299 */ 300 int 301 rip_output(struct mbuf *m, ...) 302 { 303 struct inpcb *inp; 304 struct ip *ip; 305 struct mbuf *opts; 306 int flags; 307 va_list ap; 308 309 va_start(ap, m); 310 inp = va_arg(ap, struct inpcb *); 311 va_end(ap); 312 313 flags = 314 (inp->inp_socket->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST 315 | IP_RETURNMTU; 316 317 /* 318 * If the user handed us a complete IP packet, use it. 319 * Otherwise, allocate an mbuf for a header and fill it in. 320 */ 321 if ((inp->inp_flags & INP_HDRINCL) == 0) { 322 if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) { 323 m_freem(m); 324 return (EMSGSIZE); 325 } 326 M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 327 if (!m) 328 return (ENOBUFS); 329 ip = mtod(m, struct ip *); 330 ip->ip_tos = 0; 331 ip->ip_off = htons(0); 332 ip->ip_p = inp->inp_ip.ip_p; 333 ip->ip_len = htons(m->m_pkthdr.len); 334 ip->ip_src = inp->inp_laddr; 335 ip->ip_dst = inp->inp_faddr; 336 ip->ip_ttl = MAXTTL; 337 opts = inp->inp_options; 338 } else { 339 if (m->m_pkthdr.len > IP_MAXPACKET) { 340 m_freem(m); 341 return (EMSGSIZE); 342 } 343 ip = mtod(m, struct ip *); 344 345 /* 346 * If the mbuf is read-only, we need to allocate 347 * a new mbuf for the header, since we need to 348 * modify the header. 349 */ 350 if (M_READONLY(m)) { 351 int hlen = ip->ip_hl << 2; 352 353 m = m_copyup(m, hlen, (max_linkhdr + 3) & ~3); 354 if (m == NULL) 355 return (ENOMEM); /* XXX */ 356 ip = mtod(m, struct ip *); 357 } 358 359 /* XXX userland passes ip_len and ip_off in host order */ 360 if (m->m_pkthdr.len != ip->ip_len) { 361 m_freem(m); 362 return (EINVAL); 363 } 364 HTONS(ip->ip_len); 365 HTONS(ip->ip_off); 366 if (ip->ip_id == 0) 367 ip->ip_id = ip_newid(); 368 opts = NULL; 369 /* XXX prevent ip_output from overwriting header fields */ 370 flags |= IP_RAWOUTPUT; 371 ipstat.ips_rawout++; 372 } 373 return (ip_output(m, opts, &inp->inp_route, flags, inp->inp_moptions, 374 inp->inp_socket, &inp->inp_errormtu)); 375 } 376 377 /* 378 * Raw IP socket option processing. 379 */ 380 int 381 rip_ctloutput(int op, struct socket *so, int level, int optname, 382 struct mbuf **m) 383 { 384 struct inpcb *inp = sotoinpcb(so); 385 int error = 0; 386 387 if (level != IPPROTO_IP) { 388 error = ENOPROTOOPT; 389 if (op == PRCO_SETOPT && *m != 0) 390 (void) m_free(*m); 391 } else switch (op) { 392 393 case PRCO_SETOPT: 394 switch (optname) { 395 case IP_HDRINCL: 396 if (*m == 0 || (*m)->m_len < sizeof (int)) 397 error = EINVAL; 398 else { 399 if (*mtod(*m, int *)) 400 inp->inp_flags |= INP_HDRINCL; 401 else 402 inp->inp_flags &= ~INP_HDRINCL; 403 } 404 if (*m != 0) 405 (void) m_free(*m); 406 break; 407 408 #ifdef MROUTING 409 case MRT_INIT: 410 case MRT_DONE: 411 case MRT_ADD_VIF: 412 case MRT_DEL_VIF: 413 case MRT_ADD_MFC: 414 case MRT_DEL_MFC: 415 case MRT_ASSERT: 416 case MRT_API_CONFIG: 417 case MRT_ADD_BW_UPCALL: 418 case MRT_DEL_BW_UPCALL: 419 error = ip_mrouter_set(so, optname, m); 420 break; 421 #endif 422 423 default: 424 error = ip_ctloutput(op, so, level, optname, m); 425 break; 426 } 427 break; 428 429 case PRCO_GETOPT: 430 switch (optname) { 431 case IP_HDRINCL: 432 *m = m_get(M_WAIT, MT_SOOPTS); 433 MCLAIM((*m), so->so_mowner); 434 (*m)->m_len = sizeof (int); 435 *mtod(*m, int *) = inp->inp_flags & INP_HDRINCL ? 1 : 0; 436 break; 437 438 #ifdef MROUTING 439 case MRT_VERSION: 440 case MRT_ASSERT: 441 case MRT_API_SUPPORT: 442 case MRT_API_CONFIG: 443 error = ip_mrouter_get(so, optname, m); 444 break; 445 #endif 446 447 default: 448 error = ip_ctloutput(op, so, level, optname, m); 449 break; 450 } 451 break; 452 } 453 return (error); 454 } 455 456 int 457 rip_bind(struct inpcb *inp, struct mbuf *nam) 458 { 459 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 460 461 if (nam->m_len != sizeof(*addr)) 462 return (EINVAL); 463 if (TAILQ_FIRST(&ifnet) == 0) 464 return (EADDRNOTAVAIL); 465 if (addr->sin_family != AF_INET && 466 addr->sin_family != AF_IMPLINK) 467 return (EAFNOSUPPORT); 468 if (!in_nullhost(addr->sin_addr) && 469 ifa_ifwithaddr(sintosa(addr)) == 0) 470 return (EADDRNOTAVAIL); 471 inp->inp_laddr = addr->sin_addr; 472 return (0); 473 } 474 475 int 476 rip_connect(struct inpcb *inp, struct mbuf *nam) 477 { 478 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); 479 480 if (nam->m_len != sizeof(*addr)) 481 return (EINVAL); 482 if (TAILQ_FIRST(&ifnet) == 0) 483 return (EADDRNOTAVAIL); 484 if (addr->sin_family != AF_INET && 485 addr->sin_family != AF_IMPLINK) 486 return (EAFNOSUPPORT); 487 inp->inp_faddr = addr->sin_addr; 488 return (0); 489 } 490 491 void 492 rip_disconnect(struct inpcb *inp) 493 { 494 495 inp->inp_faddr = zeroin_addr; 496 } 497 498 u_long rip_sendspace = RIPSNDQ; 499 u_long rip_recvspace = RIPRCVQ; 500 501 /*ARGSUSED*/ 502 int 503 rip_usrreq(struct socket *so, int req, 504 struct mbuf *m, struct mbuf *nam, struct mbuf *control, struct proc *p) 505 { 506 struct inpcb *inp; 507 int s; 508 int error = 0; 509 #ifdef MROUTING 510 extern struct socket *ip_mrouter; 511 #endif 512 513 if (req == PRU_CONTROL) 514 return (in_control(so, (long)m, (caddr_t)nam, 515 (struct ifnet *)control, p)); 516 517 if (req == PRU_PURGEIF) { 518 in_pcbpurgeif0(&rawcbtable, (struct ifnet *)control); 519 in_purgeif((struct ifnet *)control); 520 in_pcbpurgeif(&rawcbtable, (struct ifnet *)control); 521 return (0); 522 } 523 524 s = splsoftnet(); 525 inp = sotoinpcb(so); 526 #ifdef DIAGNOSTIC 527 if (req != PRU_SEND && req != PRU_SENDOOB && control) 528 panic("rip_usrreq: unexpected control mbuf"); 529 #endif 530 if (inp == 0 && req != PRU_ATTACH) { 531 error = EINVAL; 532 goto release; 533 } 534 535 switch (req) { 536 537 case PRU_ATTACH: 538 if (inp != 0) { 539 error = EISCONN; 540 break; 541 } 542 if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))) { 543 error = EACCES; 544 break; 545 } 546 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 547 error = soreserve(so, rip_sendspace, rip_recvspace); 548 if (error) 549 break; 550 } 551 error = in_pcballoc(so, &rawcbtable); 552 if (error) 553 break; 554 inp = sotoinpcb(so); 555 inp->inp_ip.ip_p = (long)nam; 556 break; 557 558 case PRU_DETACH: 559 #ifdef MROUTING 560 if (so == ip_mrouter) 561 ip_mrouter_done(); 562 #endif 563 in_pcbdetach(inp); 564 break; 565 566 case PRU_BIND: 567 error = rip_bind(inp, nam); 568 break; 569 570 case PRU_LISTEN: 571 error = EOPNOTSUPP; 572 break; 573 574 case PRU_CONNECT: 575 error = rip_connect(inp, nam); 576 if (error) 577 break; 578 soisconnected(so); 579 break; 580 581 case PRU_CONNECT2: 582 error = EOPNOTSUPP; 583 break; 584 585 case PRU_DISCONNECT: 586 soisdisconnected(so); 587 rip_disconnect(inp); 588 break; 589 590 /* 591 * Mark the connection as being incapable of further input. 592 */ 593 case PRU_SHUTDOWN: 594 socantsendmore(so); 595 break; 596 597 case PRU_RCVD: 598 error = EOPNOTSUPP; 599 break; 600 601 /* 602 * Ship a packet out. The appropriate raw output 603 * routine handles any massaging necessary. 604 */ 605 case PRU_SEND: 606 if (control && control->m_len) { 607 m_freem(control); 608 m_freem(m); 609 error = EINVAL; 610 break; 611 } 612 { 613 if (nam) { 614 if ((so->so_state & SS_ISCONNECTED) != 0) { 615 error = EISCONN; 616 goto die; 617 } 618 error = rip_connect(inp, nam); 619 if (error) { 620 die: 621 m_freem(m); 622 break; 623 } 624 } else { 625 if ((so->so_state & SS_ISCONNECTED) == 0) { 626 error = ENOTCONN; 627 goto die; 628 } 629 } 630 error = rip_output(m, inp); 631 if (nam) 632 rip_disconnect(inp); 633 } 634 break; 635 636 case PRU_SENSE: 637 /* 638 * stat: don't bother with a blocksize. 639 */ 640 splx(s); 641 return (0); 642 643 case PRU_RCVOOB: 644 error = EOPNOTSUPP; 645 break; 646 647 case PRU_SENDOOB: 648 m_freem(control); 649 m_freem(m); 650 error = EOPNOTSUPP; 651 break; 652 653 case PRU_SOCKADDR: 654 in_setsockaddr(inp, nam); 655 break; 656 657 case PRU_PEERADDR: 658 in_setpeeraddr(inp, nam); 659 break; 660 661 default: 662 panic("rip_usrreq"); 663 } 664 665 release: 666 splx(s); 667 return (error); 668 } 669 670 SYSCTL_SETUP(sysctl_net_inet_raw_setup, "sysctl net.inet.raw subtree setup") 671 { 672 673 sysctl_createv(clog, 0, NULL, NULL, 674 CTLFLAG_PERMANENT, 675 CTLTYPE_NODE, "net", NULL, 676 NULL, 0, NULL, 0, 677 CTL_NET, CTL_EOL); 678 sysctl_createv(clog, 0, NULL, NULL, 679 CTLFLAG_PERMANENT, 680 CTLTYPE_NODE, "inet", NULL, 681 NULL, 0, NULL, 0, 682 CTL_NET, PF_INET, CTL_EOL); 683 sysctl_createv(clog, 0, NULL, NULL, 684 CTLFLAG_PERMANENT, 685 CTLTYPE_NODE, "raw", 686 SYSCTL_DESCR("Raw IPv4 settings"), 687 NULL, 0, NULL, 0, 688 CTL_NET, PF_INET, IPPROTO_RAW, CTL_EOL); 689 690 sysctl_createv(clog, 0, NULL, NULL, 691 CTLFLAG_PERMANENT, 692 CTLTYPE_STRUCT, "pcblist", 693 SYSCTL_DESCR("Raw IPv4 control block list"), 694 sysctl_inpcblist, 0, &rawcbtable, 0, 695 CTL_NET, PF_INET, IPPROTO_RAW, 696 CTL_CREATE, CTL_EOL); 697 } 698