| @@ -1,1324 +1,1303 @@ | | | @@ -1,1324 +1,1303 @@ |
1 | /* $NetBSD: rtsock.c,v 1.115.2.2 2009/01/09 02:58:58 snj Exp $ */ | | 1 | /* $NetBSD: rtsock.c,v 1.115.2.3 2009/03/15 20:00:30 snj Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. | | 4 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
15 | * 3. Neither the name of the project nor the names of its contributors | | 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 | | 16 | * may be used to endorse or promote products derived from this software |
17 | * without specific prior written permission. | | 17 | * without specific prior written permission. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND | | 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 | | 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE | | 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 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 | | 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 | | 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 | | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | * SUCH DAMAGE. | | 29 | * SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * Copyright (c) 1988, 1991, 1993 | | 33 | * Copyright (c) 1988, 1991, 1993 |
34 | * The Regents of the University of California. All rights reserved. | | 34 | * The Regents of the University of California. All rights reserved. |
35 | * | | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | | 36 | * Redistribution and use in source and binary forms, with or without |
37 | * modification, are permitted provided that the following conditions | | 37 | * modification, are permitted provided that the following conditions |
38 | * are met: | | 38 | * are met: |
39 | * 1. Redistributions of source code must retain the above copyright | | 39 | * 1. Redistributions of source code must retain the above copyright |
40 | * notice, this list of conditions and the following disclaimer. | | 40 | * notice, this list of conditions and the following disclaimer. |
41 | * 2. Redistributions in binary form must reproduce the above copyright | | 41 | * 2. Redistributions in binary form must reproduce the above copyright |
42 | * notice, this list of conditions and the following disclaimer in the | | 42 | * notice, this list of conditions and the following disclaimer in the |
43 | * documentation and/or other materials provided with the distribution. | | 43 | * documentation and/or other materials provided with the distribution. |
44 | * 3. Neither the name of the University nor the names of its contributors | | 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 | | 45 | * may be used to endorse or promote products derived from this software |
46 | * without specific prior written permission. | | 46 | * without specific prior written permission. |
47 | * | | 47 | * |
48 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 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 | | 49 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
50 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 50 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
51 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 51 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
52 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 52 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
53 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 53 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
54 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 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 | | 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 | | 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 | | 57 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
58 | * SUCH DAMAGE. | | 58 | * SUCH DAMAGE. |
59 | * | | 59 | * |
60 | * @(#)rtsock.c 8.7 (Berkeley) 10/12/95 | | 60 | * @(#)rtsock.c 8.7 (Berkeley) 10/12/95 |
61 | */ | | 61 | */ |
62 | | | 62 | |
63 | #include <sys/cdefs.h> | | 63 | #include <sys/cdefs.h> |
64 | __KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.115.2.2 2009/01/09 02:58:58 snj Exp $"); | | 64 | __KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.115.2.3 2009/03/15 20:00:30 snj Exp $"); |
65 | | | 65 | |
66 | #include "opt_inet.h" | | 66 | #include "opt_inet.h" |
67 | | | 67 | |
68 | #include <sys/param.h> | | 68 | #include <sys/param.h> |
69 | #include <sys/systm.h> | | 69 | #include <sys/systm.h> |
70 | #include <sys/proc.h> | | 70 | #include <sys/proc.h> |
71 | #include <sys/mbuf.h> | | 71 | #include <sys/mbuf.h> |
72 | #include <sys/socket.h> | | 72 | #include <sys/socket.h> |
73 | #include <sys/socketvar.h> | | 73 | #include <sys/socketvar.h> |
74 | #include <sys/domain.h> | | 74 | #include <sys/domain.h> |
75 | #include <sys/protosw.h> | | 75 | #include <sys/protosw.h> |
76 | #include <sys/sysctl.h> | | 76 | #include <sys/sysctl.h> |
77 | #include <sys/kauth.h> | | 77 | #include <sys/kauth.h> |
78 | #include <sys/intr.h> | | 78 | #include <sys/intr.h> |
79 | #ifdef RTSOCK_DEBUG | | 79 | #ifdef RTSOCK_DEBUG |
80 | #include <netinet/in.h> | | 80 | #include <netinet/in.h> |
81 | #endif /* RTSOCK_DEBUG */ | | 81 | #endif /* RTSOCK_DEBUG */ |
82 | | | 82 | |
83 | #include <net/if.h> | | 83 | #include <net/if.h> |
84 | #include <net/route.h> | | 84 | #include <net/route.h> |
85 | #include <net/raw_cb.h> | | 85 | #include <net/raw_cb.h> |
86 | | | 86 | |
87 | #include <machine/stdarg.h> | | 87 | #include <machine/stdarg.h> |
88 | | | 88 | |
89 | DOMAIN_DEFINE(routedomain); /* forward declare and add to link set */ | | 89 | DOMAIN_DEFINE(routedomain); /* forward declare and add to link set */ |
90 | | | 90 | |
91 | struct sockaddr route_dst = { .sa_len = 2, .sa_family = PF_ROUTE, }; | | 91 | struct sockaddr route_dst = { .sa_len = 2, .sa_family = PF_ROUTE, }; |
92 | struct sockaddr route_src = { .sa_len = 2, .sa_family = PF_ROUTE, }; | | 92 | struct sockaddr route_src = { .sa_len = 2, .sa_family = PF_ROUTE, }; |
93 | | | 93 | |
94 | int route_maxqlen = IFQ_MAXLEN; | | 94 | int route_maxqlen = IFQ_MAXLEN; |
95 | static struct ifqueue route_intrq; | | 95 | static struct ifqueue route_intrq; |
96 | static void *route_sih; | | 96 | static void *route_sih; |
97 | | | 97 | |
98 | struct walkarg { | | 98 | struct walkarg { |
99 | int w_op; | | 99 | int w_op; |
100 | int w_arg; | | 100 | int w_arg; |
101 | int w_given; | | 101 | int w_given; |
102 | int w_needed; | | 102 | int w_needed; |
103 | void * w_where; | | 103 | void * w_where; |
104 | int w_tmemsize; | | 104 | int w_tmemsize; |
105 | int w_tmemneeded; | | 105 | int w_tmemneeded; |
106 | void * w_tmem; | | 106 | void * w_tmem; |
107 | }; | | 107 | }; |
108 | | | 108 | |
109 | static struct mbuf *rt_msg1(int, struct rt_addrinfo *, void *, int); | | 109 | static struct mbuf *rt_msg1(int, struct rt_addrinfo *, void *, int); |
110 | static int rt_msg2(int, struct rt_addrinfo *, void *, struct walkarg *, int *); | | 110 | static int rt_msg2(int, struct rt_addrinfo *, void *, struct walkarg *, int *); |
111 | static int rt_xaddrs(u_char, const char *, const char *, struct rt_addrinfo *); | | 111 | static int rt_xaddrs(u_char, const char *, const char *, struct rt_addrinfo *); |
112 | static struct mbuf *rt_makeifannouncemsg(struct ifnet *, int, int, | | 112 | static struct mbuf *rt_makeifannouncemsg(struct ifnet *, int, int, |
113 | struct rt_addrinfo *); | | 113 | struct rt_addrinfo *); |
114 | static int sysctl_dumpentry(struct rtentry *, void *); | | 114 | static int sysctl_dumpentry(struct rtentry *, void *); |
115 | static int sysctl_iflist(int, struct walkarg *, int); | | 115 | static int sysctl_iflist(int, struct walkarg *, int); |
116 | static int sysctl_rtable(SYSCTLFN_PROTO); | | 116 | static int sysctl_rtable(SYSCTLFN_PROTO); |
117 | static inline void rt_adjustcount(int, int); | | 117 | static inline void rt_adjustcount(int, int); |
118 | static void route_enqueue(struct mbuf *, int); | | 118 | static void route_enqueue(struct mbuf *, int); |
119 | | | 119 | |
120 | static inline void | | 120 | static inline void |
121 | rt_adjustcount(int af, int cnt) | | 121 | rt_adjustcount(int af, int cnt) |
122 | { | | 122 | { |
123 | route_cb.any_count += cnt; | | 123 | route_cb.any_count += cnt; |
124 | switch (af) { | | 124 | switch (af) { |
125 | case AF_INET: | | 125 | case AF_INET: |
126 | route_cb.ip_count += cnt; | | 126 | route_cb.ip_count += cnt; |
127 | return; | | 127 | return; |
128 | #ifdef INET6 | | 128 | #ifdef INET6 |
129 | case AF_INET6: | | 129 | case AF_INET6: |
130 | route_cb.ip6_count += cnt; | | 130 | route_cb.ip6_count += cnt; |
131 | return; | | 131 | return; |
132 | #endif | | 132 | #endif |
133 | case AF_IPX: | | 133 | case AF_IPX: |
134 | route_cb.ipx_count += cnt; | | 134 | route_cb.ipx_count += cnt; |
135 | return; | | 135 | return; |
136 | case AF_NS: | | 136 | case AF_NS: |
137 | route_cb.ns_count += cnt; | | 137 | route_cb.ns_count += cnt; |
138 | return; | | 138 | return; |
139 | case AF_ISO: | | 139 | case AF_ISO: |
140 | route_cb.iso_count += cnt; | | 140 | route_cb.iso_count += cnt; |
141 | return; | | 141 | return; |
142 | } | | 142 | } |
143 | } | | 143 | } |
144 | | | 144 | |
145 | /*ARGSUSED*/ | | 145 | /*ARGSUSED*/ |
146 | int | | 146 | int |
147 | route_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, | | 147 | route_usrreq(struct socket *so, int req, struct mbuf *m, struct mbuf *nam, |
148 | struct mbuf *control, struct lwp *l) | | 148 | struct mbuf *control, struct lwp *l) |
149 | { | | 149 | { |
150 | int error = 0; | | 150 | int error = 0; |
151 | struct rawcb *rp = sotorawcb(so); | | 151 | struct rawcb *rp = sotorawcb(so); |
152 | int s; | | 152 | int s; |
153 | | | 153 | |
154 | if (req == PRU_ATTACH) { | | 154 | if (req == PRU_ATTACH) { |
155 | sosetlock(so); | | 155 | sosetlock(so); |
156 | MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK|M_ZERO); | | 156 | MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK|M_ZERO); |
157 | so->so_pcb = rp; | | 157 | so->so_pcb = rp; |
158 | } | | 158 | } |
159 | if (req == PRU_DETACH && rp) | | 159 | if (req == PRU_DETACH && rp) |
160 | rt_adjustcount(rp->rcb_proto.sp_protocol, -1); | | 160 | rt_adjustcount(rp->rcb_proto.sp_protocol, -1); |
161 | s = splsoftnet(); | | 161 | s = splsoftnet(); |
162 | | | 162 | |
163 | /* | | 163 | /* |
164 | * Don't call raw_usrreq() in the attach case, because | | 164 | * Don't call raw_usrreq() in the attach case, because |
165 | * we want to allow non-privileged processes to listen on | | 165 | * we want to allow non-privileged processes to listen on |
166 | * and send "safe" commands to the routing socket. | | 166 | * and send "safe" commands to the routing socket. |
167 | */ | | 167 | */ |
168 | if (req == PRU_ATTACH) { | | 168 | if (req == PRU_ATTACH) { |
169 | if (l == NULL) | | 169 | if (l == NULL) |
170 | error = EACCES; | | 170 | error = EACCES; |
171 | else | | 171 | else |
172 | error = raw_attach(so, (int)(long)nam); | | 172 | error = raw_attach(so, (int)(long)nam); |
173 | } else | | 173 | } else |
174 | error = raw_usrreq(so, req, m, nam, control, l); | | 174 | error = raw_usrreq(so, req, m, nam, control, l); |
175 | | | 175 | |
176 | rp = sotorawcb(so); | | 176 | rp = sotorawcb(so); |
177 | if (req == PRU_ATTACH && rp) { | | 177 | if (req == PRU_ATTACH && rp) { |
178 | if (error) { | | 178 | if (error) { |
179 | free(rp, M_PCB); | | 179 | free(rp, M_PCB); |
180 | splx(s); | | 180 | splx(s); |
181 | return error; | | 181 | return error; |
182 | } | | 182 | } |
183 | rt_adjustcount(rp->rcb_proto.sp_protocol, 1); | | 183 | rt_adjustcount(rp->rcb_proto.sp_protocol, 1); |
184 | rp->rcb_laddr = &route_src; | | 184 | rp->rcb_laddr = &route_src; |
185 | rp->rcb_faddr = &route_dst; | | 185 | rp->rcb_faddr = &route_dst; |
186 | soisconnected(so); | | 186 | soisconnected(so); |
187 | so->so_options |= SO_USELOOPBACK; | | 187 | so->so_options |= SO_USELOOPBACK; |
188 | } | | 188 | } |
189 | splx(s); | | 189 | splx(s); |
190 | return error; | | 190 | return error; |
191 | } | | 191 | } |
192 | | | 192 | |
193 | static const struct sockaddr * | | 193 | static const struct sockaddr * |
194 | intern_netmask(const struct sockaddr *mask) | | 194 | intern_netmask(const struct sockaddr *mask) |
195 | { | | 195 | { |
196 | struct radix_node *rn; | | 196 | struct radix_node *rn; |
197 | extern struct radix_node_head *mask_rnhead; | | 197 | extern struct radix_node_head *mask_rnhead; |
198 | | | 198 | |
199 | if (mask != NULL && | | 199 | if (mask != NULL && |
200 | (rn = rn_search(mask, mask_rnhead->rnh_treetop))) | | 200 | (rn = rn_search(mask, mask_rnhead->rnh_treetop))) |
201 | mask = (const struct sockaddr *)rn->rn_key; | | 201 | mask = (const struct sockaddr *)rn->rn_key; |
202 | | | 202 | |
203 | return mask; | | 203 | return mask; |
204 | } | | 204 | } |
205 | | | 205 | |
206 | /*ARGSUSED*/ | | 206 | /*ARGSUSED*/ |
207 | int | | 207 | int |
208 | route_output(struct mbuf *m, ...) | | 208 | route_output(struct mbuf *m, ...) |
209 | { | | 209 | { |
210 | struct sockproto proto = { .sp_family = PF_ROUTE, }; | | 210 | struct sockproto proto = { .sp_family = PF_ROUTE, }; |
211 | struct rt_msghdr *rtm = NULL; | | 211 | struct rt_msghdr *rtm = NULL; |
212 | struct rt_msghdr *old_rtm = NULL; | | 212 | struct rt_msghdr *old_rtm = NULL; |
213 | struct rtentry *rt = NULL; | | 213 | struct rtentry *rt = NULL; |
214 | struct rtentry *saved_nrt = NULL; | | 214 | struct rtentry *saved_nrt = NULL; |
215 | struct rt_addrinfo info; | | 215 | struct rt_addrinfo info; |
216 | int len, error = 0, ifa_route = 0; | | 216 | int len, error = 0; |
217 | struct ifnet *ifp = NULL; | | 217 | struct ifnet *ifp = NULL; |
218 | struct ifaddr *ifa = NULL, *oifa; | | 218 | struct ifaddr *ifa = NULL; |
219 | struct socket *so; | | 219 | struct socket *so; |
220 | va_list ap; | | 220 | va_list ap; |
221 | sa_family_t family; | | 221 | sa_family_t family; |
222 | | | 222 | |
223 | va_start(ap, m); | | 223 | va_start(ap, m); |
224 | so = va_arg(ap, struct socket *); | | 224 | so = va_arg(ap, struct socket *); |
225 | va_end(ap); | | 225 | va_end(ap); |
226 | | | 226 | |
227 | #define senderr(e) do { error = e; goto flush;} while (/*CONSTCOND*/ 0) | | 227 | #define senderr(e) do { error = e; goto flush;} while (/*CONSTCOND*/ 0) |
228 | if (m == NULL || ((m->m_len < sizeof(int32_t)) && | | 228 | if (m == NULL || ((m->m_len < sizeof(int32_t)) && |
229 | (m = m_pullup(m, sizeof(int32_t))) == NULL)) | | 229 | (m = m_pullup(m, sizeof(int32_t))) == NULL)) |
230 | return ENOBUFS; | | 230 | return ENOBUFS; |
231 | if ((m->m_flags & M_PKTHDR) == 0) | | 231 | if ((m->m_flags & M_PKTHDR) == 0) |
232 | panic("route_output"); | | 232 | panic("route_output"); |
233 | len = m->m_pkthdr.len; | | 233 | len = m->m_pkthdr.len; |
234 | if (len < sizeof(*rtm) || | | 234 | if (len < sizeof(*rtm) || |
235 | len != mtod(m, struct rt_msghdr *)->rtm_msglen) { | | 235 | len != mtod(m, struct rt_msghdr *)->rtm_msglen) { |
236 | info.rti_info[RTAX_DST] = NULL; | | 236 | info.rti_info[RTAX_DST] = NULL; |
237 | senderr(EINVAL); | | 237 | senderr(EINVAL); |
238 | } | | 238 | } |
239 | R_Malloc(rtm, struct rt_msghdr *, len); | | 239 | R_Malloc(rtm, struct rt_msghdr *, len); |
240 | if (rtm == NULL) { | | 240 | if (rtm == NULL) { |
241 | info.rti_info[RTAX_DST] = NULL; | | 241 | info.rti_info[RTAX_DST] = NULL; |
242 | senderr(ENOBUFS); | | 242 | senderr(ENOBUFS); |
243 | } | | 243 | } |
244 | m_copydata(m, 0, len, rtm); | | 244 | m_copydata(m, 0, len, rtm); |
245 | if (rtm->rtm_version != RTM_VERSION) { | | 245 | if (rtm->rtm_version != RTM_VERSION) { |
246 | info.rti_info[RTAX_DST] = NULL; | | 246 | info.rti_info[RTAX_DST] = NULL; |
247 | senderr(EPROTONOSUPPORT); | | 247 | senderr(EPROTONOSUPPORT); |
248 | } | | 248 | } |
249 | rtm->rtm_pid = curproc->p_pid; | | 249 | rtm->rtm_pid = curproc->p_pid; |
250 | memset(&info, 0, sizeof(info)); | | 250 | memset(&info, 0, sizeof(info)); |
251 | info.rti_addrs = rtm->rtm_addrs; | | 251 | info.rti_addrs = rtm->rtm_addrs; |
252 | if (rt_xaddrs(rtm->rtm_type, (const char *)(rtm + 1), len + (char *)rtm, | | 252 | if (rt_xaddrs(rtm->rtm_type, (const char *)(rtm + 1), len + (char *)rtm, |
253 | &info)) | | 253 | &info)) |
254 | senderr(EINVAL); | | 254 | senderr(EINVAL); |
255 | info.rti_flags = rtm->rtm_flags; | | 255 | info.rti_flags = rtm->rtm_flags; |
256 | #ifdef RTSOCK_DEBUG | | 256 | #ifdef RTSOCK_DEBUG |
257 | if (info.rti_info[RTAX_DST]->sa_family == AF_INET) { | | 257 | if (info.rti_info[RTAX_DST]->sa_family == AF_INET) { |
258 | printf("%s: extracted info.rti_info[RTAX_DST] %s\n", __func__, | | 258 | printf("%s: extracted info.rti_info[RTAX_DST] %s\n", __func__, |
259 | inet_ntoa(((const struct sockaddr_in *) | | 259 | inet_ntoa(((const struct sockaddr_in *) |
260 | info.rti_info[RTAX_DST])->sin_addr)); | | 260 | info.rti_info[RTAX_DST])->sin_addr)); |
261 | } | | 261 | } |
262 | #endif /* RTSOCK_DEBUG */ | | 262 | #endif /* RTSOCK_DEBUG */ |
263 | if (info.rti_info[RTAX_DST] == NULL || | | 263 | if (info.rti_info[RTAX_DST] == NULL || |
264 | (info.rti_info[RTAX_DST]->sa_family >= AF_MAX)) | | 264 | (info.rti_info[RTAX_DST]->sa_family >= AF_MAX)) |
265 | senderr(EINVAL); | | 265 | senderr(EINVAL); |
266 | if (info.rti_info[RTAX_GATEWAY] != NULL && | | 266 | if (info.rti_info[RTAX_GATEWAY] != NULL && |
267 | (info.rti_info[RTAX_GATEWAY]->sa_family >= AF_MAX)) | | 267 | (info.rti_info[RTAX_GATEWAY]->sa_family >= AF_MAX)) |
268 | senderr(EINVAL); | | 268 | senderr(EINVAL); |
269 | | | 269 | |
270 | /* | | 270 | /* |
271 | * Verify that the caller has the appropriate privilege; RTM_GET | | 271 | * Verify that the caller has the appropriate privilege; RTM_GET |
272 | * is the only operation the non-superuser is allowed. | | 272 | * is the only operation the non-superuser is allowed. |
273 | */ | | 273 | */ |
274 | if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_ROUTE, | | 274 | if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_ROUTE, |
275 | 0, rtm, NULL, NULL) != 0) | | 275 | 0, rtm, NULL, NULL) != 0) |
276 | senderr(EACCES); | | 276 | senderr(EACCES); |
277 | | | 277 | |
278 | switch (rtm->rtm_type) { | | 278 | switch (rtm->rtm_type) { |
279 | | | 279 | |
280 | case RTM_ADD: | | 280 | case RTM_ADD: |
281 | if (info.rti_info[RTAX_GATEWAY] == NULL) | | 281 | if (info.rti_info[RTAX_GATEWAY] == NULL) |
282 | senderr(EINVAL); | | 282 | senderr(EINVAL); |
283 | error = rtrequest1(rtm->rtm_type, &info, &saved_nrt); | | 283 | error = rtrequest1(rtm->rtm_type, &info, &saved_nrt); |
284 | if (error == 0 && saved_nrt) { | | 284 | if (error == 0 && saved_nrt) { |
285 | rt_setmetrics(rtm->rtm_inits, | | 285 | rt_setmetrics(rtm->rtm_inits, |
286 | &rtm->rtm_rmx, &saved_nrt->rt_rmx); | | 286 | &rtm->rtm_rmx, &saved_nrt->rt_rmx); |
287 | saved_nrt->rt_refcnt--; | | 287 | saved_nrt->rt_refcnt--; |
288 | } | | 288 | } |
289 | break; | | 289 | break; |
290 | | | 290 | |
291 | case RTM_DELETE: | | 291 | case RTM_DELETE: |
292 | error = rtrequest1(rtm->rtm_type, &info, &saved_nrt); | | 292 | error = rtrequest1(rtm->rtm_type, &info, &saved_nrt); |
293 | if (error == 0) { | | 293 | if (error == 0) { |
294 | (rt = saved_nrt)->rt_refcnt++; | | 294 | (rt = saved_nrt)->rt_refcnt++; |
295 | ifa = rt_get_ifa(rt); | | | |
296 | /* | | | |
297 | * If deleting an automatic route, scrub the flag. | | | |
298 | */ | | | |
299 | if (ifa->ifa_flags & IFA_ROUTE) | | | |
300 | ifa->ifa_flags &= ~IFA_ROUTE; | | | |
301 | goto report; | | 295 | goto report; |
302 | } | | 296 | } |
303 | break; | | 297 | break; |
304 | | | 298 | |
305 | case RTM_GET: | | 299 | case RTM_GET: |
306 | case RTM_CHANGE: | | 300 | case RTM_CHANGE: |
307 | case RTM_LOCK: | | 301 | case RTM_LOCK: |
308 | /* XXX This will mask info.rti_info[RTAX_DST] with | | 302 | /* XXX This will mask info.rti_info[RTAX_DST] with |
309 | * info.rti_info[RTAX_NETMASK] before | | 303 | * info.rti_info[RTAX_NETMASK] before |
310 | * searching. It did not used to do that. --dyoung | | 304 | * searching. It did not used to do that. --dyoung |
311 | */ | | 305 | */ |
312 | error = rtrequest1(RTM_GET, &info, &rt); | | 306 | error = rtrequest1(RTM_GET, &info, &rt); |
313 | if (error != 0) | | 307 | if (error != 0) |
314 | senderr(error); | | 308 | senderr(error); |
315 | if (rtm->rtm_type != RTM_GET) {/* XXX: too grotty */ | | 309 | if (rtm->rtm_type != RTM_GET) {/* XXX: too grotty */ |
316 | struct radix_node *rn; | | 310 | struct radix_node *rn; |
317 | | | 311 | |
318 | if (memcmp(info.rti_info[RTAX_DST], rt_getkey(rt), | | 312 | if (memcmp(info.rti_info[RTAX_DST], rt_getkey(rt), |
319 | info.rti_info[RTAX_DST]->sa_len) != 0) | | 313 | info.rti_info[RTAX_DST]->sa_len) != 0) |
320 | senderr(ESRCH); | | 314 | senderr(ESRCH); |
321 | info.rti_info[RTAX_NETMASK] = intern_netmask( | | 315 | info.rti_info[RTAX_NETMASK] = intern_netmask( |
322 | info.rti_info[RTAX_NETMASK]); | | 316 | info.rti_info[RTAX_NETMASK]); |
323 | for (rn = rt->rt_nodes; rn; rn = rn->rn_dupedkey) | | 317 | for (rn = rt->rt_nodes; rn; rn = rn->rn_dupedkey) |
324 | if (info.rti_info[RTAX_NETMASK] == | | 318 | if (info.rti_info[RTAX_NETMASK] == |
325 | (const struct sockaddr *)rn->rn_mask) | | 319 | (const struct sockaddr *)rn->rn_mask) |
326 | break; | | 320 | break; |
327 | if (rn == NULL) | | 321 | if (rn == NULL) |
328 | senderr(ETOOMANYREFS); | | 322 | senderr(ETOOMANYREFS); |
329 | rt = (struct rtentry *)rn; | | 323 | rt = (struct rtentry *)rn; |
330 | } | | 324 | } |
331 | | | 325 | |
332 | switch (rtm->rtm_type) { | | 326 | switch (rtm->rtm_type) { |
333 | case RTM_GET: | | 327 | case RTM_GET: |
334 | report: | | 328 | report: |
335 | info.rti_info[RTAX_DST] = rt_getkey(rt); | | 329 | info.rti_info[RTAX_DST] = rt_getkey(rt); |
336 | info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; | | 330 | info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; |
337 | info.rti_info[RTAX_NETMASK] = rt_mask(rt); | | 331 | info.rti_info[RTAX_NETMASK] = rt_mask(rt); |
338 | if ((rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) == 0) | | 332 | if ((rtm->rtm_addrs & (RTA_IFP | RTA_IFA)) == 0) |
339 | ; | | 333 | ; |
340 | else if ((ifp = rt->rt_ifp) != NULL) { | | 334 | else if ((ifp = rt->rt_ifp) != NULL) { |
341 | const struct ifaddr *rtifa; | | 335 | const struct ifaddr *rtifa; |
342 | info.rti_info[RTAX_IFP] = ifp->if_dl->ifa_addr; | | 336 | info.rti_info[RTAX_IFP] = ifp->if_dl->ifa_addr; |
343 | /* rtifa used to be simply rt->rt_ifa. | | 337 | /* rtifa used to be simply rt->rt_ifa. |
344 | * If rt->rt_ifa != NULL, then | | 338 | * If rt->rt_ifa != NULL, then |
345 | * rt_get_ifa() != NULL. So this | | 339 | * rt_get_ifa() != NULL. So this |
346 | * ought to still be safe. --dyoung | | 340 | * ought to still be safe. --dyoung |
347 | */ | | 341 | */ |
348 | rtifa = rt_get_ifa(rt); | | 342 | rtifa = rt_get_ifa(rt); |
349 | info.rti_info[RTAX_IFA] = rtifa->ifa_addr; | | 343 | info.rti_info[RTAX_IFA] = rtifa->ifa_addr; |
350 | #ifdef RTSOCK_DEBUG | | 344 | #ifdef RTSOCK_DEBUG |
351 | if (info.rti_info[RTAX_IFA]->sa_family == | | 345 | if (info.rti_info[RTAX_IFA]->sa_family == |
352 | AF_INET) { | | 346 | AF_INET) { |
353 | printf("%s: copying out RTAX_IFA %s ", | | 347 | printf("%s: copying out RTAX_IFA %s ", |
354 | __func__, inet_ntoa( | | 348 | __func__, inet_ntoa( |
355 | (const struct sockaddr_in *) | | 349 | (const struct sockaddr_in *) |
356 | info.rti_info[RTAX_IFA])->sin_addr); | | 350 | info.rti_info[RTAX_IFA])->sin_addr); |
357 | printf("for info.rti_info[RTAX_DST] %s " | | 351 | printf("for info.rti_info[RTAX_DST] %s " |
358 | "ifa_getifa %p ifa_seqno %p\n", | | 352 | "ifa_getifa %p ifa_seqno %p\n", |
359 | inet_ntoa( | | 353 | inet_ntoa( |
360 | (const struct sockaddr_in *) | | 354 | (const struct sockaddr_in *) |
361 | info.rti_info[RTAX_DST])->sin_addr), | | 355 | info.rti_info[RTAX_DST])->sin_addr), |
362 | (void *)rtifa->ifa_getifa, | | 356 | (void *)rtifa->ifa_getifa, |
363 | rtifa->ifa_seqno); | | 357 | rtifa->ifa_seqno); |
364 | } | | 358 | } |
365 | #endif /* RTSOCK_DEBUG */ | | 359 | #endif /* RTSOCK_DEBUG */ |
366 | if (ifp->if_flags & IFF_POINTOPOINT) { | | 360 | if (ifp->if_flags & IFF_POINTOPOINT) { |
367 | info.rti_info[RTAX_BRD] = | | 361 | info.rti_info[RTAX_BRD] = |
368 | rtifa->ifa_dstaddr; | | 362 | rtifa->ifa_dstaddr; |
369 | } else | | 363 | } else |
370 | info.rti_info[RTAX_BRD] = NULL; | | 364 | info.rti_info[RTAX_BRD] = NULL; |
371 | rtm->rtm_index = ifp->if_index; | | 365 | rtm->rtm_index = ifp->if_index; |
372 | } else { | | 366 | } else { |
373 | info.rti_info[RTAX_IFP] = NULL; | | 367 | info.rti_info[RTAX_IFP] = NULL; |
374 | info.rti_info[RTAX_IFA] = NULL; | | 368 | info.rti_info[RTAX_IFA] = NULL; |
375 | } | | 369 | } |
376 | (void)rt_msg2(rtm->rtm_type, &info, NULL, NULL, &len); | | 370 | (void)rt_msg2(rtm->rtm_type, &info, NULL, NULL, &len); |
377 | if (len > rtm->rtm_msglen) { | | 371 | if (len > rtm->rtm_msglen) { |
378 | old_rtm = rtm; | | 372 | old_rtm = rtm; |
379 | R_Malloc(rtm, struct rt_msghdr *, len); | | 373 | R_Malloc(rtm, struct rt_msghdr *, len); |
380 | if (rtm == NULL) | | 374 | if (rtm == NULL) |
381 | senderr(ENOBUFS); | | 375 | senderr(ENOBUFS); |
382 | (void)memcpy(rtm, old_rtm, old_rtm->rtm_msglen); | | 376 | (void)memcpy(rtm, old_rtm, old_rtm->rtm_msglen); |
383 | } | | 377 | } |
384 | (void)rt_msg2(rtm->rtm_type, &info, rtm, NULL, 0); | | 378 | (void)rt_msg2(rtm->rtm_type, &info, rtm, NULL, 0); |
385 | rtm->rtm_flags = rt->rt_flags; | | 379 | rtm->rtm_flags = rt->rt_flags; |
386 | rtm->rtm_rmx = rt->rt_rmx; | | 380 | rtm->rtm_rmx = rt->rt_rmx; |
387 | rtm->rtm_addrs = info.rti_addrs; | | 381 | rtm->rtm_addrs = info.rti_addrs; |
388 | break; | | 382 | break; |
389 | | | 383 | |
390 | case RTM_CHANGE: | | 384 | case RTM_CHANGE: |
391 | /* | | 385 | /* |
392 | * new gateway could require new ifaddr, ifp; | | 386 | * new gateway could require new ifaddr, ifp; |
393 | * flags may also be different; ifp may be specified | | 387 | * flags may also be different; ifp may be specified |
394 | * by ll sockaddr when protocol address is ambiguous | | 388 | * by ll sockaddr when protocol address is ambiguous |
395 | */ | | 389 | */ |
396 | if ((error = rt_getifa(&info)) != 0) | | 390 | if ((error = rt_getifa(&info)) != 0) |
397 | senderr(error); | | 391 | senderr(error); |
398 | if (info.rti_info[RTAX_GATEWAY] && | | 392 | if (info.rti_info[RTAX_GATEWAY] && |
399 | rt_setgate(rt, info.rti_info[RTAX_GATEWAY])) | | 393 | rt_setgate(rt, info.rti_info[RTAX_GATEWAY])) |
400 | senderr(EDQUOT); | | 394 | senderr(EDQUOT); |
401 | /* new gateway could require new ifaddr, ifp; | | 395 | /* new gateway could require new ifaddr, ifp; |
402 | flags may also be different; ifp may be specified | | 396 | flags may also be different; ifp may be specified |
403 | by ll sockaddr when protocol address is ambiguous */ | | 397 | by ll sockaddr when protocol address is ambiguous */ |
404 | if (info.rti_info[RTAX_IFP] && | | 398 | if (info.rti_info[RTAX_IFP] && |
405 | (ifa = ifa_ifwithnet(info.rti_info[RTAX_IFP])) && | | 399 | (ifa = ifa_ifwithnet(info.rti_info[RTAX_IFP])) && |
406 | (ifp = ifa->ifa_ifp) && (info.rti_info[RTAX_IFA] || | | 400 | (ifp = ifa->ifa_ifp) && (info.rti_info[RTAX_IFA] || |
407 | info.rti_info[RTAX_GATEWAY])) { | | 401 | info.rti_info[RTAX_GATEWAY])) { |
408 | ifa = ifaof_ifpforaddr(info.rti_info[RTAX_IFA] ? | | 402 | ifa = ifaof_ifpforaddr(info.rti_info[RTAX_IFA] ? |
409 | info.rti_info[RTAX_IFA] : | | 403 | info.rti_info[RTAX_IFA] : |
410 | info.rti_info[RTAX_GATEWAY], ifp); | | 404 | info.rti_info[RTAX_GATEWAY], ifp); |
411 | } else if ((info.rti_info[RTAX_IFA] && | | 405 | } else if ((info.rti_info[RTAX_IFA] && |
412 | (ifa = ifa_ifwithaddr(info.rti_info[RTAX_IFA]))) || | | 406 | (ifa = ifa_ifwithaddr(info.rti_info[RTAX_IFA]))) || |
413 | (info.rti_info[RTAX_GATEWAY] && | | 407 | (info.rti_info[RTAX_GATEWAY] && |
414 | (ifa = ifa_ifwithroute(rt->rt_flags, | | 408 | (ifa = ifa_ifwithroute(rt->rt_flags, |
415 | rt_getkey(rt), info.rti_info[RTAX_GATEWAY])))) { | | 409 | rt_getkey(rt), info.rti_info[RTAX_GATEWAY])))) { |
416 | ifp = ifa->ifa_ifp; | | 410 | ifp = ifa->ifa_ifp; |
417 | } | | 411 | } |
418 | oifa = rt->rt_ifa; | | | |
419 | if (oifa && oifa->ifa_flags & IFA_ROUTE) { | | | |
420 | /* | | | |
421 | * If changing an automatically added route, | | | |
422 | * remove the flag and store the fact. | | | |
423 | */ | | | |
424 | oifa->ifa_flags &= ~IFA_ROUTE; | | | |
425 | ifa_route = 1; | | | |
426 | } | | | |
427 | if (ifa) { | | 412 | if (ifa) { |
| | | 413 | struct ifaddr *oifa = rt->rt_ifa; |
428 | if (oifa != ifa) { | | 414 | if (oifa != ifa) { |
429 | if (oifa && oifa->ifa_rtrequest) { | | 415 | if (oifa && oifa->ifa_rtrequest) { |
430 | oifa->ifa_rtrequest(RTM_DELETE, | | 416 | oifa->ifa_rtrequest(RTM_DELETE, |
431 | rt, &info); | | 417 | rt, &info); |
432 | } | | 418 | } |
433 | /* | | | |
434 | * If changing an automatically added | | | |
435 | * route, store this if not static. | | | |
436 | */ | | | |
437 | if (ifa_route && | | | |
438 | !(rt->rt_flags & RTF_STATIC)) | | | |
439 | ifa->ifa_flags |= IFA_ROUTE; | | | |
440 | rt_replace_ifa(rt, ifa); | | 419 | rt_replace_ifa(rt, ifa); |
441 | rt->rt_ifp = ifp; | | 420 | rt->rt_ifp = ifp; |
442 | } | | 421 | } |
443 | } | | 422 | } |
444 | rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, | | 423 | rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, |
445 | &rt->rt_rmx); | | 424 | &rt->rt_rmx); |
446 | if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) | | 425 | if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest) |
447 | rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info); | | 426 | rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info); |
448 | /*FALLTHROUGH*/ | | 427 | /*FALLTHROUGH*/ |
449 | case RTM_LOCK: | | 428 | case RTM_LOCK: |
450 | rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); | | 429 | rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits); |
451 | rt->rt_rmx.rmx_locks |= | | 430 | rt->rt_rmx.rmx_locks |= |
452 | (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); | | 431 | (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks); |
453 | break; | | 432 | break; |
454 | } | | 433 | } |
455 | break; | | 434 | break; |
456 | | | 435 | |
457 | default: | | 436 | default: |
458 | senderr(EOPNOTSUPP); | | 437 | senderr(EOPNOTSUPP); |
459 | } | | 438 | } |
460 | | | 439 | |
461 | flush: | | 440 | flush: |
462 | if (rtm) { | | 441 | if (rtm) { |
463 | if (error) | | 442 | if (error) |
464 | rtm->rtm_errno = error; | | 443 | rtm->rtm_errno = error; |
465 | else | | 444 | else |
466 | rtm->rtm_flags |= RTF_DONE; | | 445 | rtm->rtm_flags |= RTF_DONE; |
467 | } | | 446 | } |
468 | family = info.rti_info[RTAX_DST] ? info.rti_info[RTAX_DST]->sa_family : | | 447 | family = info.rti_info[RTAX_DST] ? info.rti_info[RTAX_DST]->sa_family : |
469 | 0; | | 448 | 0; |
470 | /* We cannot free old_rtm until we have stopped using the | | 449 | /* We cannot free old_rtm until we have stopped using the |
471 | * pointers in info, some of which may point to sockaddrs | | 450 | * pointers in info, some of which may point to sockaddrs |
472 | * in old_rtm. | | 451 | * in old_rtm. |
473 | */ | | 452 | */ |
474 | if (old_rtm != NULL) | | 453 | if (old_rtm != NULL) |
475 | Free(old_rtm); | | 454 | Free(old_rtm); |
476 | if (rt) | | 455 | if (rt) |
477 | rtfree(rt); | | 456 | rtfree(rt); |
478 | { | | 457 | { |
479 | struct rawcb *rp = NULL; | | 458 | struct rawcb *rp = NULL; |
480 | /* | | 459 | /* |
481 | * Check to see if we don't want our own messages. | | 460 | * Check to see if we don't want our own messages. |
482 | */ | | 461 | */ |
483 | if ((so->so_options & SO_USELOOPBACK) == 0) { | | 462 | if ((so->so_options & SO_USELOOPBACK) == 0) { |
484 | if (route_cb.any_count <= 1) { | | 463 | if (route_cb.any_count <= 1) { |
485 | if (rtm) | | 464 | if (rtm) |
486 | Free(rtm); | | 465 | Free(rtm); |
487 | m_freem(m); | | 466 | m_freem(m); |
488 | return error; | | 467 | return error; |
489 | } | | 468 | } |
490 | /* There is another listener, so construct message */ | | 469 | /* There is another listener, so construct message */ |
491 | rp = sotorawcb(so); | | 470 | rp = sotorawcb(so); |
492 | } | | 471 | } |
493 | if (rtm) { | | 472 | if (rtm) { |
494 | m_copyback(m, 0, rtm->rtm_msglen, rtm); | | 473 | m_copyback(m, 0, rtm->rtm_msglen, rtm); |
495 | if (m->m_pkthdr.len < rtm->rtm_msglen) { | | 474 | if (m->m_pkthdr.len < rtm->rtm_msglen) { |
496 | m_freem(m); | | 475 | m_freem(m); |
497 | m = NULL; | | 476 | m = NULL; |
498 | } else if (m->m_pkthdr.len > rtm->rtm_msglen) | | 477 | } else if (m->m_pkthdr.len > rtm->rtm_msglen) |
499 | m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len); | | 478 | m_adj(m, rtm->rtm_msglen - m->m_pkthdr.len); |
500 | Free(rtm); | | 479 | Free(rtm); |
501 | } | | 480 | } |
502 | if (rp) | | 481 | if (rp) |
503 | rp->rcb_proto.sp_family = 0; /* Avoid us */ | | 482 | rp->rcb_proto.sp_family = 0; /* Avoid us */ |
504 | if (family) | | 483 | if (family) |
505 | proto.sp_protocol = family; | | 484 | proto.sp_protocol = family; |
506 | if (m) | | 485 | if (m) |
507 | raw_input(m, &proto, &route_src, &route_dst); | | 486 | raw_input(m, &proto, &route_src, &route_dst); |
508 | if (rp) | | 487 | if (rp) |
509 | rp->rcb_proto.sp_family = PF_ROUTE; | | 488 | rp->rcb_proto.sp_family = PF_ROUTE; |
510 | } | | 489 | } |
511 | return error; | | 490 | return error; |
512 | } | | 491 | } |
513 | | | 492 | |
514 | void | | 493 | void |
515 | rt_setmetrics(u_long which, const struct rt_metrics *in, struct rt_metrics *out) | | 494 | rt_setmetrics(u_long which, const struct rt_metrics *in, struct rt_metrics *out) |
516 | { | | 495 | { |
517 | #define metric(f, e) if (which & (f)) out->e = in->e; | | 496 | #define metric(f, e) if (which & (f)) out->e = in->e; |
518 | metric(RTV_RPIPE, rmx_recvpipe); | | 497 | metric(RTV_RPIPE, rmx_recvpipe); |
519 | metric(RTV_SPIPE, rmx_sendpipe); | | 498 | metric(RTV_SPIPE, rmx_sendpipe); |
520 | metric(RTV_SSTHRESH, rmx_ssthresh); | | 499 | metric(RTV_SSTHRESH, rmx_ssthresh); |
521 | metric(RTV_RTT, rmx_rtt); | | 500 | metric(RTV_RTT, rmx_rtt); |
522 | metric(RTV_RTTVAR, rmx_rttvar); | | 501 | metric(RTV_RTTVAR, rmx_rttvar); |
523 | metric(RTV_HOPCOUNT, rmx_hopcount); | | 502 | metric(RTV_HOPCOUNT, rmx_hopcount); |
524 | metric(RTV_MTU, rmx_mtu); | | 503 | metric(RTV_MTU, rmx_mtu); |
525 | metric(RTV_EXPIRE, rmx_expire); | | 504 | metric(RTV_EXPIRE, rmx_expire); |
526 | #undef metric | | 505 | #undef metric |
527 | } | | 506 | } |
528 | | | 507 | |
529 | #define ROUNDUP(a) \ | | 508 | #define ROUNDUP(a) \ |
530 | ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) | | 509 | ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) |
531 | #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) | | 510 | #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) |
532 | | | 511 | |
533 | static int | | 512 | static int |
534 | rt_xaddrs(u_char rtmtype, const char *cp, const char *cplim, | | 513 | rt_xaddrs(u_char rtmtype, const char *cp, const char *cplim, |
535 | struct rt_addrinfo *rtinfo) | | 514 | struct rt_addrinfo *rtinfo) |
536 | { | | 515 | { |
537 | const struct sockaddr *sa = NULL; /* Quell compiler warning */ | | 516 | const struct sockaddr *sa = NULL; /* Quell compiler warning */ |
538 | int i; | | 517 | int i; |
539 | | | 518 | |
540 | for (i = 0; i < RTAX_MAX && cp < cplim; i++) { | | 519 | for (i = 0; i < RTAX_MAX && cp < cplim; i++) { |
541 | if ((rtinfo->rti_addrs & (1 << i)) == 0) | | 520 | if ((rtinfo->rti_addrs & (1 << i)) == 0) |
542 | continue; | | 521 | continue; |
543 | rtinfo->rti_info[i] = sa = (const struct sockaddr *)cp; | | 522 | rtinfo->rti_info[i] = sa = (const struct sockaddr *)cp; |
544 | ADVANCE(cp, sa); | | 523 | ADVANCE(cp, sa); |
545 | } | | 524 | } |
546 | | | 525 | |
547 | /* | | 526 | /* |
548 | * Check for extra addresses specified, except RTM_GET asking | | 527 | * Check for extra addresses specified, except RTM_GET asking |
549 | * for interface info. | | 528 | * for interface info. |
550 | */ | | 529 | */ |
551 | if (rtmtype == RTM_GET) { | | 530 | if (rtmtype == RTM_GET) { |
552 | if (((rtinfo->rti_addrs & | | 531 | if (((rtinfo->rti_addrs & |
553 | (~((1 << RTAX_IFP) | (1 << RTAX_IFA)))) & (~0 << i)) != 0) | | 532 | (~((1 << RTAX_IFP) | (1 << RTAX_IFA)))) & (~0 << i)) != 0) |
554 | return 1; | | 533 | return 1; |
555 | } else if ((rtinfo->rti_addrs & (~0 << i)) != 0) | | 534 | } else if ((rtinfo->rti_addrs & (~0 << i)) != 0) |
556 | return 1; | | 535 | return 1; |
557 | /* Check for bad data length. */ | | 536 | /* Check for bad data length. */ |
558 | if (cp != cplim) { | | 537 | if (cp != cplim) { |
559 | if (i == RTAX_NETMASK + 1 && sa != NULL && | | 538 | if (i == RTAX_NETMASK + 1 && sa != NULL && |
560 | cp - ROUNDUP(sa->sa_len) + sa->sa_len == cplim) | | 539 | cp - ROUNDUP(sa->sa_len) + sa->sa_len == cplim) |
561 | /* | | 540 | /* |
562 | * The last sockaddr was info.rti_info[RTAX_NETMASK]. | | 541 | * The last sockaddr was info.rti_info[RTAX_NETMASK]. |
563 | * We accept this for now for the sake of old | | 542 | * We accept this for now for the sake of old |
564 | * binaries or third party softwares. | | 543 | * binaries or third party softwares. |
565 | */ | | 544 | */ |
566 | ; | | 545 | ; |
567 | else | | 546 | else |
568 | return 1; | | 547 | return 1; |
569 | } | | 548 | } |
570 | return 0; | | 549 | return 0; |
571 | } | | 550 | } |
572 | | | 551 | |
573 | static struct mbuf * | | 552 | static struct mbuf * |
574 | rt_msg1(int type, struct rt_addrinfo *rtinfo, void *data, int datalen) | | 553 | rt_msg1(int type, struct rt_addrinfo *rtinfo, void *data, int datalen) |
575 | { | | 554 | { |
576 | struct rt_msghdr *rtm; | | 555 | struct rt_msghdr *rtm; |
577 | struct mbuf *m; | | 556 | struct mbuf *m; |
578 | int i; | | 557 | int i; |
579 | const struct sockaddr *sa; | | 558 | const struct sockaddr *sa; |
580 | int len, dlen; | | 559 | int len, dlen; |
581 | | | 560 | |
582 | m = m_gethdr(M_DONTWAIT, MT_DATA); | | 561 | m = m_gethdr(M_DONTWAIT, MT_DATA); |
583 | if (m == NULL) | | 562 | if (m == NULL) |
584 | return m; | | 563 | return m; |
585 | MCLAIM(m, &routedomain.dom_mowner); | | 564 | MCLAIM(m, &routedomain.dom_mowner); |
586 | switch (type) { | | 565 | switch (type) { |
587 | | | 566 | |
588 | case RTM_DELADDR: | | 567 | case RTM_DELADDR: |
589 | case RTM_NEWADDR: | | 568 | case RTM_NEWADDR: |
590 | len = sizeof(struct ifa_msghdr); | | 569 | len = sizeof(struct ifa_msghdr); |
591 | break; | | 570 | break; |
592 | | | 571 | |
593 | #ifdef COMPAT_14 | | 572 | #ifdef COMPAT_14 |
594 | case RTM_OIFINFO: | | 573 | case RTM_OIFINFO: |
595 | len = sizeof(struct if_msghdr14); | | 574 | len = sizeof(struct if_msghdr14); |
596 | break; | | 575 | break; |
597 | #endif | | 576 | #endif |
598 | | | 577 | |
599 | case RTM_IFINFO: | | 578 | case RTM_IFINFO: |
600 | len = sizeof(struct if_msghdr); | | 579 | len = sizeof(struct if_msghdr); |
601 | break; | | 580 | break; |
602 | | | 581 | |
603 | case RTM_IFANNOUNCE: | | 582 | case RTM_IFANNOUNCE: |
604 | case RTM_IEEE80211: | | 583 | case RTM_IEEE80211: |
605 | len = sizeof(struct if_announcemsghdr); | | 584 | len = sizeof(struct if_announcemsghdr); |
606 | break; | | 585 | break; |
607 | | | 586 | |
608 | default: | | 587 | default: |
609 | len = sizeof(struct rt_msghdr); | | 588 | len = sizeof(struct rt_msghdr); |
610 | } | | 589 | } |
611 | if (len > MHLEN + MLEN) | | 590 | if (len > MHLEN + MLEN) |
612 | panic("rt_msg1: message too long"); | | 591 | panic("rt_msg1: message too long"); |
613 | else if (len > MHLEN) { | | 592 | else if (len > MHLEN) { |
614 | m->m_next = m_get(M_DONTWAIT, MT_DATA); | | 593 | m->m_next = m_get(M_DONTWAIT, MT_DATA); |
615 | if (m->m_next == NULL) { | | 594 | if (m->m_next == NULL) { |
616 | m_freem(m); | | 595 | m_freem(m); |
617 | return NULL; | | 596 | return NULL; |
618 | } | | 597 | } |
619 | MCLAIM(m->m_next, m->m_owner); | | 598 | MCLAIM(m->m_next, m->m_owner); |
620 | m->m_pkthdr.len = len; | | 599 | m->m_pkthdr.len = len; |
621 | m->m_len = MHLEN; | | 600 | m->m_len = MHLEN; |
622 | m->m_next->m_len = len - MHLEN; | | 601 | m->m_next->m_len = len - MHLEN; |
623 | } else { | | 602 | } else { |
624 | m->m_pkthdr.len = m->m_len = len; | | 603 | m->m_pkthdr.len = m->m_len = len; |
625 | } | | 604 | } |
626 | m->m_pkthdr.rcvif = NULL; | | 605 | m->m_pkthdr.rcvif = NULL; |
627 | m_copyback(m, 0, datalen, data); | | 606 | m_copyback(m, 0, datalen, data); |
628 | if (len > datalen) | | 607 | if (len > datalen) |
629 | (void)memset(mtod(m, char *) + datalen, 0, len - datalen); | | 608 | (void)memset(mtod(m, char *) + datalen, 0, len - datalen); |
630 | rtm = mtod(m, struct rt_msghdr *); | | 609 | rtm = mtod(m, struct rt_msghdr *); |
631 | for (i = 0; i < RTAX_MAX; i++) { | | 610 | for (i = 0; i < RTAX_MAX; i++) { |
632 | if ((sa = rtinfo->rti_info[i]) == NULL) | | 611 | if ((sa = rtinfo->rti_info[i]) == NULL) |
633 | continue; | | 612 | continue; |
634 | rtinfo->rti_addrs |= (1 << i); | | 613 | rtinfo->rti_addrs |= (1 << i); |
635 | dlen = ROUNDUP(sa->sa_len); | | 614 | dlen = ROUNDUP(sa->sa_len); |
636 | m_copyback(m, len, dlen, sa); | | 615 | m_copyback(m, len, dlen, sa); |
637 | len += dlen; | | 616 | len += dlen; |
638 | } | | 617 | } |
639 | if (m->m_pkthdr.len != len) { | | 618 | if (m->m_pkthdr.len != len) { |
640 | m_freem(m); | | 619 | m_freem(m); |
641 | return NULL; | | 620 | return NULL; |
642 | } | | 621 | } |
643 | rtm->rtm_msglen = len; | | 622 | rtm->rtm_msglen = len; |
644 | rtm->rtm_version = RTM_VERSION; | | 623 | rtm->rtm_version = RTM_VERSION; |
645 | rtm->rtm_type = type; | | 624 | rtm->rtm_type = type; |
646 | return m; | | 625 | return m; |
647 | } | | 626 | } |
648 | | | 627 | |
649 | /* | | 628 | /* |
650 | * rt_msg2 | | 629 | * rt_msg2 |
651 | * | | 630 | * |
652 | * fills 'cp' or 'w'.w_tmem with the routing socket message and | | 631 | * fills 'cp' or 'w'.w_tmem with the routing socket message and |
653 | * returns the length of the message in 'lenp'. | | 632 | * returns the length of the message in 'lenp'. |
654 | * | | 633 | * |
655 | * if walkarg is 0, cp is expected to be 0 or a buffer large enough to hold | | 634 | * if walkarg is 0, cp is expected to be 0 or a buffer large enough to hold |
656 | * the message | | 635 | * the message |
657 | * otherwise walkarg's w_needed is updated and if the user buffer is | | 636 | * otherwise walkarg's w_needed is updated and if the user buffer is |
658 | * specified and w_needed indicates space exists the information is copied | | 637 | * specified and w_needed indicates space exists the information is copied |
659 | * into the temp space (w_tmem). w_tmem is [re]allocated if necessary, | | 638 | * into the temp space (w_tmem). w_tmem is [re]allocated if necessary, |
660 | * if the allocation fails ENOBUFS is returned. | | 639 | * if the allocation fails ENOBUFS is returned. |
661 | */ | | 640 | */ |
662 | static int | | 641 | static int |
663 | rt_msg2(int type, struct rt_addrinfo *rtinfo, void *cpv, struct walkarg *w, | | 642 | rt_msg2(int type, struct rt_addrinfo *rtinfo, void *cpv, struct walkarg *w, |
664 | int *lenp) | | 643 | int *lenp) |
665 | { | | 644 | { |
666 | int i; | | 645 | int i; |
667 | int len, dlen, second_time = 0; | | 646 | int len, dlen, second_time = 0; |
668 | char *cp0, *cp = cpv; | | 647 | char *cp0, *cp = cpv; |
669 | | | 648 | |
670 | rtinfo->rti_addrs = 0; | | 649 | rtinfo->rti_addrs = 0; |
671 | again: | | 650 | again: |
672 | switch (type) { | | 651 | switch (type) { |
673 | | | 652 | |
674 | case RTM_DELADDR: | | 653 | case RTM_DELADDR: |
675 | case RTM_NEWADDR: | | 654 | case RTM_NEWADDR: |
676 | len = sizeof(struct ifa_msghdr); | | 655 | len = sizeof(struct ifa_msghdr); |
677 | break; | | 656 | break; |
678 | #ifdef COMPAT_14 | | 657 | #ifdef COMPAT_14 |
679 | case RTM_OIFINFO: | | 658 | case RTM_OIFINFO: |
680 | len = sizeof(struct if_msghdr14); | | 659 | len = sizeof(struct if_msghdr14); |
681 | break; | | 660 | break; |
682 | #endif | | 661 | #endif |
683 | | | 662 | |
684 | case RTM_IFINFO: | | 663 | case RTM_IFINFO: |
685 | len = sizeof(struct if_msghdr); | | 664 | len = sizeof(struct if_msghdr); |
686 | break; | | 665 | break; |
687 | | | 666 | |
688 | default: | | 667 | default: |
689 | len = sizeof(struct rt_msghdr); | | 668 | len = sizeof(struct rt_msghdr); |
690 | } | | 669 | } |
691 | if ((cp0 = cp) != NULL) | | 670 | if ((cp0 = cp) != NULL) |
692 | cp += len; | | 671 | cp += len; |
693 | for (i = 0; i < RTAX_MAX; i++) { | | 672 | for (i = 0; i < RTAX_MAX; i++) { |
694 | const struct sockaddr *sa; | | 673 | const struct sockaddr *sa; |
695 | | | 674 | |
696 | if ((sa = rtinfo->rti_info[i]) == NULL) | | 675 | if ((sa = rtinfo->rti_info[i]) == NULL) |
697 | continue; | | 676 | continue; |
698 | rtinfo->rti_addrs |= (1 << i); | | 677 | rtinfo->rti_addrs |= (1 << i); |
699 | dlen = ROUNDUP(sa->sa_len); | | 678 | dlen = ROUNDUP(sa->sa_len); |
700 | if (cp) { | | 679 | if (cp) { |
701 | (void)memcpy(cp, sa, (size_t)dlen); | | 680 | (void)memcpy(cp, sa, (size_t)dlen); |
702 | cp += dlen; | | 681 | cp += dlen; |
703 | } | | 682 | } |
704 | len += dlen; | | 683 | len += dlen; |
705 | } | | 684 | } |
706 | if (cp == NULL && w != NULL && !second_time) { | | 685 | if (cp == NULL && w != NULL && !second_time) { |
707 | struct walkarg *rw = w; | | 686 | struct walkarg *rw = w; |
708 | | | 687 | |
709 | rw->w_needed += len; | | 688 | rw->w_needed += len; |
710 | if (rw->w_needed <= 0 && rw->w_where) { | | 689 | if (rw->w_needed <= 0 && rw->w_where) { |
711 | if (rw->w_tmemsize < len) { | | 690 | if (rw->w_tmemsize < len) { |
712 | if (rw->w_tmem) | | 691 | if (rw->w_tmem) |
713 | free(rw->w_tmem, M_RTABLE); | | 692 | free(rw->w_tmem, M_RTABLE); |
714 | rw->w_tmem = malloc(len, M_RTABLE, M_NOWAIT); | | 693 | rw->w_tmem = malloc(len, M_RTABLE, M_NOWAIT); |
715 | if (rw->w_tmem) | | 694 | if (rw->w_tmem) |
716 | rw->w_tmemsize = len; | | 695 | rw->w_tmemsize = len; |
717 | else | | 696 | else |
718 | rw->w_tmemsize = 0; | | 697 | rw->w_tmemsize = 0; |
719 | } | | 698 | } |
720 | if (rw->w_tmem) { | | 699 | if (rw->w_tmem) { |
721 | cp = rw->w_tmem; | | 700 | cp = rw->w_tmem; |
722 | second_time = 1; | | 701 | second_time = 1; |
723 | goto again; | | 702 | goto again; |
724 | } else { | | 703 | } else { |
725 | rw->w_tmemneeded = len; | | 704 | rw->w_tmemneeded = len; |
726 | return ENOBUFS; | | 705 | return ENOBUFS; |
727 | } | | 706 | } |
728 | } | | 707 | } |
729 | } | | 708 | } |
730 | if (cp) { | | 709 | if (cp) { |
731 | struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; | | 710 | struct rt_msghdr *rtm = (struct rt_msghdr *)cp0; |
732 | | | 711 | |
733 | rtm->rtm_version = RTM_VERSION; | | 712 | rtm->rtm_version = RTM_VERSION; |
734 | rtm->rtm_type = type; | | 713 | rtm->rtm_type = type; |
735 | rtm->rtm_msglen = len; | | 714 | rtm->rtm_msglen = len; |
736 | } | | 715 | } |
737 | if (lenp) | | 716 | if (lenp) |
738 | *lenp = len; | | 717 | *lenp = len; |
739 | return 0; | | 718 | return 0; |
740 | } | | 719 | } |
741 | | | 720 | |
742 | /* | | 721 | /* |
743 | * This routine is called to generate a message from the routing | | 722 | * This routine is called to generate a message from the routing |
744 | * socket indicating that a redirect has occurred, a routing lookup | | 723 | * socket indicating that a redirect has occurred, a routing lookup |
745 | * has failed, or that a protocol has detected timeouts to a particular | | 724 | * has failed, or that a protocol has detected timeouts to a particular |
746 | * destination. | | 725 | * destination. |
747 | */ | | 726 | */ |
748 | void | | 727 | void |
749 | rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, int error) | | 728 | rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, int error) |
750 | { | | 729 | { |
751 | struct rt_msghdr rtm; | | 730 | struct rt_msghdr rtm; |
752 | struct mbuf *m; | | 731 | struct mbuf *m; |
753 | const struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; | | 732 | const struct sockaddr *sa = rtinfo->rti_info[RTAX_DST]; |
754 | | | 733 | |
755 | if (route_cb.any_count == 0) | | 734 | if (route_cb.any_count == 0) |
756 | return; | | 735 | return; |
757 | memset(&rtm, 0, sizeof(rtm)); | | 736 | memset(&rtm, 0, sizeof(rtm)); |
758 | rtm.rtm_flags = RTF_DONE | flags; | | 737 | rtm.rtm_flags = RTF_DONE | flags; |
759 | rtm.rtm_errno = error; | | 738 | rtm.rtm_errno = error; |
760 | m = rt_msg1(type, rtinfo, &rtm, sizeof(rtm)); | | 739 | m = rt_msg1(type, rtinfo, &rtm, sizeof(rtm)); |
761 | if (m == NULL) | | 740 | if (m == NULL) |
762 | return; | | 741 | return; |
763 | mtod(m, struct rt_msghdr *)->rtm_addrs = rtinfo->rti_addrs; | | 742 | mtod(m, struct rt_msghdr *)->rtm_addrs = rtinfo->rti_addrs; |
764 | route_enqueue(m, sa ? sa->sa_family : 0); | | 743 | route_enqueue(m, sa ? sa->sa_family : 0); |
765 | } | | 744 | } |
766 | | | 745 | |
767 | /* | | 746 | /* |
768 | * This routine is called to generate a message from the routing | | 747 | * This routine is called to generate a message from the routing |
769 | * socket indicating that the status of a network interface has changed. | | 748 | * socket indicating that the status of a network interface has changed. |
770 | */ | | 749 | */ |
771 | void | | 750 | void |
772 | rt_ifmsg(struct ifnet *ifp) | | 751 | rt_ifmsg(struct ifnet *ifp) |
773 | { | | 752 | { |
774 | struct if_msghdr ifm; | | 753 | struct if_msghdr ifm; |
775 | #ifdef COMPAT_14 | | 754 | #ifdef COMPAT_14 |
776 | struct if_msghdr14 oifm; | | 755 | struct if_msghdr14 oifm; |
777 | #endif | | 756 | #endif |
778 | struct mbuf *m; | | 757 | struct mbuf *m; |
779 | struct rt_addrinfo info; | | 758 | struct rt_addrinfo info; |
780 | | | 759 | |
781 | if (route_cb.any_count == 0) | | 760 | if (route_cb.any_count == 0) |
782 | return; | | 761 | return; |
783 | memset(&info, 0, sizeof(info)); | | 762 | memset(&info, 0, sizeof(info)); |
784 | memset(&ifm, 0, sizeof(ifm)); | | 763 | memset(&ifm, 0, sizeof(ifm)); |
785 | ifm.ifm_index = ifp->if_index; | | 764 | ifm.ifm_index = ifp->if_index; |
786 | ifm.ifm_flags = ifp->if_flags; | | 765 | ifm.ifm_flags = ifp->if_flags; |
787 | ifm.ifm_data = ifp->if_data; | | 766 | ifm.ifm_data = ifp->if_data; |
788 | ifm.ifm_addrs = 0; | | 767 | ifm.ifm_addrs = 0; |
789 | m = rt_msg1(RTM_IFINFO, &info, &ifm, sizeof(ifm)); | | 768 | m = rt_msg1(RTM_IFINFO, &info, &ifm, sizeof(ifm)); |
790 | if (m == NULL) | | 769 | if (m == NULL) |
791 | return; | | 770 | return; |
792 | route_enqueue(m, 0); | | 771 | route_enqueue(m, 0); |
793 | #ifdef COMPAT_14 | | 772 | #ifdef COMPAT_14 |
794 | memset(&info, 0, sizeof(info)); | | 773 | memset(&info, 0, sizeof(info)); |
795 | memset(&oifm, 0, sizeof(oifm)); | | 774 | memset(&oifm, 0, sizeof(oifm)); |
796 | oifm.ifm_index = ifp->if_index; | | 775 | oifm.ifm_index = ifp->if_index; |
797 | oifm.ifm_flags = ifp->if_flags; | | 776 | oifm.ifm_flags = ifp->if_flags; |
798 | oifm.ifm_data.ifi_type = ifp->if_data.ifi_type; | | 777 | oifm.ifm_data.ifi_type = ifp->if_data.ifi_type; |
799 | oifm.ifm_data.ifi_addrlen = ifp->if_data.ifi_addrlen; | | 778 | oifm.ifm_data.ifi_addrlen = ifp->if_data.ifi_addrlen; |
800 | oifm.ifm_data.ifi_hdrlen = ifp->if_data.ifi_hdrlen; | | 779 | oifm.ifm_data.ifi_hdrlen = ifp->if_data.ifi_hdrlen; |
801 | oifm.ifm_data.ifi_mtu = ifp->if_data.ifi_mtu; | | 780 | oifm.ifm_data.ifi_mtu = ifp->if_data.ifi_mtu; |
802 | oifm.ifm_data.ifi_metric = ifp->if_data.ifi_metric; | | 781 | oifm.ifm_data.ifi_metric = ifp->if_data.ifi_metric; |
803 | oifm.ifm_data.ifi_baudrate = ifp->if_data.ifi_baudrate; | | 782 | oifm.ifm_data.ifi_baudrate = ifp->if_data.ifi_baudrate; |
804 | oifm.ifm_data.ifi_ipackets = ifp->if_data.ifi_ipackets; | | 783 | oifm.ifm_data.ifi_ipackets = ifp->if_data.ifi_ipackets; |
805 | oifm.ifm_data.ifi_ierrors = ifp->if_data.ifi_ierrors; | | 784 | oifm.ifm_data.ifi_ierrors = ifp->if_data.ifi_ierrors; |
806 | oifm.ifm_data.ifi_opackets = ifp->if_data.ifi_opackets; | | 785 | oifm.ifm_data.ifi_opackets = ifp->if_data.ifi_opackets; |
807 | oifm.ifm_data.ifi_oerrors = ifp->if_data.ifi_oerrors; | | 786 | oifm.ifm_data.ifi_oerrors = ifp->if_data.ifi_oerrors; |
808 | oifm.ifm_data.ifi_collisions = ifp->if_data.ifi_collisions; | | 787 | oifm.ifm_data.ifi_collisions = ifp->if_data.ifi_collisions; |
809 | oifm.ifm_data.ifi_ibytes = ifp->if_data.ifi_ibytes; | | 788 | oifm.ifm_data.ifi_ibytes = ifp->if_data.ifi_ibytes; |
810 | oifm.ifm_data.ifi_obytes = ifp->if_data.ifi_obytes; | | 789 | oifm.ifm_data.ifi_obytes = ifp->if_data.ifi_obytes; |
811 | oifm.ifm_data.ifi_imcasts = ifp->if_data.ifi_imcasts; | | 790 | oifm.ifm_data.ifi_imcasts = ifp->if_data.ifi_imcasts; |
812 | oifm.ifm_data.ifi_omcasts = ifp->if_data.ifi_omcasts; | | 791 | oifm.ifm_data.ifi_omcasts = ifp->if_data.ifi_omcasts; |
813 | oifm.ifm_data.ifi_iqdrops = ifp->if_data.ifi_iqdrops; | | 792 | oifm.ifm_data.ifi_iqdrops = ifp->if_data.ifi_iqdrops; |
814 | oifm.ifm_data.ifi_noproto = ifp->if_data.ifi_noproto; | | 793 | oifm.ifm_data.ifi_noproto = ifp->if_data.ifi_noproto; |
815 | oifm.ifm_data.ifi_lastchange = ifp->if_data.ifi_lastchange; | | 794 | oifm.ifm_data.ifi_lastchange = ifp->if_data.ifi_lastchange; |
816 | oifm.ifm_addrs = 0; | | 795 | oifm.ifm_addrs = 0; |
817 | m = rt_msg1(RTM_OIFINFO, &info, &oifm, sizeof(oifm)); | | 796 | m = rt_msg1(RTM_OIFINFO, &info, &oifm, sizeof(oifm)); |
818 | if (m == NULL) | | 797 | if (m == NULL) |
819 | return; | | 798 | return; |
820 | route_enqueue(m, 0); | | 799 | route_enqueue(m, 0); |
821 | #endif | | 800 | #endif |
822 | } | | 801 | } |
823 | | | 802 | |
824 | /* | | 803 | /* |
825 | * This is called to generate messages from the routing socket | | 804 | * This is called to generate messages from the routing socket |
826 | * indicating a network interface has had addresses associated with it. | | 805 | * indicating a network interface has had addresses associated with it. |
827 | * if we ever reverse the logic and replace messages TO the routing | | 806 | * if we ever reverse the logic and replace messages TO the routing |
828 | * socket indicate a request to configure interfaces, then it will | | 807 | * socket indicate a request to configure interfaces, then it will |
829 | * be unnecessary as the routing socket will automatically generate | | 808 | * be unnecessary as the routing socket will automatically generate |
830 | * copies of it. | | 809 | * copies of it. |
831 | */ | | 810 | */ |
832 | void | | 811 | void |
833 | rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt) | | 812 | rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt) |
834 | { | | 813 | { |
835 | struct rt_addrinfo info; | | 814 | struct rt_addrinfo info; |
836 | const struct sockaddr *sa = NULL; | | 815 | const struct sockaddr *sa = NULL; |
837 | int pass; | | 816 | int pass; |
838 | struct mbuf *m = NULL; | | 817 | struct mbuf *m = NULL; |
839 | struct ifnet *ifp = ifa->ifa_ifp; | | 818 | struct ifnet *ifp = ifa->ifa_ifp; |
840 | | | 819 | |
841 | if (route_cb.any_count == 0) | | 820 | if (route_cb.any_count == 0) |
842 | return; | | 821 | return; |
843 | for (pass = 1; pass < 3; pass++) { | | 822 | for (pass = 1; pass < 3; pass++) { |
844 | memset(&info, 0, sizeof(info)); | | 823 | memset(&info, 0, sizeof(info)); |
845 | if ((cmd == RTM_ADD && pass == 1) || | | 824 | if ((cmd == RTM_ADD && pass == 1) || |
846 | (cmd == RTM_DELETE && pass == 2)) { | | 825 | (cmd == RTM_DELETE && pass == 2)) { |
847 | struct ifa_msghdr ifam; | | 826 | struct ifa_msghdr ifam; |
848 | int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR; | | 827 | int ncmd = cmd == RTM_ADD ? RTM_NEWADDR : RTM_DELADDR; |
849 | | | 828 | |
850 | info.rti_info[RTAX_IFA] = sa = ifa->ifa_addr; | | 829 | info.rti_info[RTAX_IFA] = sa = ifa->ifa_addr; |
851 | info.rti_info[RTAX_IFP] = ifp->if_dl->ifa_addr; | | 830 | info.rti_info[RTAX_IFP] = ifp->if_dl->ifa_addr; |
852 | info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; | | 831 | info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; |
853 | info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; | | 832 | info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; |
854 | memset(&ifam, 0, sizeof(ifam)); | | 833 | memset(&ifam, 0, sizeof(ifam)); |
855 | ifam.ifam_index = ifp->if_index; | | 834 | ifam.ifam_index = ifp->if_index; |
856 | ifam.ifam_metric = ifa->ifa_metric; | | 835 | ifam.ifam_metric = ifa->ifa_metric; |
857 | ifam.ifam_flags = ifa->ifa_flags; | | 836 | ifam.ifam_flags = ifa->ifa_flags; |
858 | m = rt_msg1(ncmd, &info, &ifam, sizeof(ifam)); | | 837 | m = rt_msg1(ncmd, &info, &ifam, sizeof(ifam)); |
859 | if (m == NULL) | | 838 | if (m == NULL) |
860 | continue; | | 839 | continue; |
861 | mtod(m, struct ifa_msghdr *)->ifam_addrs = | | 840 | mtod(m, struct ifa_msghdr *)->ifam_addrs = |
862 | info.rti_addrs; | | 841 | info.rti_addrs; |
863 | } | | 842 | } |
864 | if ((cmd == RTM_ADD && pass == 2) || | | 843 | if ((cmd == RTM_ADD && pass == 2) || |
865 | (cmd == RTM_DELETE && pass == 1)) { | | 844 | (cmd == RTM_DELETE && pass == 1)) { |
866 | struct rt_msghdr rtm; | | 845 | struct rt_msghdr rtm; |
867 | | | 846 | |
868 | if (rt == NULL) | | 847 | if (rt == NULL) |
869 | continue; | | 848 | continue; |
870 | info.rti_info[RTAX_NETMASK] = rt_mask(rt); | | 849 | info.rti_info[RTAX_NETMASK] = rt_mask(rt); |
871 | info.rti_info[RTAX_DST] = sa = rt_getkey(rt); | | 850 | info.rti_info[RTAX_DST] = sa = rt_getkey(rt); |
872 | info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; | | 851 | info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; |
873 | memset(&rtm, 0, sizeof(rtm)); | | 852 | memset(&rtm, 0, sizeof(rtm)); |
874 | rtm.rtm_index = ifp->if_index; | | 853 | rtm.rtm_index = ifp->if_index; |
875 | rtm.rtm_flags |= rt->rt_flags; | | 854 | rtm.rtm_flags |= rt->rt_flags; |
876 | rtm.rtm_errno = error; | | 855 | rtm.rtm_errno = error; |
877 | m = rt_msg1(cmd, &info, &rtm, sizeof(rtm)); | | 856 | m = rt_msg1(cmd, &info, &rtm, sizeof(rtm)); |
878 | if (m == NULL) | | 857 | if (m == NULL) |
879 | continue; | | 858 | continue; |
880 | mtod(m, struct rt_msghdr *)->rtm_addrs = info.rti_addrs; | | 859 | mtod(m, struct rt_msghdr *)->rtm_addrs = info.rti_addrs; |
881 | } | | 860 | } |
882 | #ifdef DIAGNOSTIC | | 861 | #ifdef DIAGNOSTIC |
883 | if (m == NULL) | | 862 | if (m == NULL) |
884 | panic("%s: called with wrong command", __func__); | | 863 | panic("%s: called with wrong command", __func__); |
885 | #endif | | 864 | #endif |
886 | route_enqueue(m, sa ? sa->sa_family : 0); | | 865 | route_enqueue(m, sa ? sa->sa_family : 0); |
887 | } | | 866 | } |
888 | } | | 867 | } |
889 | | | 868 | |
890 | static struct mbuf * | | 869 | static struct mbuf * |
891 | rt_makeifannouncemsg(struct ifnet *ifp, int type, int what, | | 870 | rt_makeifannouncemsg(struct ifnet *ifp, int type, int what, |
892 | struct rt_addrinfo *info) | | 871 | struct rt_addrinfo *info) |
893 | { | | 872 | { |
894 | struct if_announcemsghdr ifan; | | 873 | struct if_announcemsghdr ifan; |
895 | | | 874 | |
896 | memset(info, 0, sizeof(*info)); | | 875 | memset(info, 0, sizeof(*info)); |
897 | memset(&ifan, 0, sizeof(ifan)); | | 876 | memset(&ifan, 0, sizeof(ifan)); |
898 | ifan.ifan_index = ifp->if_index; | | 877 | ifan.ifan_index = ifp->if_index; |
899 | strlcpy(ifan.ifan_name, ifp->if_xname, sizeof(ifan.ifan_name)); | | 878 | strlcpy(ifan.ifan_name, ifp->if_xname, sizeof(ifan.ifan_name)); |
900 | ifan.ifan_what = what; | | 879 | ifan.ifan_what = what; |
901 | return rt_msg1(type, info, &ifan, sizeof(ifan)); | | 880 | return rt_msg1(type, info, &ifan, sizeof(ifan)); |
902 | } | | 881 | } |
903 | | | 882 | |
904 | /* | | 883 | /* |
905 | * This is called to generate routing socket messages indicating | | 884 | * This is called to generate routing socket messages indicating |
906 | * network interface arrival and departure. | | 885 | * network interface arrival and departure. |
907 | */ | | 886 | */ |
908 | void | | 887 | void |
909 | rt_ifannouncemsg(struct ifnet *ifp, int what) | | 888 | rt_ifannouncemsg(struct ifnet *ifp, int what) |
910 | { | | 889 | { |
911 | struct mbuf *m; | | 890 | struct mbuf *m; |
912 | struct rt_addrinfo info; | | 891 | struct rt_addrinfo info; |
913 | | | 892 | |
914 | if (route_cb.any_count == 0) | | 893 | if (route_cb.any_count == 0) |
915 | return; | | 894 | return; |
916 | m = rt_makeifannouncemsg(ifp, RTM_IFANNOUNCE, what, &info); | | 895 | m = rt_makeifannouncemsg(ifp, RTM_IFANNOUNCE, what, &info); |
917 | if (m == NULL) | | 896 | if (m == NULL) |
918 | return; | | 897 | return; |
919 | route_enqueue(m, 0); | | 898 | route_enqueue(m, 0); |
920 | } | | 899 | } |
921 | | | 900 | |
922 | /* | | 901 | /* |
923 | * This is called to generate routing socket messages indicating | | 902 | * This is called to generate routing socket messages indicating |
924 | * IEEE80211 wireless events. | | 903 | * IEEE80211 wireless events. |
925 | * XXX we piggyback on the RTM_IFANNOUNCE msg format in a clumsy way. | | 904 | * XXX we piggyback on the RTM_IFANNOUNCE msg format in a clumsy way. |
926 | */ | | 905 | */ |
927 | void | | 906 | void |
928 | rt_ieee80211msg(struct ifnet *ifp, int what, void *data, size_t data_len) | | 907 | rt_ieee80211msg(struct ifnet *ifp, int what, void *data, size_t data_len) |
929 | { | | 908 | { |
930 | struct mbuf *m; | | 909 | struct mbuf *m; |
931 | struct rt_addrinfo info; | | 910 | struct rt_addrinfo info; |
932 | | | 911 | |
933 | if (route_cb.any_count == 0) | | 912 | if (route_cb.any_count == 0) |
934 | return; | | 913 | return; |
935 | m = rt_makeifannouncemsg(ifp, RTM_IEEE80211, what, &info); | | 914 | m = rt_makeifannouncemsg(ifp, RTM_IEEE80211, what, &info); |
936 | if (m == NULL) | | 915 | if (m == NULL) |
937 | return; | | 916 | return; |
938 | /* | | 917 | /* |
939 | * Append the ieee80211 data. Try to stick it in the | | 918 | * Append the ieee80211 data. Try to stick it in the |
940 | * mbuf containing the ifannounce msg; otherwise allocate | | 919 | * mbuf containing the ifannounce msg; otherwise allocate |
941 | * a new mbuf and append. | | 920 | * a new mbuf and append. |
942 | * | | 921 | * |
943 | * NB: we assume m is a single mbuf. | | 922 | * NB: we assume m is a single mbuf. |
944 | */ | | 923 | */ |
945 | if (data_len > M_TRAILINGSPACE(m)) { | | 924 | if (data_len > M_TRAILINGSPACE(m)) { |
946 | struct mbuf *n = m_get(M_NOWAIT, MT_DATA); | | 925 | struct mbuf *n = m_get(M_NOWAIT, MT_DATA); |
947 | if (n == NULL) { | | 926 | if (n == NULL) { |
948 | m_freem(m); | | 927 | m_freem(m); |
949 | return; | | 928 | return; |
950 | } | | 929 | } |
951 | (void)memcpy(mtod(n, void *), data, data_len); | | 930 | (void)memcpy(mtod(n, void *), data, data_len); |
952 | n->m_len = data_len; | | 931 | n->m_len = data_len; |
953 | m->m_next = n; | | 932 | m->m_next = n; |
954 | } else if (data_len > 0) { | | 933 | } else if (data_len > 0) { |
955 | (void)memcpy(mtod(m, uint8_t *) + m->m_len, data, data_len); | | 934 | (void)memcpy(mtod(m, uint8_t *) + m->m_len, data, data_len); |
956 | m->m_len += data_len; | | 935 | m->m_len += data_len; |
957 | } | | 936 | } |
958 | if (m->m_flags & M_PKTHDR) | | 937 | if (m->m_flags & M_PKTHDR) |
959 | m->m_pkthdr.len += data_len; | | 938 | m->m_pkthdr.len += data_len; |
960 | mtod(m, struct if_announcemsghdr *)->ifan_msglen += data_len; | | 939 | mtod(m, struct if_announcemsghdr *)->ifan_msglen += data_len; |
961 | route_enqueue(m, 0); | | 940 | route_enqueue(m, 0); |
962 | } | | 941 | } |
963 | | | 942 | |
964 | /* | | 943 | /* |
965 | * This is used in dumping the kernel table via sysctl(). | | 944 | * This is used in dumping the kernel table via sysctl(). |
966 | */ | | 945 | */ |
967 | static int | | 946 | static int |
968 | sysctl_dumpentry(struct rtentry *rt, void *v) | | 947 | sysctl_dumpentry(struct rtentry *rt, void *v) |
969 | { | | 948 | { |
970 | struct walkarg *w = v; | | 949 | struct walkarg *w = v; |
971 | int error = 0, size; | | 950 | int error = 0, size; |
972 | struct rt_addrinfo info; | | 951 | struct rt_addrinfo info; |
973 | | | 952 | |
974 | if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) | | 953 | if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) |
975 | return 0; | | 954 | return 0; |
976 | memset(&info, 0, sizeof(info)); | | 955 | memset(&info, 0, sizeof(info)); |
977 | info.rti_info[RTAX_DST] = rt_getkey(rt); | | 956 | info.rti_info[RTAX_DST] = rt_getkey(rt); |
978 | info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; | | 957 | info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; |
979 | info.rti_info[RTAX_NETMASK] = rt_mask(rt); | | 958 | info.rti_info[RTAX_NETMASK] = rt_mask(rt); |
980 | if (rt->rt_ifp) { | | 959 | if (rt->rt_ifp) { |
981 | const struct ifaddr *rtifa; | | 960 | const struct ifaddr *rtifa; |
982 | info.rti_info[RTAX_IFP] = rt->rt_ifp->if_dl->ifa_addr; | | 961 | info.rti_info[RTAX_IFP] = rt->rt_ifp->if_dl->ifa_addr; |
983 | /* rtifa used to be simply rt->rt_ifa. If rt->rt_ifa != NULL, | | 962 | /* rtifa used to be simply rt->rt_ifa. If rt->rt_ifa != NULL, |
984 | * then rt_get_ifa() != NULL. So this ought to still be safe. | | 963 | * then rt_get_ifa() != NULL. So this ought to still be safe. |
985 | * --dyoung | | 964 | * --dyoung |
986 | */ | | 965 | */ |
987 | rtifa = rt_get_ifa(rt); | | 966 | rtifa = rt_get_ifa(rt); |
988 | info.rti_info[RTAX_IFA] = rtifa->ifa_addr; | | 967 | info.rti_info[RTAX_IFA] = rtifa->ifa_addr; |
989 | if (rt->rt_ifp->if_flags & IFF_POINTOPOINT) | | 968 | if (rt->rt_ifp->if_flags & IFF_POINTOPOINT) |
990 | info.rti_info[RTAX_BRD] = rtifa->ifa_dstaddr; | | 969 | info.rti_info[RTAX_BRD] = rtifa->ifa_dstaddr; |
991 | } | | 970 | } |
992 | if ((error = rt_msg2(RTM_GET, &info, 0, w, &size))) | | 971 | if ((error = rt_msg2(RTM_GET, &info, 0, w, &size))) |
993 | return error; | | 972 | return error; |
994 | if (w->w_where && w->w_tmem && w->w_needed <= 0) { | | 973 | if (w->w_where && w->w_tmem && w->w_needed <= 0) { |
995 | struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; | | 974 | struct rt_msghdr *rtm = (struct rt_msghdr *)w->w_tmem; |
996 | | | 975 | |
997 | rtm->rtm_flags = rt->rt_flags; | | 976 | rtm->rtm_flags = rt->rt_flags; |
998 | rtm->rtm_use = rt->rt_use; | | 977 | rtm->rtm_use = rt->rt_use; |
999 | rtm->rtm_rmx = rt->rt_rmx; | | 978 | rtm->rtm_rmx = rt->rt_rmx; |
1000 | KASSERT(rt->rt_ifp != NULL); | | 979 | KASSERT(rt->rt_ifp != NULL); |
1001 | rtm->rtm_index = rt->rt_ifp->if_index; | | 980 | rtm->rtm_index = rt->rt_ifp->if_index; |
1002 | rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; | | 981 | rtm->rtm_errno = rtm->rtm_pid = rtm->rtm_seq = 0; |
1003 | rtm->rtm_addrs = info.rti_addrs; | | 982 | rtm->rtm_addrs = info.rti_addrs; |
1004 | if ((error = copyout(rtm, w->w_where, size)) != 0) | | 983 | if ((error = copyout(rtm, w->w_where, size)) != 0) |
1005 | w->w_where = NULL; | | 984 | w->w_where = NULL; |
1006 | else | | 985 | else |
1007 | w->w_where = (char *)w->w_where + size; | | 986 | w->w_where = (char *)w->w_where + size; |
1008 | } | | 987 | } |
1009 | return error; | | 988 | return error; |
1010 | } | | 989 | } |
1011 | | | 990 | |
1012 | static int | | 991 | static int |
1013 | sysctl_iflist(int af, struct walkarg *w, int type) | | 992 | sysctl_iflist(int af, struct walkarg *w, int type) |
1014 | { | | 993 | { |
1015 | struct ifnet *ifp; | | 994 | struct ifnet *ifp; |
1016 | struct ifaddr *ifa; | | 995 | struct ifaddr *ifa; |
1017 | struct rt_addrinfo info; | | 996 | struct rt_addrinfo info; |
1018 | int len, error = 0; | | 997 | int len, error = 0; |
1019 | | | 998 | |
1020 | memset(&info, 0, sizeof(info)); | | 999 | memset(&info, 0, sizeof(info)); |
1021 | IFNET_FOREACH(ifp) { | | 1000 | IFNET_FOREACH(ifp) { |
1022 | if (w->w_arg && w->w_arg != ifp->if_index) | | 1001 | if (w->w_arg && w->w_arg != ifp->if_index) |
1023 | continue; | | 1002 | continue; |
1024 | if (IFADDR_EMPTY(ifp)) | | 1003 | if (IFADDR_EMPTY(ifp)) |
1025 | continue; | | 1004 | continue; |
1026 | info.rti_info[RTAX_IFP] = ifp->if_dl->ifa_addr; | | 1005 | info.rti_info[RTAX_IFP] = ifp->if_dl->ifa_addr; |
1027 | switch (type) { | | 1006 | switch (type) { |
1028 | case NET_RT_IFLIST: | | 1007 | case NET_RT_IFLIST: |
1029 | error = rt_msg2(RTM_IFINFO, &info, NULL, w, &len); | | 1008 | error = rt_msg2(RTM_IFINFO, &info, NULL, w, &len); |
1030 | break; | | 1009 | break; |
1031 | #ifdef COMPAT_14 | | 1010 | #ifdef COMPAT_14 |
1032 | case NET_RT_OIFLIST: | | 1011 | case NET_RT_OIFLIST: |
1033 | error = rt_msg2(RTM_OIFINFO, &info, NULL, w, &len); | | 1012 | error = rt_msg2(RTM_OIFINFO, &info, NULL, w, &len); |
1034 | break; | | 1013 | break; |
1035 | #endif | | 1014 | #endif |
1036 | default: | | 1015 | default: |
1037 | panic("sysctl_iflist(1)"); | | 1016 | panic("sysctl_iflist(1)"); |
1038 | } | | 1017 | } |
1039 | if (error) | | 1018 | if (error) |
1040 | return error; | | 1019 | return error; |
1041 | info.rti_info[RTAX_IFP] = NULL; | | 1020 | info.rti_info[RTAX_IFP] = NULL; |
1042 | if (w->w_where && w->w_tmem && w->w_needed <= 0) { | | 1021 | if (w->w_where && w->w_tmem && w->w_needed <= 0) { |
1043 | switch (type) { | | 1022 | switch (type) { |
1044 | case NET_RT_IFLIST: { | | 1023 | case NET_RT_IFLIST: { |
1045 | struct if_msghdr *ifm; | | 1024 | struct if_msghdr *ifm; |
1046 | | | 1025 | |
1047 | ifm = (struct if_msghdr *)w->w_tmem; | | 1026 | ifm = (struct if_msghdr *)w->w_tmem; |
1048 | ifm->ifm_index = ifp->if_index; | | 1027 | ifm->ifm_index = ifp->if_index; |
1049 | ifm->ifm_flags = ifp->if_flags; | | 1028 | ifm->ifm_flags = ifp->if_flags; |
1050 | ifm->ifm_data = ifp->if_data; | | 1029 | ifm->ifm_data = ifp->if_data; |
1051 | ifm->ifm_addrs = info.rti_addrs; | | 1030 | ifm->ifm_addrs = info.rti_addrs; |
1052 | error = copyout(ifm, w->w_where, len); | | 1031 | error = copyout(ifm, w->w_where, len); |
1053 | if (error) | | 1032 | if (error) |
1054 | return error; | | 1033 | return error; |
1055 | w->w_where = (char *)w->w_where + len; | | 1034 | w->w_where = (char *)w->w_where + len; |
1056 | break; | | 1035 | break; |
1057 | } | | 1036 | } |
1058 | | | 1037 | |
1059 | #ifdef COMPAT_14 | | 1038 | #ifdef COMPAT_14 |
1060 | case NET_RT_OIFLIST: { | | 1039 | case NET_RT_OIFLIST: { |
1061 | struct if_msghdr14 *ifm; | | 1040 | struct if_msghdr14 *ifm; |
1062 | | | 1041 | |
1063 | ifm = (struct if_msghdr14 *)w->w_tmem; | | 1042 | ifm = (struct if_msghdr14 *)w->w_tmem; |
1064 | ifm->ifm_index = ifp->if_index; | | 1043 | ifm->ifm_index = ifp->if_index; |
1065 | ifm->ifm_flags = ifp->if_flags; | | 1044 | ifm->ifm_flags = ifp->if_flags; |
1066 | ifm->ifm_data.ifi_type = ifp->if_data.ifi_type; | | 1045 | ifm->ifm_data.ifi_type = ifp->if_data.ifi_type; |
1067 | ifm->ifm_data.ifi_addrlen = | | 1046 | ifm->ifm_data.ifi_addrlen = |
1068 | ifp->if_data.ifi_addrlen; | | 1047 | ifp->if_data.ifi_addrlen; |
1069 | ifm->ifm_data.ifi_hdrlen = | | 1048 | ifm->ifm_data.ifi_hdrlen = |
1070 | ifp->if_data.ifi_hdrlen; | | 1049 | ifp->if_data.ifi_hdrlen; |
1071 | ifm->ifm_data.ifi_mtu = ifp->if_data.ifi_mtu; | | 1050 | ifm->ifm_data.ifi_mtu = ifp->if_data.ifi_mtu; |
1072 | ifm->ifm_data.ifi_metric = | | 1051 | ifm->ifm_data.ifi_metric = |
1073 | ifp->if_data.ifi_metric; | | 1052 | ifp->if_data.ifi_metric; |
1074 | ifm->ifm_data.ifi_baudrate = | | 1053 | ifm->ifm_data.ifi_baudrate = |
1075 | ifp->if_data.ifi_baudrate; | | 1054 | ifp->if_data.ifi_baudrate; |
1076 | ifm->ifm_data.ifi_ipackets = | | 1055 | ifm->ifm_data.ifi_ipackets = |
1077 | ifp->if_data.ifi_ipackets; | | 1056 | ifp->if_data.ifi_ipackets; |
1078 | ifm->ifm_data.ifi_ierrors = | | 1057 | ifm->ifm_data.ifi_ierrors = |
1079 | ifp->if_data.ifi_ierrors; | | 1058 | ifp->if_data.ifi_ierrors; |
1080 | ifm->ifm_data.ifi_opackets = | | 1059 | ifm->ifm_data.ifi_opackets = |
1081 | ifp->if_data.ifi_opackets; | | 1060 | ifp->if_data.ifi_opackets; |
1082 | ifm->ifm_data.ifi_oerrors = | | 1061 | ifm->ifm_data.ifi_oerrors = |
1083 | ifp->if_data.ifi_oerrors; | | 1062 | ifp->if_data.ifi_oerrors; |
1084 | ifm->ifm_data.ifi_collisions = | | 1063 | ifm->ifm_data.ifi_collisions = |
1085 | ifp->if_data.ifi_collisions; | | 1064 | ifp->if_data.ifi_collisions; |
1086 | ifm->ifm_data.ifi_ibytes = | | 1065 | ifm->ifm_data.ifi_ibytes = |
1087 | ifp->if_data.ifi_ibytes; | | 1066 | ifp->if_data.ifi_ibytes; |
1088 | ifm->ifm_data.ifi_obytes = | | 1067 | ifm->ifm_data.ifi_obytes = |
1089 | ifp->if_data.ifi_obytes; | | 1068 | ifp->if_data.ifi_obytes; |
1090 | ifm->ifm_data.ifi_imcasts = | | 1069 | ifm->ifm_data.ifi_imcasts = |
1091 | ifp->if_data.ifi_imcasts; | | 1070 | ifp->if_data.ifi_imcasts; |
1092 | ifm->ifm_data.ifi_omcasts = | | 1071 | ifm->ifm_data.ifi_omcasts = |
1093 | ifp->if_data.ifi_omcasts; | | 1072 | ifp->if_data.ifi_omcasts; |
1094 | ifm->ifm_data.ifi_iqdrops = | | 1073 | ifm->ifm_data.ifi_iqdrops = |
1095 | ifp->if_data.ifi_iqdrops; | | 1074 | ifp->if_data.ifi_iqdrops; |
1096 | ifm->ifm_data.ifi_noproto = | | 1075 | ifm->ifm_data.ifi_noproto = |
1097 | ifp->if_data.ifi_noproto; | | 1076 | ifp->if_data.ifi_noproto; |
1098 | ifm->ifm_data.ifi_lastchange = | | 1077 | ifm->ifm_data.ifi_lastchange = |
1099 | ifp->if_data.ifi_lastchange; | | 1078 | ifp->if_data.ifi_lastchange; |
1100 | ifm->ifm_addrs = info.rti_addrs; | | 1079 | ifm->ifm_addrs = info.rti_addrs; |
1101 | error = copyout(ifm, w->w_where, len); | | 1080 | error = copyout(ifm, w->w_where, len); |
1102 | if (error) | | 1081 | if (error) |
1103 | return error; | | 1082 | return error; |
1104 | w->w_where = (char *)w->w_where + len; | | 1083 | w->w_where = (char *)w->w_where + len; |
1105 | break; | | 1084 | break; |
1106 | } | | 1085 | } |
1107 | #endif | | 1086 | #endif |
1108 | default: | | 1087 | default: |
1109 | panic("sysctl_iflist(2)"); | | 1088 | panic("sysctl_iflist(2)"); |
1110 | } | | 1089 | } |
1111 | } | | 1090 | } |
1112 | IFADDR_FOREACH(ifa, ifp) { | | 1091 | IFADDR_FOREACH(ifa, ifp) { |
1113 | if (af && af != ifa->ifa_addr->sa_family) | | 1092 | if (af && af != ifa->ifa_addr->sa_family) |
1114 | continue; | | 1093 | continue; |
1115 | info.rti_info[RTAX_IFA] = ifa->ifa_addr; | | 1094 | info.rti_info[RTAX_IFA] = ifa->ifa_addr; |
1116 | info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; | | 1095 | info.rti_info[RTAX_NETMASK] = ifa->ifa_netmask; |
1117 | info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; | | 1096 | info.rti_info[RTAX_BRD] = ifa->ifa_dstaddr; |
1118 | if ((error = rt_msg2(RTM_NEWADDR, &info, 0, w, &len))) | | 1097 | if ((error = rt_msg2(RTM_NEWADDR, &info, 0, w, &len))) |
1119 | return error; | | 1098 | return error; |
1120 | if (w->w_where && w->w_tmem && w->w_needed <= 0) { | | 1099 | if (w->w_where && w->w_tmem && w->w_needed <= 0) { |
1121 | struct ifa_msghdr *ifam; | | 1100 | struct ifa_msghdr *ifam; |
1122 | | | 1101 | |
1123 | ifam = (struct ifa_msghdr *)w->w_tmem; | | 1102 | ifam = (struct ifa_msghdr *)w->w_tmem; |
1124 | ifam->ifam_index = ifa->ifa_ifp->if_index; | | 1103 | ifam->ifam_index = ifa->ifa_ifp->if_index; |
1125 | ifam->ifam_flags = ifa->ifa_flags; | | 1104 | ifam->ifam_flags = ifa->ifa_flags; |
1126 | ifam->ifam_metric = ifa->ifa_metric; | | 1105 | ifam->ifam_metric = ifa->ifa_metric; |
1127 | ifam->ifam_addrs = info.rti_addrs; | | 1106 | ifam->ifam_addrs = info.rti_addrs; |
1128 | error = copyout(w->w_tmem, w->w_where, len); | | 1107 | error = copyout(w->w_tmem, w->w_where, len); |
1129 | if (error) | | 1108 | if (error) |
1130 | return error; | | 1109 | return error; |
1131 | w->w_where = (char *)w->w_where + len; | | 1110 | w->w_where = (char *)w->w_where + len; |
1132 | } | | 1111 | } |
1133 | } | | 1112 | } |
1134 | info.rti_info[RTAX_IFA] = info.rti_info[RTAX_NETMASK] = | | 1113 | info.rti_info[RTAX_IFA] = info.rti_info[RTAX_NETMASK] = |
1135 | info.rti_info[RTAX_BRD] = NULL; | | 1114 | info.rti_info[RTAX_BRD] = NULL; |
1136 | } | | 1115 | } |
1137 | return 0; | | 1116 | return 0; |
1138 | } | | 1117 | } |
1139 | | | 1118 | |
1140 | static int | | 1119 | static int |
1141 | sysctl_rtable(SYSCTLFN_ARGS) | | 1120 | sysctl_rtable(SYSCTLFN_ARGS) |
1142 | { | | 1121 | { |
1143 | void *where = oldp; | | 1122 | void *where = oldp; |
1144 | size_t *given = oldlenp; | | 1123 | size_t *given = oldlenp; |
1145 | const void *new = newp; | | 1124 | const void *new = newp; |
1146 | int i, s, error = EINVAL; | | 1125 | int i, s, error = EINVAL; |
1147 | u_char af; | | 1126 | u_char af; |
1148 | struct walkarg w; | | 1127 | struct walkarg w; |
1149 | | | 1128 | |
1150 | if (namelen == 1 && name[0] == CTL_QUERY) | | 1129 | if (namelen == 1 && name[0] == CTL_QUERY) |
1151 | return sysctl_query(SYSCTLFN_CALL(rnode)); | | 1130 | return sysctl_query(SYSCTLFN_CALL(rnode)); |
1152 | | | 1131 | |
1153 | if (new) | | 1132 | if (new) |
1154 | return EPERM; | | 1133 | return EPERM; |
1155 | if (namelen != 3) | | 1134 | if (namelen != 3) |
1156 | return EINVAL; | | 1135 | return EINVAL; |
1157 | af = name[0]; | | 1136 | af = name[0]; |
1158 | w.w_tmemneeded = 0; | | 1137 | w.w_tmemneeded = 0; |
1159 | w.w_tmemsize = 0; | | 1138 | w.w_tmemsize = 0; |
1160 | w.w_tmem = NULL; | | 1139 | w.w_tmem = NULL; |
1161 | again: | | 1140 | again: |
1162 | /* we may return here if a later [re]alloc of the t_mem buffer fails */ | | 1141 | /* we may return here if a later [re]alloc of the t_mem buffer fails */ |
1163 | if (w.w_tmemneeded) { | | 1142 | if (w.w_tmemneeded) { |
1164 | w.w_tmem = malloc(w.w_tmemneeded, M_RTABLE, M_WAITOK); | | 1143 | w.w_tmem = malloc(w.w_tmemneeded, M_RTABLE, M_WAITOK); |
1165 | w.w_tmemsize = w.w_tmemneeded; | | 1144 | w.w_tmemsize = w.w_tmemneeded; |
1166 | w.w_tmemneeded = 0; | | 1145 | w.w_tmemneeded = 0; |
1167 | } | | 1146 | } |
1168 | w.w_op = name[1]; | | 1147 | w.w_op = name[1]; |
1169 | w.w_arg = name[2]; | | 1148 | w.w_arg = name[2]; |
1170 | w.w_given = *given; | | 1149 | w.w_given = *given; |
1171 | w.w_needed = 0 - w.w_given; | | 1150 | w.w_needed = 0 - w.w_given; |
1172 | w.w_where = where; | | 1151 | w.w_where = where; |
1173 | | | 1152 | |
1174 | s = splsoftnet(); | | 1153 | s = splsoftnet(); |
1175 | switch (w.w_op) { | | 1154 | switch (w.w_op) { |
1176 | | | 1155 | |
1177 | case NET_RT_DUMP: | | 1156 | case NET_RT_DUMP: |
1178 | case NET_RT_FLAGS: | | 1157 | case NET_RT_FLAGS: |
1179 | for (i = 1; i <= AF_MAX; i++) | | 1158 | for (i = 1; i <= AF_MAX; i++) |
1180 | if ((af == 0 || af == i) && | | 1159 | if ((af == 0 || af == i) && |
1181 | (error = rt_walktree(i, sysctl_dumpentry, &w))) | | 1160 | (error = rt_walktree(i, sysctl_dumpentry, &w))) |
1182 | break; | | 1161 | break; |
1183 | break; | | 1162 | break; |
1184 | | | 1163 | |
1185 | #ifdef COMPAT_14 | | 1164 | #ifdef COMPAT_14 |
1186 | case NET_RT_OIFLIST: | | 1165 | case NET_RT_OIFLIST: |
1187 | error = sysctl_iflist(af, &w, w.w_op); | | 1166 | error = sysctl_iflist(af, &w, w.w_op); |
1188 | break; | | 1167 | break; |
1189 | #endif | | 1168 | #endif |
1190 | | | 1169 | |
1191 | case NET_RT_IFLIST: | | 1170 | case NET_RT_IFLIST: |
1192 | error = sysctl_iflist(af, &w, w.w_op); | | 1171 | error = sysctl_iflist(af, &w, w.w_op); |
1193 | } | | 1172 | } |
1194 | splx(s); | | 1173 | splx(s); |
1195 | | | 1174 | |
1196 | /* check to see if we couldn't allocate memory with NOWAIT */ | | 1175 | /* check to see if we couldn't allocate memory with NOWAIT */ |
1197 | if (error == ENOBUFS && w.w_tmem == 0 && w.w_tmemneeded) | | 1176 | if (error == ENOBUFS && w.w_tmem == 0 && w.w_tmemneeded) |
1198 | goto again; | | 1177 | goto again; |
1199 | | | 1178 | |
1200 | if (w.w_tmem) | | 1179 | if (w.w_tmem) |
1201 | free(w.w_tmem, M_RTABLE); | | 1180 | free(w.w_tmem, M_RTABLE); |
1202 | w.w_needed += w.w_given; | | 1181 | w.w_needed += w.w_given; |
1203 | if (where) { | | 1182 | if (where) { |
1204 | *given = (char *)w.w_where - (char *)where; | | 1183 | *given = (char *)w.w_where - (char *)where; |
1205 | if (*given < w.w_needed) | | 1184 | if (*given < w.w_needed) |
1206 | return ENOMEM; | | 1185 | return ENOMEM; |
1207 | } else { | | 1186 | } else { |
1208 | *given = (11 * w.w_needed) / 10; | | 1187 | *given = (11 * w.w_needed) / 10; |
1209 | } | | 1188 | } |
1210 | return error; | | 1189 | return error; |
1211 | } | | 1190 | } |
1212 | | | 1191 | |
1213 | /* | | 1192 | /* |
1214 | * Routing message software interrupt routine | | 1193 | * Routing message software interrupt routine |
1215 | */ | | 1194 | */ |
1216 | static void | | 1195 | static void |
1217 | route_intr(void *cookie) | | 1196 | route_intr(void *cookie) |
1218 | { | | 1197 | { |
1219 | struct sockproto proto = { .sp_family = PF_ROUTE, }; | | 1198 | struct sockproto proto = { .sp_family = PF_ROUTE, }; |
1220 | struct mbuf *m; | | 1199 | struct mbuf *m; |
1221 | int s; | | 1200 | int s; |
1222 | | | 1201 | |
1223 | mutex_enter(softnet_lock); | | 1202 | mutex_enter(softnet_lock); |
1224 | KERNEL_LOCK(1, NULL); | | 1203 | KERNEL_LOCK(1, NULL); |
1225 | while (!IF_IS_EMPTY(&route_intrq)) { | | 1204 | while (!IF_IS_EMPTY(&route_intrq)) { |
1226 | s = splnet(); | | 1205 | s = splnet(); |
1227 | IF_DEQUEUE(&route_intrq, m); | | 1206 | IF_DEQUEUE(&route_intrq, m); |
1228 | splx(s); | | 1207 | splx(s); |
1229 | if (m == NULL) | | 1208 | if (m == NULL) |
1230 | break; | | 1209 | break; |
1231 | proto.sp_protocol = M_GETCTX(m, uintptr_t); | | 1210 | proto.sp_protocol = M_GETCTX(m, uintptr_t); |
1232 | raw_input(m, &proto, &route_src, &route_dst); | | 1211 | raw_input(m, &proto, &route_src, &route_dst); |
1233 | } | | 1212 | } |
1234 | KERNEL_UNLOCK_ONE(NULL); | | 1213 | KERNEL_UNLOCK_ONE(NULL); |
1235 | mutex_exit(softnet_lock); | | 1214 | mutex_exit(softnet_lock); |
1236 | } | | 1215 | } |
1237 | | | 1216 | |
1238 | /* | | 1217 | /* |
1239 | * Enqueue a message to the software interrupt routine. | | 1218 | * Enqueue a message to the software interrupt routine. |
1240 | */ | | 1219 | */ |
1241 | static void | | 1220 | static void |
1242 | route_enqueue(struct mbuf *m, int family) | | 1221 | route_enqueue(struct mbuf *m, int family) |
1243 | { | | 1222 | { |
1244 | int s, wasempty; | | 1223 | int s, wasempty; |
1245 | | | 1224 | |
1246 | s = splnet(); | | 1225 | s = splnet(); |
1247 | if (IF_QFULL(&route_intrq)) { | | 1226 | if (IF_QFULL(&route_intrq)) { |
1248 | IF_DROP(&route_intrq); | | 1227 | IF_DROP(&route_intrq); |
1249 | m_freem(m); | | 1228 | m_freem(m); |
1250 | } else { | | 1229 | } else { |
1251 | wasempty = IF_IS_EMPTY(&route_intrq); | | 1230 | wasempty = IF_IS_EMPTY(&route_intrq); |
1252 | M_SETCTX(m, (uintptr_t)family); | | 1231 | M_SETCTX(m, (uintptr_t)family); |
1253 | IF_ENQUEUE(&route_intrq, m); | | 1232 | IF_ENQUEUE(&route_intrq, m); |
1254 | if (wasempty) | | 1233 | if (wasempty) |
1255 | softint_schedule(route_sih); | | 1234 | softint_schedule(route_sih); |
1256 | } | | 1235 | } |
1257 | splx(s); | | 1236 | splx(s); |
1258 | } | | 1237 | } |
1259 | | | 1238 | |
1260 | void | | 1239 | void |
1261 | rt_init(void) | | 1240 | rt_init(void) |
1262 | { | | 1241 | { |
1263 | | | 1242 | |
1264 | route_intrq.ifq_maxlen = route_maxqlen; | | 1243 | route_intrq.ifq_maxlen = route_maxqlen; |
1265 | route_sih = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, | | 1244 | route_sih = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, |
1266 | route_intr, NULL); | | 1245 | route_intr, NULL); |
1267 | } | | 1246 | } |
1268 | | | 1247 | |
1269 | /* | | 1248 | /* |
1270 | * Definitions of protocols supported in the ROUTE domain. | | 1249 | * Definitions of protocols supported in the ROUTE domain. |
1271 | */ | | 1250 | */ |
1272 | PR_WRAP_USRREQ(route_usrreq) | | 1251 | PR_WRAP_USRREQ(route_usrreq) |
1273 | #define route_usrreq route_usrreq_wrapper | | 1252 | #define route_usrreq route_usrreq_wrapper |
1274 | | | 1253 | |
1275 | const struct protosw routesw[] = { | | 1254 | const struct protosw routesw[] = { |
1276 | { | | 1255 | { |
1277 | .pr_type = SOCK_RAW, | | 1256 | .pr_type = SOCK_RAW, |
1278 | .pr_domain = &routedomain, | | 1257 | .pr_domain = &routedomain, |
1279 | .pr_flags = PR_ATOMIC|PR_ADDR, | | 1258 | .pr_flags = PR_ATOMIC|PR_ADDR, |
1280 | .pr_input = raw_input, | | 1259 | .pr_input = raw_input, |
1281 | .pr_output = route_output, | | 1260 | .pr_output = route_output, |
1282 | .pr_ctlinput = raw_ctlinput, | | 1261 | .pr_ctlinput = raw_ctlinput, |
1283 | .pr_usrreq = route_usrreq, | | 1262 | .pr_usrreq = route_usrreq, |
1284 | .pr_init = raw_init, | | 1263 | .pr_init = raw_init, |
1285 | }, | | 1264 | }, |
1286 | }; | | 1265 | }; |
1287 | | | 1266 | |
1288 | struct domain routedomain = { | | 1267 | struct domain routedomain = { |
1289 | .dom_family = PF_ROUTE, | | 1268 | .dom_family = PF_ROUTE, |
1290 | .dom_name = "route", | | 1269 | .dom_name = "route", |
1291 | .dom_init = route_init, | | 1270 | .dom_init = route_init, |
1292 | .dom_protosw = routesw, | | 1271 | .dom_protosw = routesw, |
1293 | .dom_protoswNPROTOSW = &routesw[__arraycount(routesw)], | | 1272 | .dom_protoswNPROTOSW = &routesw[__arraycount(routesw)], |
1294 | }; | | 1273 | }; |
1295 | | | 1274 | |
1296 | SYSCTL_SETUP(sysctl_net_route_setup, "sysctl net.route subtree setup") | | 1275 | SYSCTL_SETUP(sysctl_net_route_setup, "sysctl net.route subtree setup") |
1297 | { | | 1276 | { |
1298 | const struct sysctlnode *rnode = NULL; | | 1277 | const struct sysctlnode *rnode = NULL; |
1299 | | | 1278 | |
1300 | sysctl_createv(clog, 0, NULL, NULL, | | 1279 | sysctl_createv(clog, 0, NULL, NULL, |
1301 | CTLFLAG_PERMANENT, | | 1280 | CTLFLAG_PERMANENT, |
1302 | CTLTYPE_NODE, "net", NULL, | | 1281 | CTLTYPE_NODE, "net", NULL, |
1303 | NULL, 0, NULL, 0, | | 1282 | NULL, 0, NULL, 0, |
1304 | CTL_NET, CTL_EOL); | | 1283 | CTL_NET, CTL_EOL); |
1305 | | | 1284 | |
1306 | sysctl_createv(clog, 0, NULL, &rnode, | | 1285 | sysctl_createv(clog, 0, NULL, &rnode, |
1307 | CTLFLAG_PERMANENT, | | 1286 | CTLFLAG_PERMANENT, |
1308 | CTLTYPE_NODE, "route", | | 1287 | CTLTYPE_NODE, "route", |
1309 | SYSCTL_DESCR("PF_ROUTE information"), | | 1288 | SYSCTL_DESCR("PF_ROUTE information"), |
1310 | NULL, 0, NULL, 0, | | 1289 | NULL, 0, NULL, 0, |
1311 | CTL_NET, PF_ROUTE, CTL_EOL); | | 1290 | CTL_NET, PF_ROUTE, CTL_EOL); |
1312 | sysctl_createv(clog, 0, NULL, NULL, | | 1291 | sysctl_createv(clog, 0, NULL, NULL, |
1313 | CTLFLAG_PERMANENT, | | 1292 | CTLFLAG_PERMANENT, |
1314 | CTLTYPE_NODE, "rtable", | | 1293 | CTLTYPE_NODE, "rtable", |
1315 | SYSCTL_DESCR("Routing table information"), | | 1294 | SYSCTL_DESCR("Routing table information"), |
1316 | sysctl_rtable, 0, NULL, 0, | | 1295 | sysctl_rtable, 0, NULL, 0, |
1317 | CTL_NET, PF_ROUTE, 0 /* any protocol */, CTL_EOL); | | 1296 | CTL_NET, PF_ROUTE, 0 /* any protocol */, CTL_EOL); |
1318 | sysctl_createv(clog, 0, &rnode, NULL, | | 1297 | sysctl_createv(clog, 0, &rnode, NULL, |
1319 | CTLFLAG_PERMANENT, | | 1298 | CTLFLAG_PERMANENT, |
1320 | CTLTYPE_STRUCT, "stats", | | 1299 | CTLTYPE_STRUCT, "stats", |
1321 | SYSCTL_DESCR("Routing statistics"), | | 1300 | SYSCTL_DESCR("Routing statistics"), |
1322 | NULL, 0, &rtstat, sizeof(rtstat), | | 1301 | NULL, 0, &rtstat, sizeof(rtstat), |
1323 | CTL_CREATE, CTL_EOL); | | 1302 | CTL_CREATE, CTL_EOL); |
1324 | } | | 1303 | } |