raw_ip.c revision 1.116.2.4 1 /* $NetBSD: raw_ip.c,v 1.116.2.4 2014/05/18 17:46:13 rmind 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 /*
64 * Raw interface to IP protocol.
65 */
66
67 #include <sys/cdefs.h>
68 __KERNEL_RCSID(0, "$NetBSD: raw_ip.c,v 1.116.2.4 2014/05/18 17:46:13 rmind Exp $");
69
70 #include "opt_inet.h"
71 #include "opt_compat_netbsd.h"
72 #include "opt_ipsec.h"
73 #include "opt_mrouting.h"
74
75 #include <sys/param.h>
76 #include <sys/sysctl.h>
77 #include <sys/mbuf.h>
78 #include <sys/socket.h>
79 #include <sys/protosw.h>
80 #include <sys/socketvar.h>
81 #include <sys/systm.h>
82 #include <sys/kauth.h>
83
84 #include <net/if.h>
85 #include <net/route.h>
86
87 #include <netinet/in.h>
88 #include <netinet/in_systm.h>
89 #include <netinet/ip.h>
90 #include <netinet/ip_var.h>
91 #include <netinet/ip_private.h>
92 #include <netinet/ip_mroute.h>
93 #include <netinet/ip_icmp.h>
94 #include <netinet/in_pcb.h>
95 #include <netinet/in_proto.h>
96 #include <netinet/in_var.h>
97
98 #ifdef IPSEC
99 #include <netipsec/ipsec.h>
100 #include <netipsec/ipsec_var.h>
101 #include <netipsec/ipsec_private.h>
102 #endif
103
104 #ifdef COMPAT_50
105 #include <compat/sys/socket.h>
106 #endif
107
108 static inpcbtable_t * rawcbtable __read_mostly;
109
110 static void sysctl_net_inet_raw_setup(struct sysctllog **);
111
112 /*
113 * Nominal space allocated to a raw ip socket.
114 */
115 #define RIPSNDQ 8192
116 #define RIPRCVQ 8192
117
118 static u_long rip_sendspace = RIPSNDQ;
119 static u_long rip_recvspace = RIPRCVQ;
120
121 struct rip_input_ctx {
122 struct mbuf * mbuf;
123 struct ip * ip;
124 struct sockaddr_in src;
125 unsigned hlen;
126 unsigned nfound;
127 };
128
129 struct rip_ctlinput_ctx {
130 struct ip * ip;
131 struct in_addr addr;
132 int errno;
133 };
134
135 void
136 rip_init(void)
137 {
138 rawcbtable = inpcb_init(1, 1, 0);
139 sysctl_net_inet_raw_setup(NULL);
140 }
141
142 /*
143 * rip_append: pass the received datagram to the process.
144 */
145 static void
146 rip_append(inpcb_t *inp, struct rip_input_ctx *rctx)
147 {
148 struct socket *so = inpcb_get_socket(inp);
149 int inpflags = inpcb_get_flags(inp);
150 struct mbuf *n, *opts = NULL;
151
152 /* XXX: Might optimise this, but not with a silly loop! */
153 if ((n = m_copypacket(rctx->mbuf, M_DONTWAIT)) == NULL) {
154 return;
155 }
156
157 if (inpflags & INP_NOHEADER) {
158 m_adj(n, rctx->hlen);
159 }
160
161 if ((inpflags & INP_CONTROLOPTS) != 0
162 #ifdef SO_OTIMESTAMP
163 || (so->so_options & SO_OTIMESTAMP) != 0
164 #endif
165 || (so->so_options & SO_TIMESTAMP) != 0) {
166 struct ip *ip = rctx->ip;
167 ip_savecontrol(inp, &opts, ip, n);
168 }
169
170 if (sbappendaddr(&so->so_rcv, sintosa(&rctx->src), n, opts) == 0) {
171 /* Should notify about lost packet. */
172 if (opts) {
173 m_freem(opts);
174 }
175 m_freem(n);
176 } else {
177 sorwakeup(so);
178 }
179 }
180
181 static int
182 rip_pcb_process(inpcb_t *inp, void *arg)
183 {
184 struct rip_input_ctx *rctx = arg;
185 const struct ip *ip = rctx->ip;
186 struct ip *inp_ip = in_getiphdr(inp);
187 struct in_addr laddr, faddr;
188
189 if (inp_ip->ip_p && inp_ip->ip_p != ip->ip_p) {
190 return 0;
191 }
192 inpcb_get_addrs(inp, &laddr, &faddr);
193
194 if (!in_nullhost(laddr) && !in_hosteq(laddr, ip->ip_dst)) {
195 return 0;
196 }
197 if (!in_nullhost(faddr) && !in_hosteq(faddr, ip->ip_src)) {
198 return 0;
199 }
200
201 #if defined(IPSEC)
202 /* Check AH/ESP integrity. */
203 if (ipsec4_in_reject_so(rctx->mbuf, inpcb_get_socket(inp))) {
204 /* Do not inject data into PCB. */
205 IPSEC_STATINC(IPSEC_STAT_IN_POLVIO);
206 return 0;
207 }
208 #endif
209 rip_append(inp, rctx);
210 rctx->nfound++;
211 return 0;
212 }
213
214 void
215 rip_input(struct mbuf *m, ...)
216 {
217 struct ip *ip = mtod(m, struct ip *);
218 int error, hlen, proto;
219 va_list ap;
220
221 va_start(ap, m);
222 (void)va_arg(ap, int); /* ignore value, advance ap */
223 proto = va_arg(ap, int);
224 va_end(ap);
225
226 KASSERTMSG((proto == ip->ip_p), "%s: protocol mismatch", __func__);
227
228 /*
229 * Compatibility: programs using raw IP expect ip_len field to have
230 * the header length subtracted. Also, ip_len and ip_off fields are
231 * expected to be in host order.
232 */
233 hlen = ip->ip_hl << 2;
234 ip->ip_len = ntohs(ip->ip_len) - hlen;
235 NTOHS(ip->ip_off);
236
237 /* Save some context for the iterator. */
238 struct rip_input_ctx rctx = {
239 .mbuf = m, .ip = ip, .hlen = hlen, .nfound = 0
240 };
241 sockaddr_in_init(&rctx.src, &ip->ip_src, 0);
242
243 /* Scan all raw IP PCBs for matching entries. */
244 error = inpcb_foreach(rawcbtable, AF_INET, rip_pcb_process, &rctx);
245 KASSERT(error == 0);
246
247 /* Done, if found any. */
248 if (rctx.nfound) {
249 return;
250 }
251
252 if (inetsw[ip_protox[ip->ip_p]].pr_input == rip_input) {
253 uint64_t *ips;
254
255 icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 0, 0);
256 ips = IP_STAT_GETREF();
257 ips[IP_STAT_NOPROTO]++;
258 ips[IP_STAT_DELIVERED]--;
259 IP_STAT_PUTREF();
260 } else {
261 m_freem(m);
262 }
263 }
264
265 static int
266 rip_pcbnotify(inpcb_t *inp, void *arg)
267 {
268 struct rip_ctlinput_ctx *rctx = arg;
269 const struct ip *ip = rctx->ip;
270 struct ip *inp_ip = in_getiphdr(inp);
271 struct in_addr laddr, faddr;
272
273 if (inp_ip->ip_p && inp_ip->ip_p != ip->ip_p) {
274 return 0;
275 }
276 inpcb_get_addrs(inp, &laddr, &faddr);
277
278 if (in_hosteq(faddr, rctx->addr) && in_hosteq(laddr, ip->ip_src)) {
279 inpcb_rtchange(inp, rctx->errno);
280 }
281 return 0;
282 }
283
284 void *
285 rip_ctlinput(int cmd, const struct sockaddr *sa, void *v)
286 {
287 struct ip *ip = v;
288 int errno;
289
290 if (sa->sa_family != AF_INET ||
291 sa->sa_len != sizeof(struct sockaddr_in))
292 return NULL;
293 if ((unsigned)cmd >= PRC_NCMDS)
294 return NULL;
295 errno = inetctlerrmap[cmd];
296
297 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD || ip == NULL) {
298 inpcb_notifyall(rawcbtable, satocsin(sa)->sin_addr,
299 errno, inpcb_rtchange);
300 return NULL;
301 } else if (errno == 0) {
302 return NULL;
303 }
304
305 /* Note: mapped address case. */
306 struct rip_ctlinput_ctx rctx = {
307 .ip = ip, .addr = satocsin(sa)->sin_addr, .errno = errno
308 };
309 (void)inpcb_foreach(rawcbtable, AF_INET, rip_pcbnotify, &rctx);
310
311 return NULL;
312 }
313
314 /*
315 * Generate IP header and pass packet to the IP output routine.
316 * Tack on options user may have setup with control call.
317 */
318 int
319 rip_output(struct mbuf *m, ...)
320 {
321 inpcb_t *inp;
322 struct socket *so;
323 struct ip *ip;
324 struct mbuf *opts;
325 int flags, inpflags;
326 va_list ap;
327
328 va_start(ap, m);
329 inp = va_arg(ap, inpcb_t *);
330 va_end(ap);
331
332 so = inpcb_get_socket(inp);
333 KASSERT(solocked(so));
334
335 flags = (so->so_options & SO_DONTROUTE) |
336 IP_ALLOWBROADCAST | IP_RETURNMTU;
337 inpflags = inpcb_get_flags(inp);
338
339 /*
340 * If the user handed us a complete IP packet, use it.
341 * Otherwise, allocate an mbuf for a header and fill it in.
342 */
343 if ((inpflags & INP_HDRINCL) == 0) {
344 struct ip *inp_ip = in_getiphdr(inp);
345
346 if ((m->m_pkthdr.len + sizeof(struct ip)) > IP_MAXPACKET) {
347 m_freem(m);
348 return EMSGSIZE;
349 }
350 M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
351 if (m == NULL) {
352 return ENOBUFS;
353 }
354 ip = mtod(m, struct ip *);
355 ip->ip_tos = 0;
356 ip->ip_off = htons(0);
357 ip->ip_p = inp_ip->ip_p;
358 ip->ip_len = htons(m->m_pkthdr.len);
359 inpcb_get_addrs(inp, &ip->ip_src, &ip->ip_dst);
360
361 ip->ip_ttl = MAXTTL;
362 opts = inpcb_get_options(inp);
363 } else {
364 if (m->m_pkthdr.len > IP_MAXPACKET) {
365 m_freem(m);
366 return EMSGSIZE;
367 }
368 ip = mtod(m, struct ip *);
369
370 /*
371 * If the mbuf is read-only, we need to allocate a new mbuf
372 * for the header, since we need to modify the header.
373 */
374 if (M_READONLY(m)) {
375 const int hlen = ip->ip_hl << 2;
376
377 m = m_copyup(m, hlen, (max_linkhdr + 3) & ~3);
378 if (m == NULL) {
379 return ENOMEM; /* XXX */
380 }
381 ip = mtod(m, struct ip *);
382 }
383
384 /*
385 * Applications on raw sockets pass us packets
386 * in host byte order.
387 */
388 if (m->m_pkthdr.len != ip->ip_len) {
389 m_freem(m);
390 return (EINVAL);
391 }
392 HTONS(ip->ip_len);
393 HTONS(ip->ip_off);
394 if (ip->ip_id || m->m_pkthdr.len < IP_MINFRAGSIZE) {
395 flags |= IP_NOIPNEWID;
396 }
397 opts = NULL;
398
399 /*
400 * Note: prevent IP output from overwriting header fields.
401 */
402 flags |= IP_RAWOUTPUT;
403 IP_STATINC(IP_STAT_RAWOUT);
404 }
405
406 return ip_output(m, opts, inpcb_get_route(inp), flags,
407 inpcb_get_moptions(inp), so);
408 }
409
410 /*
411 * Raw IP socket option processing.
412 */
413 int
414 rip_ctloutput(int op, struct socket *so, struct sockopt *sopt)
415 {
416 inpcb_t *inp = sotoinpcb(so);
417 int inpflags = inpcb_get_flags(inp);
418 int error = 0, optval;
419
420 KASSERT(solocked(so));
421
422 if (sopt->sopt_level == SOL_SOCKET && sopt->sopt_name == SO_NOHEADER) {
423 if (op == PRCO_GETOPT) {
424 optval = (inpflags & INP_NOHEADER) ? 1 : 0;
425 error = sockopt_set(sopt, &optval, sizeof(optval));
426 } else if (op == PRCO_SETOPT) {
427 error = sockopt_getint(sopt, &optval);
428 if (error)
429 goto out;
430 if (optval) {
431 inpflags &= ~INP_HDRINCL;
432 inpflags |= INP_NOHEADER;
433 } else
434 inpflags &= ~INP_NOHEADER;
435 }
436 goto out;
437 }
438
439 if (sopt->sopt_level != IPPROTO_IP) {
440 return ip_ctloutput(op, so, sopt);
441 }
442
443 switch (op) {
444 case PRCO_SETOPT:
445 switch (sopt->sopt_name) {
446 case IP_HDRINCL:
447 error = sockopt_getint(sopt, &optval);
448 if (error)
449 break;
450 if (optval)
451 inpflags |= INP_HDRINCL;
452 else
453 inpflags &= ~INP_HDRINCL;
454 break;
455
456 #ifdef MROUTING
457 case MRT_INIT:
458 case MRT_DONE:
459 case MRT_ADD_VIF:
460 case MRT_DEL_VIF:
461 case MRT_ADD_MFC:
462 case MRT_DEL_MFC:
463 case MRT_ASSERT:
464 case MRT_API_CONFIG:
465 case MRT_ADD_BW_UPCALL:
466 case MRT_DEL_BW_UPCALL:
467 error = ip_mrouter_set(so, sopt);
468 break;
469 #endif
470
471 default:
472 error = ip_ctloutput(op, so, sopt);
473 break;
474 }
475 break;
476
477 case PRCO_GETOPT:
478 switch (sopt->sopt_name) {
479 case IP_HDRINCL:
480 optval = inpflags & INP_HDRINCL;
481 error = sockopt_set(sopt, &optval, sizeof(optval));
482 break;
483
484 #ifdef MROUTING
485 case MRT_VERSION:
486 case MRT_ASSERT:
487 case MRT_API_SUPPORT:
488 case MRT_API_CONFIG:
489 error = ip_mrouter_get(so, sopt);
490 break;
491 #endif
492
493 default:
494 error = ip_ctloutput(op, so, sopt);
495 break;
496 }
497 break;
498 }
499 out:
500 if (!error) {
501 inpcb_set_flags(inp, inpflags);
502 }
503 return error;
504 }
505
506 static int
507 rip_bind(inpcb_t *inp, struct mbuf *nam)
508 {
509 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
510
511 if (nam->m_len != sizeof(*addr))
512 return (EINVAL);
513 if (!IFNET_FIRST())
514 return (EADDRNOTAVAIL);
515 if (addr->sin_family != AF_INET)
516 return EAFNOSUPPORT;
517 if (!in_nullhost(addr->sin_addr) && !ifa_ifwithaddr(sintosa(addr)))
518 return EADDRNOTAVAIL;
519
520 inpcb_set_addrs(inp, &addr->sin_addr, NULL);
521 return 0;
522 }
523
524 static int
525 rip_connect(inpcb_t *inp, struct mbuf *nam)
526 {
527 struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *);
528
529 if (nam->m_len != sizeof(*addr))
530 return (EINVAL);
531 if (!IFNET_FIRST())
532 return (EADDRNOTAVAIL);
533 if (addr->sin_family != AF_INET)
534 return EAFNOSUPPORT;
535
536 inpcb_set_addrs(inp, NULL, &addr->sin_addr);
537 return 0;
538 }
539
540 static void
541 rip_disconnect(inpcb_t *inp)
542 {
543 inpcb_set_addrs(inp, NULL, &zeroin_addr);
544 }
545
546 static int
547 rip_attach(struct socket *so, int proto)
548 {
549 inpcb_t *inp;
550 struct ip *ip;
551 int error;
552
553 KASSERT(sotoinpcb(so) == NULL);
554 sosetlock(so);
555
556 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
557 error = soreserve(so, rip_sendspace, rip_recvspace);
558 if (error) {
559 return error;
560 }
561 }
562
563 solock(so);
564 error = inpcb_create(so, rawcbtable);
565 if (error) {
566 sounlock(so);
567 return error;
568 }
569 inp = sotoinpcb(so);
570 ip = in_getiphdr(inp);
571 ip->ip_p = proto;
572 sounlock(so);
573
574 return 0;
575 }
576
577 static void
578 rip_detach(struct socket *so)
579 {
580 inpcb_t *inp;
581
582 KASSERT(solocked(so));
583 inp = sotoinpcb(so);
584 KASSERT(inp != NULL);
585
586 #ifdef MROUTING
587 extern struct socket *ip_mrouter;
588 if (so == ip_mrouter) {
589 ip_mrouter_done();
590 }
591 #endif
592 inpcb_destroy(inp);
593 }
594
595 int
596 rip_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam,
597 struct mbuf *control, struct lwp *l)
598 {
599 inpcb_t *inp;
600 int error = 0;
601
602 KASSERT(req != PRU_ATTACH);
603 KASSERT(req != PRU_DETACH);
604
605 if (req == PRU_CONTROL) {
606 return in_control(so, (long)m, nam, (ifnet_t *)control, l);
607 }
608 if (req == PRU_PURGEIF) {
609 int s = splsoftnet();
610 mutex_enter(softnet_lock);
611 inpcb_purgeif0(rawcbtable, (ifnet_t *)control);
612 in_purgeif((ifnet_t *)control);
613 inpcb_purgeif(rawcbtable, (ifnet_t *)control);
614 mutex_exit(softnet_lock);
615 splx(s);
616 return 0;
617 }
618
619 KASSERT(solocked(so));
620 inp = sotoinpcb(so);
621
622 KASSERT(!control || (req == PRU_SEND || req == PRU_SENDOOB));
623 if (inp == NULL) {
624 return EINVAL;
625 }
626
627 switch (req) {
628 case PRU_BIND:
629 error = rip_bind(inp, nam);
630 break;
631
632 case PRU_LISTEN:
633 error = EOPNOTSUPP;
634 break;
635
636 case PRU_CONNECT:
637 error = rip_connect(inp, nam);
638 if (error)
639 break;
640 soisconnected(so);
641 break;
642
643 case PRU_CONNECT2:
644 error = EOPNOTSUPP;
645 break;
646
647 case PRU_DISCONNECT:
648 soisdisconnected(so);
649 rip_disconnect(inp);
650 break;
651
652 /*
653 * Mark the connection as being incapable of further input.
654 */
655 case PRU_SHUTDOWN:
656 socantsendmore(so);
657 break;
658
659 case PRU_RCVD:
660 error = EOPNOTSUPP;
661 break;
662
663 /*
664 * Ship a packet out. The appropriate raw output
665 * routine handles any massaging necessary.
666 */
667 case PRU_SEND:
668 if (control && control->m_len) {
669 m_freem(control);
670 m_freem(m);
671 error = EINVAL;
672 break;
673 }
674 if ((so->so_state & SS_ISCONNECTED) != 0) {
675 error = nam ? EISCONN : ENOTCONN;
676 m_freem(m);
677 break;
678 }
679 if (nam && (error = rip_connect(inp, nam)) != 0) {
680 m_freem(m);
681 break;
682 }
683 error = rip_output(m, inp);
684 if (nam) {
685 rip_disconnect(inp);
686 }
687 break;
688
689 case PRU_SENSE:
690 /*
691 * Stat: do not bother with a blocksize.
692 */
693 return 0;
694
695 case PRU_RCVOOB:
696 error = EOPNOTSUPP;
697 break;
698
699 case PRU_SENDOOB:
700 m_freem(control);
701 m_freem(m);
702 error = EOPNOTSUPP;
703 break;
704
705 case PRU_SOCKADDR:
706 inpcb_fetch_sockaddr(inp, nam);
707 break;
708
709 case PRU_PEERADDR:
710 inpcb_fetch_peeraddr(inp, nam);
711 break;
712
713 default:
714 KASSERT(false);
715 }
716
717 return error;
718 }
719
720 PR_WRAP_USRREQ(rip_usrreq)
721
722 #define rip_usrreq rip_usrreq_wrapper
723
724 const struct pr_usrreqs rip_usrreqs = {
725 .pr_attach = rip_attach,
726 .pr_detach = rip_detach,
727 .pr_generic = rip_usrreq,
728 };
729
730 static void
731 sysctl_net_inet_raw_setup(struct sysctllog **clog)
732 {
733 sysctl_createv(clog, 0, NULL, NULL,
734 CTLFLAG_PERMANENT,
735 CTLTYPE_NODE, "inet", NULL,
736 NULL, 0, NULL, 0,
737 CTL_NET, PF_INET, CTL_EOL);
738 sysctl_createv(clog, 0, NULL, NULL,
739 CTLFLAG_PERMANENT,
740 CTLTYPE_NODE, "raw",
741 SYSCTL_DESCR("Raw IPv4 settings"),
742 NULL, 0, NULL, 0,
743 CTL_NET, PF_INET, IPPROTO_RAW, CTL_EOL);
744 sysctl_createv(clog, 0, NULL, NULL,
745 CTLFLAG_PERMANENT,
746 CTLTYPE_STRUCT, "pcblist",
747 SYSCTL_DESCR("Raw IPv4 control block list"),
748 sysctl_inpcblist, 0, rawcbtable, 0,
749 CTL_NET, PF_INET, IPPROTO_RAW,
750 CTL_CREATE, CTL_EOL);
751 }
752