This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / sys / net / rtsock.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1988, 1991 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
70c5ff60 33 * from: @(#)rtsock.c 7.18 (Berkeley) 6/27/91
fde1aeb2 34 * $Id: rtsock.c,v 1.5 1993/11/25 01:34:12 wollman Exp $
15637ed4
RG
35 */
36
37#include "param.h"
dd18dc33 38#include "systm.h"
15637ed4
RG
39#include "mbuf.h"
40#include "proc.h"
41#include "socket.h"
42#include "socketvar.h"
43#include "domain.h"
44#include "protosw.h"
45
15637ed4
RG
46#include "if.h"
47#include "route.h"
48#include "raw_cb.h"
49
50#include "machine/mtpr.h"
51
4c45483e
GW
52static void rt_setmetrics(u_long, struct rt_metrics *, struct rt_metrics *);
53
8ace4366 54struct route_cb route_cb;
15637ed4
RG
55struct sockaddr route_dst = { 2, PF_ROUTE, };
56struct sockaddr route_src = { 2, PF_ROUTE, };
57struct sockproto route_proto = { PF_ROUTE, };
58
59/*ARGSUSED*/
4c45483e 60int
15637ed4
RG
61route_usrreq(so, req, m, nam, control)
62 register struct socket *so;
63 int req;
64 struct mbuf *m, *nam, *control;
65{
66 register int error = 0;
67 register struct rawcb *rp = sotorawcb(so);
68 int s;
69 if (req == PRU_ATTACH) {
70 MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
71 if (so->so_pcb = (caddr_t)rp)
72 bzero(so->so_pcb, sizeof(*rp));
73
74 }
75 if (req == PRU_DETACH && rp) {
76 int af = rp->rcb_proto.sp_protocol;
77 if (af == AF_INET)
78 route_cb.ip_count--;
79 else if (af == AF_NS)
80 route_cb.ns_count--;
81 else if (af == AF_ISO)
82 route_cb.iso_count--;
83 route_cb.any_count--;
84 }
85 s = splnet();
fde1aeb2 86 error = raw_usrreq(so, req, m, nam, control, 0);
15637ed4
RG
87 rp = sotorawcb(so);
88 if (req == PRU_ATTACH && rp) {
89 int af = rp->rcb_proto.sp_protocol;
90 if (error) {
91 free((caddr_t)rp, M_PCB);
92 splx(s);
93 return (error);
94 }
95 if (af == AF_INET)
96 route_cb.ip_count++;
97 else if (af == AF_NS)
98 route_cb.ns_count++;
99 else if (af == AF_ISO)
100 route_cb.iso_count++;
101 rp->rcb_faddr = &route_src;
102 route_cb.any_count++;
103 soisconnected(so);
104 so->so_options |= SO_USELOOPBACK;
105 }
106 splx(s);
107 return (error);
108}
109#define ROUNDUP(a) \
110 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
111#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
112
113/*ARGSUSED*/
4c45483e 114int
15637ed4
RG
115route_output(m, so)
116 register struct mbuf *m;
117 struct socket *so;
118{
119 register struct rt_msghdr *rtm = 0;
120 register struct rtentry *rt = 0;
121 struct rtentry *saved_nrt = 0;
122 struct sockaddr *dst = 0, *gate = 0, *netmask = 0, *genmask = 0;
123 struct sockaddr *ifpaddr = 0, *ifaaddr = 0;
124 caddr_t cp, lim;
125 int len, error = 0;
126 struct ifnet *ifp = 0;
127 struct ifaddr *ifa = 0;
128 struct ifaddr *ifaof_ifpforaddr(), *ifa_ifwithroute();
129
130#define senderr(e) { error = e; goto flush;}
131 if (m == 0 || m->m_len < sizeof(long))
132 return (ENOBUFS);
133 if ((m = m_pullup(m, sizeof(long))) == 0)
134 return (ENOBUFS);
135 if ((m->m_flags & M_PKTHDR) == 0)
136 panic("route_output");
137 len = m->m_pkthdr.len;
138 if (len < sizeof(*rtm) ||
139 len != mtod(m, struct rt_msghdr *)->rtm_msglen)
140 senderr(EINVAL);
141 R_Malloc(rtm, struct rt_msghdr *, len);
142 if (rtm == 0)
143 senderr(ENOBUFS);
144 m_copydata(m, 0, len, (caddr_t)rtm);
145 if (rtm->rtm_version != RTM_VERSION)
146 senderr(EPROTONOSUPPORT);
147 rtm->rtm_pid = curproc->p_pid;
148 lim = len + (caddr_t) rtm;
149 cp = (caddr_t) (rtm + 1);
150 if (rtm->rtm_addrs & RTA_DST) {
151 dst = (struct sockaddr *)cp;
152 ADVANCE(cp, dst);
153 } else
154 senderr(EINVAL);
155 if ((rtm->rtm_addrs & RTA_GATEWAY) && cp < lim) {
156 gate = (struct sockaddr *)cp;
157 ADVANCE(cp, gate);
158 }
159 if ((rtm->rtm_addrs & RTA_NETMASK) && cp < lim) {
160 netmask = (struct sockaddr *)cp;
161 ADVANCE(cp, netmask);
162 }
163 if ((rtm->rtm_addrs & RTA_GENMASK) && cp < lim) {
164 struct radix_node *t, *rn_addmask();
165 genmask = (struct sockaddr *)cp;
166 ADVANCE(cp, genmask);
167 t = rn_addmask(genmask, 1, 2);
168 if (t && Bcmp(genmask, t->rn_key, *(u_char *)genmask) == 0)
169 genmask = (struct sockaddr *)(t->rn_key);
170 else
171 senderr(ENOBUFS);
172 }
173 if ((rtm->rtm_addrs & RTA_IFP) && cp < lim) {
174 ifpaddr = (struct sockaddr *)cp;
175 ADVANCE(cp, ifpaddr);
176 }
177 if ((rtm->rtm_addrs & RTA_IFA) && cp < lim) {
178 ifaaddr = (struct sockaddr *)cp;
179 }
180 switch (rtm->rtm_type) {
181 case RTM_ADD:
182 if (gate == 0)
183 senderr(EINVAL);
184 error = rtrequest(RTM_ADD, dst, gate, netmask,
185 rtm->rtm_flags, &saved_nrt);
186 if (error == 0 && saved_nrt) {
187 rt_setmetrics(rtm->rtm_inits,
188 &rtm->rtm_rmx, &saved_nrt->rt_rmx);
189 saved_nrt->rt_refcnt--;
190 saved_nrt->rt_genmask = genmask;
191 }
192 break;
193
194 case RTM_DELETE:
195 error = rtrequest(RTM_DELETE, dst, gate, netmask,
196 rtm->rtm_flags, (struct rtentry **)0);
197 break;
198
199 case RTM_GET:
200 case RTM_CHANGE:
201 case RTM_LOCK:
202 rt = rtalloc1(dst, 0);
203 if (rt == 0)
204 senderr(ESRCH);
205 if (rtm->rtm_type != RTM_GET) {
206 if (Bcmp(dst, rt_key(rt), dst->sa_len) != 0)
207 senderr(ESRCH);
208 if (rt->rt_nodes->rn_dupedkey &&
209 (netmask == 0 ||
210 Bcmp(netmask, rt_mask(rt), netmask->sa_len)))
211 senderr(ETOOMANYREFS);
212 }
213 switch(rtm->rtm_type) {
214
215 case RTM_GET:
216 dst = rt_key(rt); len = sizeof(*rtm);
217 ADVANCE(len, dst);
218 rtm->rtm_addrs |= RTA_DST;
219 if (gate = rt->rt_gateway) {
220 ADVANCE(len, gate);
221 rtm->rtm_addrs |= RTA_GATEWAY;
222 } else
223 rtm->rtm_addrs &= ~RTA_GATEWAY;
224 if (netmask = rt_mask(rt)) {
225 ADVANCE(len, netmask);
226 rtm->rtm_addrs |= RTA_NETMASK;
227 } else
228 rtm->rtm_addrs &= ~RTA_NETMASK;
229 if (genmask = rt->rt_genmask) {
230 ADVANCE(len, genmask);
231 rtm->rtm_addrs |= RTA_GENMASK;
232 } else
233 rtm->rtm_addrs &= ~RTA_GENMASK;
234 if (rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) {
235 if (rt->rt_ifp == 0)
236 goto badif;
237 for (ifa = rt->rt_ifp->if_addrlist;
238 ifa && ifa->ifa_addr->sa_family != AF_LINK;
239 ifa = ifa->ifa_next){}
240 if (ifa && rt->rt_ifa) {
241 ifpaddr = ifa->ifa_addr;
242 ADVANCE(len, ifpaddr);
243 ifaaddr = rt->rt_ifa->ifa_addr;
244 ADVANCE(len, ifaaddr);
245 rtm->rtm_addrs |= RTA_IFP | RTA_IFA;
246 } else {
247 badif: ifpaddr = 0;
248 rtm->rtm_addrs &= ~(RTA_IFP | RTA_IFA);
249 }
250 }
251 if (len > rtm->rtm_msglen) {
252 struct rt_msghdr *new_rtm;
253 R_Malloc(new_rtm, struct rt_msghdr *, len);
254 if (new_rtm == 0)
255 senderr(ENOBUFS);
256 Bcopy(rtm, new_rtm, rtm->rtm_msglen);
257 Free(rtm); rtm = new_rtm;
258 }
259 rtm->rtm_msglen = len;
260 rtm->rtm_flags = rt->rt_flags;
261 rtm->rtm_rmx = rt->rt_rmx;
262 cp = (caddr_t) (1 + rtm);
263 len = ROUNDUP(dst->sa_len);
264 Bcopy(dst, cp, len); cp += len;
265 if (gate) {
266 len = ROUNDUP(gate->sa_len);
267 Bcopy(gate, cp, len); cp += len;
268 }
269 if (netmask) {
270 len = ROUNDUP(netmask->sa_len);
271 Bcopy(netmask, cp, len); cp += len;
272 }
273 if (genmask) {
274 len = ROUNDUP(genmask->sa_len);
275 Bcopy(genmask, cp, len); cp += len;
276 }
277 if (ifpaddr) {
278 len = ROUNDUP(ifpaddr->sa_len);
279 Bcopy(ifpaddr, cp, len); cp += len;
280 len = ROUNDUP(ifaaddr->sa_len);
281 Bcopy(ifaaddr, cp, len); cp += len;
282 }
283 break;
284
285 case RTM_CHANGE:
286 if (gate &&
287 (gate->sa_len > (len = rt->rt_gateway->sa_len)))
288 senderr(EDQUOT);
289 /* new gateway could require new ifaddr, ifp;
290 flags may also be different; ifp may be specified
291 by ll sockaddr when protocol address is ambiguous */
292 if (ifpaddr && (ifa = ifa_ifwithnet(ifpaddr)) &&
293 (ifp = ifa->ifa_ifp))
294 ifa = ifaof_ifpforaddr(ifaaddr ? ifaaddr : gate,
295 ifp);
296 else if ((ifaaddr && (ifa = ifa_ifwithaddr(ifaaddr))) ||
297 (ifa = ifa_ifwithroute(rt->rt_flags,
298 rt_key(rt), gate)))
299 ifp = ifa->ifa_ifp;
300 if (ifa) {
301 register struct ifaddr *oifa = rt->rt_ifa;
302 if (oifa != ifa) {
303 if (oifa && oifa->ifa_rtrequest)
304 oifa->ifa_rtrequest(RTM_DELETE,
305 rt, gate);
306 rt->rt_ifa = ifa;
307 rt->rt_ifp = ifp;
308 }
309 }
310 if (gate)
311 Bcopy(gate, rt->rt_gateway, len);
312 rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx,
313 &rt->rt_rmx);
314 if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
315 rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, gate);
316 if (genmask)
317 rt->rt_genmask = genmask;
318 /*
319 * Fall into
320 */
321 case RTM_LOCK:
322 rt->rt_rmx.rmx_locks |=
323 (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
324 rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
325 break;
326 }
327 goto cleanup;
328
329 default:
330 senderr(EOPNOTSUPP);
331 }
332
333flush:
334 if (rtm) {
335 if (error)
336 rtm->rtm_errno = error;
337 else
338 rtm->rtm_flags |= RTF_DONE;
339 }
340cleanup:
341 if (rt)
342 rtfree(rt);
343 {
344 register struct rawcb *rp = 0;
345 /*
346 * Check to see if we don't want our own messages.
347 */
348 if ((so->so_options & SO_USELOOPBACK) == 0) {
349 if (route_cb.any_count <= 1) {
350 if (rtm)
351 Free(rtm);
352 m_freem(m);
353 return (error);
354 }
355 /* There is another listener, so construct message */
356 rp = sotorawcb(so);
357 }
358 if (rtm) {
359 m_copyback(m, 0, rtm->rtm_msglen, (caddr_t)rtm);
360 Free(rtm);
361 }
362 if (rp)
363 rp->rcb_proto.sp_family = 0; /* Avoid us */
364 if (dst)
365 route_proto.sp_protocol = dst->sa_family;
366 raw_input(m, &route_proto, &route_src, &route_dst);
367 if (rp)
368 rp->rcb_proto.sp_family = PF_ROUTE;
369 }
370 return (error);
371}
372
4c45483e 373void
15637ed4
RG
374rt_setmetrics(which, in, out)
375 u_long which;
376 register struct rt_metrics *in, *out;
377{
378#define metric(f, e) if (which & (f)) out->e = in->e;
379 metric(RTV_RPIPE, rmx_recvpipe);
380 metric(RTV_SPIPE, rmx_sendpipe);
381 metric(RTV_SSTHRESH, rmx_ssthresh);
382 metric(RTV_RTT, rmx_rtt);
383 metric(RTV_RTTVAR, rmx_rttvar);
384 metric(RTV_HOPCOUNT, rmx_hopcount);
385 metric(RTV_MTU, rmx_mtu);
386 metric(RTV_EXPIRE, rmx_expire);
387#undef metric
388}
389
15637ed4
RG
390/*
391 * The miss message and losing message are very similar.
392 */
393
4c45483e 394void
15637ed4 395rt_missmsg(type, dst, gate, mask, src, flags, error)
4c45483e
GW
396 int type;
397 register struct sockaddr *dst;
398 struct sockaddr *gate;
399 struct sockaddr *mask;
400 struct sockaddr *src;
401 int flags;
402 int error;
15637ed4
RG
403{
404 register struct rt_msghdr *rtm;
405 register struct mbuf *m;
406 int dlen = ROUNDUP(dst->sa_len);
407 int len = dlen + sizeof(*rtm);
408
409 if (route_cb.any_count == 0)
410 return;
411 m = m_gethdr(M_DONTWAIT, MT_DATA);
412 if (m == 0)
413 return;
414 m->m_pkthdr.len = m->m_len = min(len, MHLEN);
415 m->m_pkthdr.rcvif = 0;
416 rtm = mtod(m, struct rt_msghdr *);
417 bzero((caddr_t)rtm, sizeof(*rtm)); /*XXX assumes sizeof(*rtm) < MHLEN*/
418 rtm->rtm_flags = RTF_DONE | flags;
419 rtm->rtm_msglen = len;
420 rtm->rtm_version = RTM_VERSION;
421 rtm->rtm_type = type;
422 rtm->rtm_addrs = RTA_DST;
423 if (type == RTM_OLDADD || type == RTM_OLDDEL) {
424 rtm->rtm_pid = curproc->p_pid;
425 }
426 m_copyback(m, sizeof (*rtm), dlen, (caddr_t)dst);
427 if (gate) {
428 dlen = ROUNDUP(gate->sa_len);
429 m_copyback(m, len , dlen, (caddr_t)gate);
430 len += dlen;
431 rtm->rtm_addrs |= RTA_GATEWAY;
432 }
433 if (mask) {
434 dlen = ROUNDUP(mask->sa_len);
435 m_copyback(m, len , dlen, (caddr_t)mask);
436 len += dlen;
437 rtm->rtm_addrs |= RTA_NETMASK;
438 }
439 if (src) {
440 dlen = ROUNDUP(src->sa_len);
441 m_copyback(m, len , dlen, (caddr_t)src);
442 len += dlen;
443 rtm->rtm_addrs |= RTA_AUTHOR;
444 }
445 if (m->m_pkthdr.len != len) {
446 m_freem(m);
447 return;
448 }
449 rtm->rtm_errno = error;
450 rtm->rtm_msglen = len;
451 route_proto.sp_protocol = dst->sa_family;
452 raw_input(m, &route_proto, &route_src, &route_dst);
453}
454
455#include "kinfo.h"
456struct walkarg {
457 int w_op, w_arg;
458 int w_given, w_needed;
459 caddr_t w_where;
460 struct {
461 struct rt_msghdr m_rtm;
462 char m_sabuf[128];
463 } w_m;
464#define w_rtm w_m.m_rtm
465};
466/*
467 * This is used in dumping the kernel table via getkinfo().
468 */
4c45483e 469int
15637ed4
RG
470rt_dumpentry(rn, w)
471 struct radix_node *rn;
472 register struct walkarg *w;
473{
474 register struct sockaddr *sa;
475 int n, error;
476
477 for (; rn; rn = rn->rn_dupedkey) {
478 int count = 0, size = sizeof(w->w_rtm);
479 register struct rtentry *rt = (struct rtentry *)rn;
480
481 if (rn->rn_flags & RNF_ROOT)
482 continue;
483 if (w->w_op == KINFO_RT_FLAGS && !(rt->rt_flags & w->w_arg))
484 continue;
485#define next(a, l) {size += (l); w->w_rtm.rtm_addrs |= (a); }
486 w->w_rtm.rtm_addrs = 0;
487 if (sa = rt_key(rt))
488 next(RTA_DST, ROUNDUP(sa->sa_len));
489 if (sa = rt->rt_gateway)
490 next(RTA_GATEWAY, ROUNDUP(sa->sa_len));
491 if (sa = rt_mask(rt))
492 next(RTA_NETMASK, ROUNDUP(sa->sa_len));
493 if (sa = rt->rt_genmask)
494 next(RTA_GENMASK, ROUNDUP(sa->sa_len));
495 w->w_needed += size;
496 if (w->w_where == NULL || w->w_needed > 0)
497 continue;
498 w->w_rtm.rtm_msglen = size;
499 w->w_rtm.rtm_flags = rt->rt_flags;
500 w->w_rtm.rtm_use = rt->rt_use;
501 w->w_rtm.rtm_rmx = rt->rt_rmx;
502 w->w_rtm.rtm_index = rt->rt_ifp->if_index;
503#undef next
504#define next(l) {n = (l); Bcopy(sa, cp, n); cp += n;}
505 if (size <= sizeof(w->w_m)) {
506 register caddr_t cp = (caddr_t)(w->w_m.m_sabuf);
507 if (sa = rt_key(rt))
508 next(ROUNDUP(sa->sa_len));
509 if (sa = rt->rt_gateway)
510 next(ROUNDUP(sa->sa_len));
511 if (sa = rt_mask(rt))
512 next(ROUNDUP(sa->sa_len));
513 if (sa = rt->rt_genmask)
514 next(ROUNDUP(sa->sa_len));
515#undef next
516#define next(s, l) {n = (l); \
517 if (error = copyout((caddr_t)(s), w->w_where, n)) return (error); \
518 w->w_where += n;}
519
520 next(&w->w_m, size); /* Copy rtmsg and sockaddrs back */
521 continue;
522 }
523 next(&w->w_rtm, sizeof(w->w_rtm));
524 if (sa = rt_key(rt))
525 next(sa, ROUNDUP(sa->sa_len));
526 if (sa = rt->rt_gateway)
527 next(sa, ROUNDUP(sa->sa_len));
528 if (sa = rt_mask(rt))
529 next(sa, ROUNDUP(sa->sa_len));
530 if (sa = rt->rt_genmask)
531 next(sa, ROUNDUP(sa->sa_len));
532 }
533 return (0);
534#undef next
535}
536
4c45483e 537int
15637ed4
RG
538kinfo_rtable(op, where, given, arg, needed)
539 int op, arg;
540 caddr_t where;
541 int *given, *needed;
542{
543 register struct radix_node_head *rnh;
544 int s, error = 0;
545 u_char af = ki_af(op);
546 struct walkarg w;
547
548 op &= 0xffff;
549 if (op != KINFO_RT_DUMP && op != KINFO_RT_FLAGS)
550 return (EINVAL);
551
552 Bzero(&w, sizeof(w));
553 if ((w.w_where = where) && given)
554 w.w_given = *given;
555 w.w_needed = 0 - w.w_given;
556 w.w_arg = arg;
557 w.w_op = op;
558 w.w_rtm.rtm_version = RTM_VERSION;
559 w.w_rtm.rtm_type = RTM_GET;
560
561 s = splnet();
562 for (rnh = radix_node_head; rnh; rnh = rnh->rnh_next) {
563 if (rnh->rnh_af == 0)
564 continue;
565 if (af && af != rnh->rnh_af)
566 continue;
567 error = rt_walk(rnh->rnh_treetop, rt_dumpentry, &w);
568 if (error)
569 break;
570 }
571 w.w_needed += w.w_given;
572 if (where && given)
573 *given = w.w_where - where;
574 else
575 w.w_needed = (11 * w.w_needed) / 10;
576 *needed = w.w_needed;
577 splx(s);
578 return (error);
579}
580
4c45483e 581int
15637ed4
RG
582rt_walk(rn, f, w)
583 register struct radix_node *rn;
584 register int (*f)();
585 struct walkarg *w;
586{
587 int error;
588 for (;;) {
589 while (rn->rn_b >= 0)
590 rn = rn->rn_l; /* First time through node, go left */
591 if (error = (*f)(rn, w))
592 return (error); /* Process Leaf */
593 while (rn->rn_p->rn_r == rn) { /* if coming back from right */
594 rn = rn->rn_p; /* go back up */
595 if (rn->rn_flags & RNF_ROOT)
596 return 0;
597 }
598 rn = rn->rn_p->rn_r; /* otherwise, go right*/
599 }
600}
601
602/*
603 * Definitions of protocols supported in the ROUTE domain.
604 */
605
15637ed4
RG
606extern struct domain routedomain; /* or at least forward */
607
608struct protosw routesw[] = {
609{ SOCK_RAW, &routedomain, 0, PR_ATOMIC|PR_ADDR,
610 raw_input, route_output, raw_ctlinput, 0,
611 route_usrreq,
612 raw_init, 0, 0, 0,
613}
614};
615
616int unp_externalize(), unp_dispose();
617
618struct domain routedomain =
619 { PF_ROUTE, "route", 0, 0, 0,
620 routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] };