1 | /* $NetBSD: if_gre.c,v 1.171 2016/10/02 14:17:07 christos Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1998, 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Heiko W.Rupp <hwr@pilhuhn.de> |
9 | * |
10 | * IPv6-over-GRE contributed by Gert Doering <gert@greenie.muc.de> |
11 | * |
12 | * GRE over UDP/IPv4/IPv6 sockets contributed by David Young <dyoung@NetBSD.org> |
13 | * |
14 | * Redistribution and use in source and binary forms, with or without |
15 | * modification, are permitted provided that the following conditions |
16 | * are met: |
17 | * 1. Redistributions of source code must retain the above copyright |
18 | * notice, this list of conditions and the following disclaimer. |
19 | * 2. Redistributions in binary form must reproduce the above copyright |
20 | * notice, this list of conditions and the following disclaimer in the |
21 | * documentation and/or other materials provided with the distribution. |
22 | * |
23 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
24 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
25 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
26 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
27 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
28 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
29 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
30 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
31 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
32 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
33 | * POSSIBILITY OF SUCH DAMAGE. |
34 | * |
35 | * This material is based upon work partially supported by NSF |
36 | * under Contract No. NSF CNS-0626584. |
37 | */ |
38 | |
39 | /* |
40 | * Encapsulate L3 protocols into IP |
41 | * See RFC 1701 and 1702 for more details. |
42 | * If_gre is compatible with Cisco GRE tunnels, so you can |
43 | * have a NetBSD box as the other end of a tunnel interface of a Cisco |
44 | * router. See gre(4) for more details. |
45 | */ |
46 | |
47 | #include <sys/cdefs.h> |
48 | __KERNEL_RCSID(0, "$NetBSD: if_gre.c,v 1.171 2016/10/02 14:17:07 christos Exp $" ); |
49 | |
50 | #ifdef _KERNEL_OPT |
51 | #include "opt_atalk.h" |
52 | #include "opt_gre.h" |
53 | #include "opt_inet.h" |
54 | #include "opt_mpls.h" |
55 | #endif |
56 | |
57 | #include <sys/param.h> |
58 | #include <sys/file.h> |
59 | #include <sys/filedesc.h> |
60 | #include <sys/malloc.h> |
61 | #include <sys/mallocvar.h> |
62 | #include <sys/mbuf.h> |
63 | #include <sys/proc.h> |
64 | #include <sys/domain.h> |
65 | #include <sys/protosw.h> |
66 | #include <sys/socket.h> |
67 | #include <sys/socketvar.h> |
68 | #include <sys/ioctl.h> |
69 | #include <sys/queue.h> |
70 | #include <sys/intr.h> |
71 | #include <sys/systm.h> |
72 | #include <sys/sysctl.h> |
73 | #include <sys/kauth.h> |
74 | #include <sys/device.h> |
75 | #include <sys/module.h> |
76 | |
77 | #include <sys/kernel.h> |
78 | #include <sys/mutex.h> |
79 | #include <sys/condvar.h> |
80 | #include <sys/kthread.h> |
81 | |
82 | #include <sys/cpu.h> |
83 | |
84 | #include <net/ethertypes.h> |
85 | #include <net/if.h> |
86 | #include <net/if_types.h> |
87 | #include <net/netisr.h> |
88 | #include <net/route.h> |
89 | #include <sys/device.h> |
90 | #include <sys/module.h> |
91 | #include <sys/atomic.h> |
92 | |
93 | #include <netinet/in_systm.h> |
94 | #include <netinet/in.h> |
95 | #include <netinet/ip.h> /* we always need this for sizeof(struct ip) */ |
96 | |
97 | #ifdef INET |
98 | #include <netinet/in_var.h> |
99 | #include <netinet/ip_var.h> |
100 | #endif |
101 | |
102 | #ifdef INET6 |
103 | #include <netinet6/in6_var.h> |
104 | #endif |
105 | |
106 | #ifdef MPLS |
107 | #include <netmpls/mpls.h> |
108 | #include <netmpls/mpls_var.h> |
109 | #endif |
110 | |
111 | #ifdef NETATALK |
112 | #include <netatalk/at.h> |
113 | #include <netatalk/at_var.h> |
114 | #include <netatalk/at_extern.h> |
115 | #endif |
116 | |
117 | #include <sys/time.h> |
118 | #include <net/bpf.h> |
119 | |
120 | #include <net/if_gre.h> |
121 | |
122 | #include <compat/sys/socket.h> |
123 | #include <compat/sys/sockio.h> |
124 | |
125 | #include "ioconf.h" |
126 | |
127 | /* |
128 | * It is not easy to calculate the right value for a GRE MTU. |
129 | * We leave this task to the admin and use the same default that |
130 | * other vendors use. |
131 | */ |
132 | #define GREMTU 1476 |
133 | |
134 | #ifdef GRE_DEBUG |
135 | int gre_debug = 0; |
136 | #define GRE_DPRINTF(__sc, ...) \ |
137 | do { \ |
138 | if (__predict_false(gre_debug || \ |
139 | ((__sc)->sc_if.if_flags & IFF_DEBUG) != 0)) { \ |
140 | printf("%s.%d: ", __func__, __LINE__); \ |
141 | printf(__VA_ARGS__); \ |
142 | } \ |
143 | } while (/*CONSTCOND*/0) |
144 | #else |
145 | #define GRE_DPRINTF(__sc, __fmt, ...) do { } while (/*CONSTCOND*/0) |
146 | #endif /* GRE_DEBUG */ |
147 | |
148 | int ip_gre_ttl = GRE_TTL; |
149 | |
150 | static u_int gre_count; |
151 | |
152 | static int gre_clone_create(struct if_clone *, int); |
153 | static int gre_clone_destroy(struct ifnet *); |
154 | |
155 | static struct if_clone gre_cloner = |
156 | IF_CLONE_INITIALIZER("gre" , gre_clone_create, gre_clone_destroy); |
157 | |
158 | static int gre_input(struct gre_softc *, struct mbuf *, int, |
159 | const struct gre_h *); |
160 | static bool gre_is_nullconf(const struct gre_soparm *); |
161 | static int gre_output(struct ifnet *, struct mbuf *, |
162 | const struct sockaddr *, const struct rtentry *); |
163 | static int gre_ioctl(struct ifnet *, u_long, void *); |
164 | static int gre_getsockname(struct socket *, struct sockaddr *); |
165 | static int gre_getpeername(struct socket *, struct sockaddr *); |
166 | static int gre_getnames(struct socket *, struct lwp *, |
167 | struct sockaddr_storage *, struct sockaddr_storage *); |
168 | static void gre_clearconf(struct gre_soparm *, bool); |
169 | static int gre_soreceive(struct socket *, struct mbuf **); |
170 | static int gre_sosend(struct socket *, struct mbuf *); |
171 | static struct socket *gre_reconf(struct gre_softc *, const struct gre_soparm *); |
172 | |
173 | static bool gre_fp_send(struct gre_softc *, enum gre_msg, file_t *); |
174 | static bool gre_fp_recv(struct gre_softc *); |
175 | static void gre_fp_recvloop(void *); |
176 | |
177 | static void |
178 | gre_bufq_init(struct gre_bufq *bq, size_t len0) |
179 | { |
180 | memset(bq, 0, sizeof(*bq)); |
181 | bq->bq_q = pcq_create(len0, KM_SLEEP); |
182 | KASSERT(bq->bq_q != NULL); |
183 | } |
184 | |
185 | static struct mbuf * |
186 | gre_bufq_dequeue(struct gre_bufq *bq) |
187 | { |
188 | return pcq_get(bq->bq_q); |
189 | } |
190 | |
191 | static void |
192 | gre_bufq_purge(struct gre_bufq *bq) |
193 | { |
194 | struct mbuf *m; |
195 | |
196 | while ((m = gre_bufq_dequeue(bq)) != NULL) |
197 | m_freem(m); |
198 | } |
199 | |
200 | static void |
201 | gre_bufq_destroy(struct gre_bufq *bq) |
202 | { |
203 | gre_bufq_purge(bq); |
204 | pcq_destroy(bq->bq_q); |
205 | } |
206 | |
207 | static int |
208 | gre_bufq_enqueue(struct gre_bufq *bq, struct mbuf *m) |
209 | { |
210 | KASSERT(bq->bq_q != NULL); |
211 | |
212 | if (!pcq_put(bq->bq_q, m)) { |
213 | bq->bq_drops++; |
214 | return ENOBUFS; |
215 | } |
216 | return 0; |
217 | } |
218 | |
219 | static void |
220 | greintr(void *arg) |
221 | { |
222 | struct gre_softc *sc = (struct gre_softc *)arg; |
223 | struct socket *so = sc->sc_soparm.sp_so; |
224 | int rc; |
225 | struct mbuf *m; |
226 | |
227 | KASSERT(so != NULL); |
228 | |
229 | sc->sc_send_ev.ev_count++; |
230 | GRE_DPRINTF(sc, "enter\n" ); |
231 | while ((m = gre_bufq_dequeue(&sc->sc_snd)) != NULL) { |
232 | /* XXX handle ENOBUFS? */ |
233 | if ((rc = gre_sosend(so, m)) != 0) |
234 | GRE_DPRINTF(sc, "gre_sosend failed %d\n" , rc); |
235 | } |
236 | } |
237 | |
238 | /* Caller must hold sc->sc_mtx. */ |
239 | static void |
240 | gre_fp_wait(struct gre_softc *sc) |
241 | { |
242 | sc->sc_fp_waiters++; |
243 | cv_wait(&sc->sc_fp_condvar, &sc->sc_mtx); |
244 | sc->sc_fp_waiters--; |
245 | } |
246 | |
247 | static void |
248 | gre_evcnt_detach(struct gre_softc *sc) |
249 | { |
250 | evcnt_detach(&sc->sc_recv_ev); |
251 | evcnt_detach(&sc->sc_block_ev); |
252 | evcnt_detach(&sc->sc_error_ev); |
253 | evcnt_detach(&sc->sc_pullup_ev); |
254 | evcnt_detach(&sc->sc_unsupp_ev); |
255 | |
256 | evcnt_detach(&sc->sc_send_ev); |
257 | evcnt_detach(&sc->sc_oflow_ev); |
258 | } |
259 | |
260 | static void |
261 | gre_evcnt_attach(struct gre_softc *sc) |
262 | { |
263 | evcnt_attach_dynamic(&sc->sc_recv_ev, EVCNT_TYPE_MISC, |
264 | NULL, sc->sc_if.if_xname, "recv" ); |
265 | evcnt_attach_dynamic(&sc->sc_block_ev, EVCNT_TYPE_MISC, |
266 | &sc->sc_recv_ev, sc->sc_if.if_xname, "would block" ); |
267 | evcnt_attach_dynamic(&sc->sc_error_ev, EVCNT_TYPE_MISC, |
268 | &sc->sc_recv_ev, sc->sc_if.if_xname, "error" ); |
269 | evcnt_attach_dynamic(&sc->sc_pullup_ev, EVCNT_TYPE_MISC, |
270 | &sc->sc_recv_ev, sc->sc_if.if_xname, "pullup failed" ); |
271 | evcnt_attach_dynamic(&sc->sc_unsupp_ev, EVCNT_TYPE_MISC, |
272 | &sc->sc_recv_ev, sc->sc_if.if_xname, "unsupported" ); |
273 | |
274 | evcnt_attach_dynamic(&sc->sc_send_ev, EVCNT_TYPE_MISC, |
275 | NULL, sc->sc_if.if_xname, "send" ); |
276 | evcnt_attach_dynamic(&sc->sc_oflow_ev, EVCNT_TYPE_MISC, |
277 | &sc->sc_send_ev, sc->sc_if.if_xname, "overflow" ); |
278 | } |
279 | |
280 | static int |
281 | gre_clone_create(struct if_clone *ifc, int unit) |
282 | { |
283 | int rc; |
284 | struct gre_softc *sc; |
285 | struct gre_soparm *sp; |
286 | const struct sockaddr *any; |
287 | |
288 | if ((any = sockaddr_any_by_family(AF_INET)) == NULL && |
289 | (any = sockaddr_any_by_family(AF_INET6)) == NULL) |
290 | goto fail0; |
291 | |
292 | sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); |
293 | mutex_init(&sc->sc_mtx, MUTEX_DRIVER, IPL_SOFTNET); |
294 | cv_init(&sc->sc_condvar, "gre wait" ); |
295 | cv_init(&sc->sc_fp_condvar, "gre fp" ); |
296 | |
297 | if_initname(&sc->sc_if, ifc->ifc_name, unit); |
298 | sc->sc_if.if_softc = sc; |
299 | sc->sc_if.if_type = IFT_TUNNEL; |
300 | sc->sc_if.if_addrlen = 0; |
301 | sc->sc_if.if_hdrlen = sizeof(struct ip) + sizeof(struct gre_h); |
302 | sc->sc_if.if_dlt = DLT_NULL; |
303 | sc->sc_if.if_mtu = GREMTU; |
304 | sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST; |
305 | sc->sc_if.if_output = gre_output; |
306 | sc->sc_if.if_ioctl = gre_ioctl; |
307 | sp = &sc->sc_soparm; |
308 | sockaddr_copy(sstosa(&sp->sp_dst), sizeof(sp->sp_dst), any); |
309 | sockaddr_copy(sstosa(&sp->sp_src), sizeof(sp->sp_src), any); |
310 | sp->sp_proto = IPPROTO_GRE; |
311 | sp->sp_type = SOCK_RAW; |
312 | |
313 | sc->sc_fd = -1; |
314 | |
315 | rc = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, gre_fp_recvloop, sc, |
316 | NULL, "%s" , sc->sc_if.if_xname); |
317 | if (rc) |
318 | goto fail1; |
319 | |
320 | gre_evcnt_attach(sc); |
321 | |
322 | gre_bufq_init(&sc->sc_snd, 17); |
323 | sc->sc_if.if_flags |= IFF_LINK0; |
324 | if_attach(&sc->sc_if); |
325 | if_alloc_sadl(&sc->sc_if); |
326 | bpf_attach(&sc->sc_if, DLT_NULL, sizeof(uint32_t)); |
327 | atomic_inc_uint(&gre_count); |
328 | return 0; |
329 | |
330 | fail1: cv_destroy(&sc->sc_fp_condvar); |
331 | cv_destroy(&sc->sc_condvar); |
332 | mutex_destroy(&sc->sc_mtx); |
333 | free(sc, M_DEVBUF); |
334 | fail0: return -1; |
335 | } |
336 | |
337 | static int |
338 | gre_clone_destroy(struct ifnet *ifp) |
339 | { |
340 | int s; |
341 | struct gre_softc *sc = ifp->if_softc; |
342 | |
343 | GRE_DPRINTF(sc, "\n" ); |
344 | |
345 | bpf_detach(ifp); |
346 | s = splnet(); |
347 | if_detach(ifp); |
348 | |
349 | GRE_DPRINTF(sc, "\n" ); |
350 | /* Note that we must not hold the mutex while we call gre_reconf(). */ |
351 | gre_reconf(sc, NULL); |
352 | |
353 | mutex_enter(&sc->sc_mtx); |
354 | sc->sc_msg = GRE_M_STOP; |
355 | cv_signal(&sc->sc_fp_condvar); |
356 | while (sc->sc_fp_waiters > 0) |
357 | cv_wait(&sc->sc_fp_condvar, &sc->sc_mtx); |
358 | mutex_exit(&sc->sc_mtx); |
359 | |
360 | splx(s); |
361 | |
362 | cv_destroy(&sc->sc_condvar); |
363 | cv_destroy(&sc->sc_fp_condvar); |
364 | mutex_destroy(&sc->sc_mtx); |
365 | gre_bufq_destroy(&sc->sc_snd); |
366 | gre_evcnt_detach(sc); |
367 | free(sc, M_DEVBUF); |
368 | |
369 | atomic_dec_uint(&gre_count); |
370 | return 0; |
371 | } |
372 | |
373 | static void |
374 | gre_receive(struct socket *so, void *arg, int events, int waitflag) |
375 | { |
376 | struct gre_softc *sc = (struct gre_softc *)arg; |
377 | int rc; |
378 | const struct gre_h *gh; |
379 | struct mbuf *m; |
380 | |
381 | GRE_DPRINTF(sc, "enter\n" ); |
382 | |
383 | sc->sc_recv_ev.ev_count++; |
384 | |
385 | rc = gre_soreceive(so, &m); |
386 | /* TBD Back off if ECONNREFUSED (indicates |
387 | * ICMP Port Unreachable)? |
388 | */ |
389 | if (rc == EWOULDBLOCK) { |
390 | GRE_DPRINTF(sc, "EWOULDBLOCK\n" ); |
391 | sc->sc_block_ev.ev_count++; |
392 | return; |
393 | } else if (rc != 0 || m == NULL) { |
394 | GRE_DPRINTF(sc, "%s: rc %d m %p\n" , |
395 | sc->sc_if.if_xname, rc, (void *)m); |
396 | sc->sc_error_ev.ev_count++; |
397 | return; |
398 | } |
399 | if (m->m_len < sizeof(*gh) && (m = m_pullup(m, sizeof(*gh))) == NULL) { |
400 | GRE_DPRINTF(sc, "m_pullup failed\n" ); |
401 | sc->sc_pullup_ev.ev_count++; |
402 | return; |
403 | } |
404 | gh = mtod(m, const struct gre_h *); |
405 | |
406 | if (gre_input(sc, m, 0, gh) == 0) { |
407 | sc->sc_unsupp_ev.ev_count++; |
408 | GRE_DPRINTF(sc, "dropping unsupported\n" ); |
409 | m_freem(m); |
410 | } |
411 | } |
412 | |
413 | static void |
414 | gre_upcall_add(struct socket *so, void *arg) |
415 | { |
416 | /* XXX What if the kernel already set an upcall? */ |
417 | KASSERT((so->so_rcv.sb_flags & SB_UPCALL) == 0); |
418 | so->so_upcallarg = arg; |
419 | so->so_upcall = gre_receive; |
420 | so->so_rcv.sb_flags |= SB_UPCALL; |
421 | } |
422 | |
423 | static void |
424 | gre_upcall_remove(struct socket *so) |
425 | { |
426 | so->so_rcv.sb_flags &= ~SB_UPCALL; |
427 | so->so_upcallarg = NULL; |
428 | so->so_upcall = NULL; |
429 | } |
430 | |
431 | static int |
432 | gre_socreate(struct gre_softc *sc, const struct gre_soparm *sp, int *fdout) |
433 | { |
434 | int fd, rc; |
435 | struct socket *so; |
436 | struct sockaddr_big sbig; |
437 | sa_family_t af; |
438 | int val; |
439 | |
440 | GRE_DPRINTF(sc, "enter\n" ); |
441 | |
442 | af = sp->sp_src.ss_family; |
443 | rc = fsocreate(af, NULL, sp->sp_type, sp->sp_proto, &fd); |
444 | if (rc != 0) { |
445 | GRE_DPRINTF(sc, "fsocreate failed\n" ); |
446 | return rc; |
447 | } |
448 | |
449 | if ((rc = fd_getsock(fd, &so)) != 0) |
450 | return rc; |
451 | |
452 | memcpy(&sbig, &sp->sp_src, sizeof(sp->sp_src)); |
453 | if ((rc = sobind(so, (struct sockaddr *)&sbig, curlwp)) != 0) { |
454 | GRE_DPRINTF(sc, "sobind failed\n" ); |
455 | goto out; |
456 | } |
457 | |
458 | memcpy(&sbig, &sp->sp_dst, sizeof(sp->sp_dst)); |
459 | solock(so); |
460 | if ((rc = soconnect(so, (struct sockaddr *)&sbig, curlwp)) != 0) { |
461 | GRE_DPRINTF(sc, "soconnect failed\n" ); |
462 | sounlock(so); |
463 | goto out; |
464 | } |
465 | sounlock(so); |
466 | |
467 | /* XXX convert to a (new) SOL_SOCKET call */ |
468 | KASSERT(so->so_proto != NULL); |
469 | rc = so_setsockopt(curlwp, so, IPPROTO_IP, IP_TTL, |
470 | &ip_gre_ttl, sizeof(ip_gre_ttl)); |
471 | if (rc != 0) { |
472 | GRE_DPRINTF(sc, "so_setsockopt ttl failed\n" ); |
473 | rc = 0; |
474 | } |
475 | |
476 | val = 1; |
477 | rc = so_setsockopt(curlwp, so, SOL_SOCKET, SO_NOHEADER, |
478 | &val, sizeof(val)); |
479 | if (rc != 0) { |
480 | GRE_DPRINTF(sc, "so_setsockopt SO_NOHEADER failed\n" ); |
481 | rc = 0; |
482 | } |
483 | out: |
484 | if (rc != 0) |
485 | fd_close(fd); |
486 | else { |
487 | fd_putfile(fd); |
488 | *fdout = fd; |
489 | } |
490 | |
491 | return rc; |
492 | } |
493 | |
494 | static int |
495 | gre_sosend(struct socket *so, struct mbuf *top) |
496 | { |
497 | struct proc *p; |
498 | long space, resid; |
499 | int error; |
500 | struct lwp * const l = curlwp; |
501 | |
502 | p = l->l_proc; |
503 | |
504 | resid = top->m_pkthdr.len; |
505 | if (p) |
506 | l->l_ru.ru_msgsnd++; |
507 | #define snderr(errno) { error = errno; goto release; } |
508 | |
509 | solock(so); |
510 | if ((error = sblock(&so->so_snd, M_NOWAIT)) != 0) |
511 | goto out; |
512 | if (so->so_state & SS_CANTSENDMORE) |
513 | snderr(EPIPE); |
514 | if (so->so_error) { |
515 | error = so->so_error; |
516 | so->so_error = 0; |
517 | goto release; |
518 | } |
519 | if ((so->so_state & SS_ISCONNECTED) == 0) { |
520 | if (so->so_proto->pr_flags & PR_CONNREQUIRED) { |
521 | snderr(ENOTCONN); |
522 | } else { |
523 | snderr(EDESTADDRREQ); |
524 | } |
525 | } |
526 | space = sbspace(&so->so_snd); |
527 | if (resid > so->so_snd.sb_hiwat) |
528 | snderr(EMSGSIZE); |
529 | if (space < resid) |
530 | snderr(EWOULDBLOCK); |
531 | /* |
532 | * Data is prepackaged in "top". |
533 | */ |
534 | if (so->so_state & SS_CANTSENDMORE) |
535 | snderr(EPIPE); |
536 | error = (*so->so_proto->pr_usrreqs->pr_send)(so, |
537 | top, NULL, NULL, l); |
538 | top = NULL; |
539 | release: |
540 | sbunlock(&so->so_snd); |
541 | out: |
542 | sounlock(so); |
543 | if (top != NULL) |
544 | m_freem(top); |
545 | return error; |
546 | } |
547 | |
548 | /* This is a stripped-down version of soreceive() that will never |
549 | * block. It will support SOCK_DGRAM sockets. It may also support |
550 | * SOCK_SEQPACKET sockets. |
551 | */ |
552 | static int |
553 | gre_soreceive(struct socket *so, struct mbuf **mp0) |
554 | { |
555 | struct mbuf *m, **mp; |
556 | int flags, len, error, type; |
557 | const struct protosw *pr; |
558 | struct mbuf *nextrecord; |
559 | |
560 | KASSERT(mp0 != NULL); |
561 | |
562 | flags = MSG_DONTWAIT; |
563 | pr = so->so_proto; |
564 | mp = mp0; |
565 | type = 0; |
566 | |
567 | *mp = NULL; |
568 | |
569 | KASSERT(pr->pr_flags & PR_ATOMIC); |
570 | restart: |
571 | if ((error = sblock(&so->so_rcv, M_NOWAIT)) != 0) { |
572 | return error; |
573 | } |
574 | m = so->so_rcv.sb_mb; |
575 | /* |
576 | * If we have less data than requested, do not block awaiting more. |
577 | */ |
578 | if (m == NULL) { |
579 | #ifdef DIAGNOSTIC |
580 | if (so->so_rcv.sb_cc) |
581 | panic("receive 1" ); |
582 | #endif |
583 | if (so->so_error) { |
584 | error = so->so_error; |
585 | so->so_error = 0; |
586 | } else if (so->so_state & SS_CANTRCVMORE) |
587 | ; |
588 | else if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 |
589 | && (so->so_proto->pr_flags & PR_CONNREQUIRED)) |
590 | error = ENOTCONN; |
591 | else |
592 | error = EWOULDBLOCK; |
593 | goto release; |
594 | } |
595 | /* |
596 | * On entry here, m points to the first record of the socket buffer. |
597 | * While we process the initial mbufs containing address and control |
598 | * info, we save a copy of m->m_nextpkt into nextrecord. |
599 | */ |
600 | if (curlwp != NULL) |
601 | curlwp->l_ru.ru_msgrcv++; |
602 | KASSERT(m == so->so_rcv.sb_mb); |
603 | SBLASTRECORDCHK(&so->so_rcv, "soreceive 1" ); |
604 | SBLASTMBUFCHK(&so->so_rcv, "soreceive 1" ); |
605 | nextrecord = m->m_nextpkt; |
606 | if (pr->pr_flags & PR_ADDR) { |
607 | #ifdef DIAGNOSTIC |
608 | if (m->m_type != MT_SONAME) |
609 | panic("receive 1a" ); |
610 | #endif |
611 | sbfree(&so->so_rcv, m); |
612 | m = so->so_rcv.sb_mb = m_free(m); |
613 | } |
614 | while (m != NULL && m->m_type == MT_CONTROL && error == 0) { |
615 | sbfree(&so->so_rcv, m); |
616 | /* |
617 | * Dispose of any SCM_RIGHTS message that went |
618 | * through the read path rather than recv. |
619 | */ |
620 | if (pr->pr_domain->dom_dispose && |
621 | mtod(m, struct cmsghdr *)->cmsg_type == SCM_RIGHTS) |
622 | (*pr->pr_domain->dom_dispose)(m); |
623 | m = so->so_rcv.sb_mb = m_free(m); |
624 | } |
625 | |
626 | /* |
627 | * If m is non-NULL, we have some data to read. From now on, |
628 | * make sure to keep sb_lastrecord consistent when working on |
629 | * the last packet on the chain (nextrecord == NULL) and we |
630 | * change m->m_nextpkt. |
631 | */ |
632 | if (m != NULL) { |
633 | m->m_nextpkt = nextrecord; |
634 | /* |
635 | * If nextrecord == NULL (this is a single chain), |
636 | * then sb_lastrecord may not be valid here if m |
637 | * was changed earlier. |
638 | */ |
639 | if (nextrecord == NULL) { |
640 | KASSERT(so->so_rcv.sb_mb == m); |
641 | so->so_rcv.sb_lastrecord = m; |
642 | } |
643 | type = m->m_type; |
644 | if (type == MT_OOBDATA) |
645 | flags |= MSG_OOB; |
646 | } else { |
647 | KASSERT(so->so_rcv.sb_mb == m); |
648 | so->so_rcv.sb_mb = nextrecord; |
649 | SB_EMPTY_FIXUP(&so->so_rcv); |
650 | } |
651 | SBLASTRECORDCHK(&so->so_rcv, "soreceive 2" ); |
652 | SBLASTMBUFCHK(&so->so_rcv, "soreceive 2" ); |
653 | |
654 | while (m != NULL) { |
655 | if (m->m_type == MT_OOBDATA) { |
656 | if (type != MT_OOBDATA) |
657 | break; |
658 | } else if (type == MT_OOBDATA) |
659 | break; |
660 | #ifdef DIAGNOSTIC |
661 | else if (m->m_type != MT_DATA && m->m_type != MT_HEADER) |
662 | panic("receive 3" ); |
663 | #endif |
664 | so->so_state &= ~SS_RCVATMARK; |
665 | if (so->so_oobmark != 0 && so->so_oobmark < m->m_len) |
666 | break; |
667 | len = m->m_len; |
668 | /* |
669 | * mp is set, just pass back the mbufs. |
670 | * Sockbuf must be consistent here (points to current mbuf, |
671 | * it points to next record) when we drop priority; |
672 | * we must note any additions to the sockbuf when we |
673 | * block interrupts again. |
674 | */ |
675 | if (m->m_flags & M_EOR) |
676 | flags |= MSG_EOR; |
677 | nextrecord = m->m_nextpkt; |
678 | sbfree(&so->so_rcv, m); |
679 | *mp = m; |
680 | mp = &m->m_next; |
681 | so->so_rcv.sb_mb = m = m->m_next; |
682 | *mp = NULL; |
683 | /* |
684 | * If m != NULL, we also know that |
685 | * so->so_rcv.sb_mb != NULL. |
686 | */ |
687 | KASSERT(so->so_rcv.sb_mb == m); |
688 | if (m) { |
689 | m->m_nextpkt = nextrecord; |
690 | if (nextrecord == NULL) |
691 | so->so_rcv.sb_lastrecord = m; |
692 | } else { |
693 | so->so_rcv.sb_mb = nextrecord; |
694 | SB_EMPTY_FIXUP(&so->so_rcv); |
695 | } |
696 | SBLASTRECORDCHK(&so->so_rcv, "soreceive 3" ); |
697 | SBLASTMBUFCHK(&so->so_rcv, "soreceive 3" ); |
698 | if (so->so_oobmark) { |
699 | so->so_oobmark -= len; |
700 | if (so->so_oobmark == 0) { |
701 | so->so_state |= SS_RCVATMARK; |
702 | break; |
703 | } |
704 | } |
705 | if (flags & MSG_EOR) |
706 | break; |
707 | } |
708 | |
709 | if (m != NULL) { |
710 | m_freem(*mp); |
711 | *mp = NULL; |
712 | error = ENOMEM; |
713 | (void) sbdroprecord(&so->so_rcv); |
714 | } else { |
715 | /* |
716 | * First part is an inline SB_EMPTY_FIXUP(). Second |
717 | * part makes sure sb_lastrecord is up-to-date if |
718 | * there is still data in the socket buffer. |
719 | */ |
720 | so->so_rcv.sb_mb = nextrecord; |
721 | if (so->so_rcv.sb_mb == NULL) { |
722 | so->so_rcv.sb_mbtail = NULL; |
723 | so->so_rcv.sb_lastrecord = NULL; |
724 | } else if (nextrecord->m_nextpkt == NULL) |
725 | so->so_rcv.sb_lastrecord = nextrecord; |
726 | } |
727 | SBLASTRECORDCHK(&so->so_rcv, "soreceive 4" ); |
728 | SBLASTMBUFCHK(&so->so_rcv, "soreceive 4" ); |
729 | if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) |
730 | (*pr->pr_usrreqs->pr_rcvd)(so, flags, curlwp); |
731 | if (*mp0 == NULL && (flags & MSG_EOR) == 0 && |
732 | (so->so_state & SS_CANTRCVMORE) == 0) { |
733 | sbunlock(&so->so_rcv); |
734 | goto restart; |
735 | } |
736 | |
737 | release: |
738 | sbunlock(&so->so_rcv); |
739 | return error; |
740 | } |
741 | |
742 | static struct socket * |
743 | gre_reconf(struct gre_softc *sc, const struct gre_soparm *newsoparm) |
744 | { |
745 | struct ifnet *ifp = &sc->sc_if; |
746 | |
747 | GRE_DPRINTF(sc, "enter\n" ); |
748 | |
749 | shutdown: |
750 | if (sc->sc_soparm.sp_so != NULL) { |
751 | GRE_DPRINTF(sc, "\n" ); |
752 | gre_upcall_remove(sc->sc_soparm.sp_so); |
753 | softint_disestablish(sc->sc_si); |
754 | sc->sc_si = NULL; |
755 | gre_fp_send(sc, GRE_M_DELFP, NULL); |
756 | gre_clearconf(&sc->sc_soparm, false); |
757 | } |
758 | |
759 | if (newsoparm != NULL) { |
760 | GRE_DPRINTF(sc, "\n" ); |
761 | sc->sc_soparm = *newsoparm; |
762 | newsoparm = NULL; |
763 | } |
764 | |
765 | if (sc->sc_soparm.sp_so != NULL) { |
766 | GRE_DPRINTF(sc, "\n" ); |
767 | sc->sc_si = softint_establish(SOFTINT_NET, greintr, sc); |
768 | gre_upcall_add(sc->sc_soparm.sp_so, sc); |
769 | if ((ifp->if_flags & IFF_UP) == 0) { |
770 | GRE_DPRINTF(sc, "down\n" ); |
771 | goto shutdown; |
772 | } |
773 | } |
774 | |
775 | GRE_DPRINTF(sc, "\n" ); |
776 | if (sc->sc_soparm.sp_so != NULL) |
777 | sc->sc_if.if_flags |= IFF_RUNNING; |
778 | else { |
779 | gre_bufq_purge(&sc->sc_snd); |
780 | sc->sc_if.if_flags &= ~IFF_RUNNING; |
781 | } |
782 | return sc->sc_soparm.sp_so; |
783 | } |
784 | |
785 | static int |
786 | gre_input(struct gre_softc *sc, struct mbuf *m, int hlen, |
787 | const struct gre_h *gh) |
788 | { |
789 | pktqueue_t *pktq = NULL; |
790 | struct ifqueue *ifq = NULL; |
791 | uint16_t flags; |
792 | uint32_t af; /* af passed to BPF tap */ |
793 | int isr = 0, s; |
794 | |
795 | sc->sc_if.if_ipackets++; |
796 | sc->sc_if.if_ibytes += m->m_pkthdr.len; |
797 | |
798 | hlen += sizeof(struct gre_h); |
799 | |
800 | /* process GRE flags as packet can be of variable len */ |
801 | flags = ntohs(gh->flags); |
802 | |
803 | /* Checksum & Offset are present */ |
804 | if ((flags & GRE_CP) | (flags & GRE_RP)) |
805 | hlen += 4; |
806 | /* We don't support routing fields (variable length) */ |
807 | if (flags & GRE_RP) { |
808 | sc->sc_if.if_ierrors++; |
809 | return 0; |
810 | } |
811 | if (flags & GRE_KP) |
812 | hlen += 4; |
813 | if (flags & GRE_SP) |
814 | hlen += 4; |
815 | |
816 | switch (ntohs(gh->ptype)) { /* ethertypes */ |
817 | #ifdef INET |
818 | case ETHERTYPE_IP: |
819 | pktq = ip_pktq; |
820 | af = AF_INET; |
821 | break; |
822 | #endif |
823 | #ifdef NETATALK |
824 | case ETHERTYPE_ATALK: |
825 | ifq = &atintrq1; |
826 | isr = NETISR_ATALK; |
827 | af = AF_APPLETALK; |
828 | break; |
829 | #endif |
830 | #ifdef INET6 |
831 | case ETHERTYPE_IPV6: |
832 | pktq = ip6_pktq; |
833 | af = AF_INET6; |
834 | break; |
835 | #endif |
836 | #ifdef MPLS |
837 | case ETHERTYPE_MPLS: |
838 | ifq = &mplsintrq; |
839 | isr = NETISR_MPLS; |
840 | af = AF_MPLS; |
841 | break; |
842 | #endif |
843 | default: /* others not yet supported */ |
844 | GRE_DPRINTF(sc, "unhandled ethertype 0x%04x\n" , |
845 | ntohs(gh->ptype)); |
846 | sc->sc_if.if_noproto++; |
847 | return 0; |
848 | } |
849 | |
850 | if (hlen > m->m_pkthdr.len) { |
851 | m_freem(m); |
852 | sc->sc_if.if_ierrors++; |
853 | return EINVAL; |
854 | } |
855 | m_adj(m, hlen); |
856 | |
857 | bpf_mtap_af(&sc->sc_if, af, m); |
858 | |
859 | m_set_rcvif(m, &sc->sc_if); |
860 | |
861 | if (__predict_true(pktq)) { |
862 | if (__predict_false(!pktq_enqueue(pktq, m, 0))) { |
863 | m_freem(m); |
864 | } |
865 | return 1; |
866 | } |
867 | |
868 | s = splnet(); |
869 | if (IF_QFULL(ifq)) { |
870 | IF_DROP(ifq); |
871 | m_freem(m); |
872 | } else { |
873 | IF_ENQUEUE(ifq, m); |
874 | } |
875 | /* we need schednetisr since the address family may change */ |
876 | schednetisr(isr); |
877 | splx(s); |
878 | |
879 | return 1; /* packet is done, no further processing needed */ |
880 | } |
881 | |
882 | /* |
883 | * The output routine. Takes a packet and encapsulates it in the protocol |
884 | * given by sc->sc_soparm.sp_proto. See also RFC 1701 and RFC 2004 |
885 | */ |
886 | static int |
887 | gre_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, |
888 | const struct rtentry *rt) |
889 | { |
890 | int error = 0; |
891 | struct gre_softc *sc = ifp->if_softc; |
892 | struct gre_h *gh; |
893 | uint16_t etype = 0; |
894 | |
895 | if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { |
896 | m_freem(m); |
897 | error = ENETDOWN; |
898 | goto end; |
899 | } |
900 | |
901 | bpf_mtap_af(ifp, dst->sa_family, m); |
902 | |
903 | m->m_flags &= ~(M_BCAST|M_MCAST); |
904 | |
905 | GRE_DPRINTF(sc, "dst->sa_family=%d\n" , dst->sa_family); |
906 | switch (dst->sa_family) { |
907 | #ifdef INET |
908 | case AF_INET: |
909 | /* TBD Extract the IP ToS field and set the |
910 | * encapsulating protocol's ToS to suit. |
911 | */ |
912 | etype = htons(ETHERTYPE_IP); |
913 | break; |
914 | #endif |
915 | #ifdef NETATALK |
916 | case AF_APPLETALK: |
917 | etype = htons(ETHERTYPE_ATALK); |
918 | break; |
919 | #endif |
920 | #ifdef INET6 |
921 | case AF_INET6: |
922 | etype = htons(ETHERTYPE_IPV6); |
923 | break; |
924 | #endif |
925 | default: |
926 | IF_DROP(&ifp->if_snd); |
927 | m_freem(m); |
928 | error = EAFNOSUPPORT; |
929 | goto end; |
930 | } |
931 | |
932 | #ifdef MPLS |
933 | if (rt != NULL && rt_gettag(rt) != NULL) { |
934 | union mpls_shim msh; |
935 | msh.s_addr = MPLS_GETSADDR(rt); |
936 | if (msh.shim.label != MPLS_LABEL_IMPLNULL) |
937 | etype = htons(ETHERTYPE_MPLS); |
938 | } |
939 | #endif |
940 | |
941 | M_PREPEND(m, sizeof(*gh), M_DONTWAIT); |
942 | |
943 | if (m == NULL) { |
944 | IF_DROP(&ifp->if_snd); |
945 | error = ENOBUFS; |
946 | goto end; |
947 | } |
948 | |
949 | gh = mtod(m, struct gre_h *); |
950 | gh->flags = 0; |
951 | gh->ptype = etype; |
952 | /* XXX Need to handle IP ToS. Look at how I handle IP TTL. */ |
953 | |
954 | ifp->if_opackets++; |
955 | ifp->if_obytes += m->m_pkthdr.len; |
956 | |
957 | /* Clear checksum-offload flags. */ |
958 | m->m_pkthdr.csum_flags = 0; |
959 | m->m_pkthdr.csum_data = 0; |
960 | |
961 | /* send it off */ |
962 | if ((error = gre_bufq_enqueue(&sc->sc_snd, m)) != 0) { |
963 | sc->sc_oflow_ev.ev_count++; |
964 | m_freem(m); |
965 | } else |
966 | softint_schedule(sc->sc_si); |
967 | end: |
968 | if (error) |
969 | ifp->if_oerrors++; |
970 | return error; |
971 | } |
972 | |
973 | static int |
974 | gre_getsockname(struct socket *so, struct sockaddr *nam) |
975 | { |
976 | return (*so->so_proto->pr_usrreqs->pr_sockaddr)(so, nam); |
977 | } |
978 | |
979 | static int |
980 | gre_getpeername(struct socket *so, struct sockaddr *nam) |
981 | { |
982 | return (*so->so_proto->pr_usrreqs->pr_peeraddr)(so, nam); |
983 | } |
984 | |
985 | static int |
986 | gre_getnames(struct socket *so, struct lwp *l, struct sockaddr_storage *src, |
987 | struct sockaddr_storage *dst) |
988 | { |
989 | struct sockaddr_storage ss; |
990 | int rc; |
991 | |
992 | solock(so); |
993 | if ((rc = gre_getsockname(so, (struct sockaddr *)&ss)) != 0) |
994 | goto out; |
995 | *src = ss; |
996 | |
997 | if ((rc = gre_getpeername(so, (struct sockaddr *)&ss)) != 0) |
998 | goto out; |
999 | *dst = ss; |
1000 | out: |
1001 | sounlock(so); |
1002 | return rc; |
1003 | } |
1004 | |
1005 | static void |
1006 | gre_fp_recvloop(void *arg) |
1007 | { |
1008 | struct gre_softc *sc = arg; |
1009 | |
1010 | mutex_enter(&sc->sc_mtx); |
1011 | while (gre_fp_recv(sc)) |
1012 | ; |
1013 | mutex_exit(&sc->sc_mtx); |
1014 | kthread_exit(0); |
1015 | } |
1016 | |
1017 | static bool |
1018 | gre_fp_recv(struct gre_softc *sc) |
1019 | { |
1020 | int fd, ofd, rc; |
1021 | file_t *fp; |
1022 | |
1023 | fp = sc->sc_fp; |
1024 | ofd = sc->sc_fd; |
1025 | fd = -1; |
1026 | |
1027 | switch (sc->sc_msg) { |
1028 | case GRE_M_STOP: |
1029 | cv_signal(&sc->sc_fp_condvar); |
1030 | return false; |
1031 | case GRE_M_SETFP: |
1032 | mutex_exit(&sc->sc_mtx); |
1033 | rc = fd_dup(fp, 0, &fd, 0); |
1034 | mutex_enter(&sc->sc_mtx); |
1035 | if (rc != 0) { |
1036 | sc->sc_msg = GRE_M_ERR; |
1037 | break; |
1038 | } |
1039 | /*FALLTHROUGH*/ |
1040 | case GRE_M_DELFP: |
1041 | mutex_exit(&sc->sc_mtx); |
1042 | if (ofd != -1 && fd_getfile(ofd) != NULL) |
1043 | fd_close(ofd); |
1044 | mutex_enter(&sc->sc_mtx); |
1045 | sc->sc_fd = fd; |
1046 | sc->sc_msg = GRE_M_OK; |
1047 | break; |
1048 | default: |
1049 | gre_fp_wait(sc); |
1050 | return true; |
1051 | } |
1052 | cv_signal(&sc->sc_fp_condvar); |
1053 | return true; |
1054 | } |
1055 | |
1056 | static bool |
1057 | gre_fp_send(struct gre_softc *sc, enum gre_msg msg, file_t *fp) |
1058 | { |
1059 | bool rc; |
1060 | |
1061 | mutex_enter(&sc->sc_mtx); |
1062 | while (sc->sc_msg != GRE_M_NONE) |
1063 | gre_fp_wait(sc); |
1064 | sc->sc_fp = fp; |
1065 | sc->sc_msg = msg; |
1066 | cv_signal(&sc->sc_fp_condvar); |
1067 | while (sc->sc_msg != GRE_M_STOP && sc->sc_msg != GRE_M_OK && |
1068 | sc->sc_msg != GRE_M_ERR) |
1069 | gre_fp_wait(sc); |
1070 | rc = (sc->sc_msg != GRE_M_ERR); |
1071 | sc->sc_msg = GRE_M_NONE; |
1072 | cv_signal(&sc->sc_fp_condvar); |
1073 | mutex_exit(&sc->sc_mtx); |
1074 | return rc; |
1075 | } |
1076 | |
1077 | static int |
1078 | gre_ssock(struct ifnet *ifp, struct gre_soparm *sp, int fd) |
1079 | { |
1080 | int error = 0; |
1081 | const struct protosw *pr; |
1082 | file_t *fp; |
1083 | struct gre_softc *sc = ifp->if_softc; |
1084 | struct socket *so; |
1085 | struct sockaddr_storage dst, src; |
1086 | |
1087 | if ((fp = fd_getfile(fd)) == NULL) |
1088 | return EBADF; |
1089 | if (fp->f_type != DTYPE_SOCKET) { |
1090 | fd_putfile(fd); |
1091 | return ENOTSOCK; |
1092 | } |
1093 | |
1094 | GRE_DPRINTF(sc, "\n" ); |
1095 | |
1096 | so = fp->f_socket; |
1097 | pr = so->so_proto; |
1098 | |
1099 | GRE_DPRINTF(sc, "type %d, proto %d\n" , pr->pr_type, pr->pr_protocol); |
1100 | |
1101 | if ((pr->pr_flags & PR_ATOMIC) == 0 || |
1102 | (sp->sp_type != 0 && pr->pr_type != sp->sp_type) || |
1103 | (sp->sp_proto != 0 && pr->pr_protocol != 0 && |
1104 | pr->pr_protocol != sp->sp_proto)) { |
1105 | error = EINVAL; |
1106 | goto err; |
1107 | } |
1108 | |
1109 | GRE_DPRINTF(sc, "\n" ); |
1110 | |
1111 | /* check address */ |
1112 | if ((error = gre_getnames(so, curlwp, &src, &dst)) != 0) |
1113 | goto err; |
1114 | |
1115 | GRE_DPRINTF(sc, "\n" ); |
1116 | |
1117 | if (!gre_fp_send(sc, GRE_M_SETFP, fp)) { |
1118 | error = EBUSY; |
1119 | goto err; |
1120 | } |
1121 | |
1122 | GRE_DPRINTF(sc, "\n" ); |
1123 | |
1124 | sp->sp_src = src; |
1125 | sp->sp_dst = dst; |
1126 | |
1127 | sp->sp_so = so; |
1128 | |
1129 | err: |
1130 | fd_putfile(fd); |
1131 | return error; |
1132 | } |
1133 | |
1134 | static bool |
1135 | sockaddr_is_anyaddr(const struct sockaddr *sa) |
1136 | { |
1137 | socklen_t anylen, salen; |
1138 | const void *anyaddr, *addr; |
1139 | |
1140 | if ((anyaddr = sockaddr_anyaddr(sa, &anylen)) == NULL || |
1141 | (addr = sockaddr_const_addr(sa, &salen)) == NULL) |
1142 | return false; |
1143 | |
1144 | if (salen > anylen) |
1145 | return false; |
1146 | |
1147 | return memcmp(anyaddr, addr, MIN(anylen, salen)) == 0; |
1148 | } |
1149 | |
1150 | static bool |
1151 | gre_is_nullconf(const struct gre_soparm *sp) |
1152 | { |
1153 | return sockaddr_is_anyaddr(sstocsa(&sp->sp_src)) || |
1154 | sockaddr_is_anyaddr(sstocsa(&sp->sp_dst)); |
1155 | } |
1156 | |
1157 | static void |
1158 | gre_clearconf(struct gre_soparm *sp, bool force) |
1159 | { |
1160 | if (sp->sp_bysock || force) { |
1161 | sockaddr_copy(sstosa(&sp->sp_src), sizeof(sp->sp_src), |
1162 | sockaddr_any(sstosa(&sp->sp_src))); |
1163 | sockaddr_copy(sstosa(&sp->sp_dst), sizeof(sp->sp_dst), |
1164 | sockaddr_any(sstosa(&sp->sp_dst))); |
1165 | sp->sp_bysock = false; |
1166 | } |
1167 | sp->sp_so = NULL; /* XXX */ |
1168 | } |
1169 | |
1170 | static int |
1171 | gre_ioctl(struct ifnet *ifp, const u_long cmd, void *data) |
1172 | { |
1173 | struct ifreq *ifr; |
1174 | struct ifaddr *ifa = (struct ifaddr *)data; |
1175 | struct if_laddrreq *lifr = (struct if_laddrreq *)data; |
1176 | struct gre_softc *sc = ifp->if_softc; |
1177 | struct gre_soparm *sp; |
1178 | int fd, error = 0, oproto, otype, s; |
1179 | struct gre_soparm sp0; |
1180 | |
1181 | ifr = data; |
1182 | |
1183 | GRE_DPRINTF(sc, "cmd %lu\n" , cmd); |
1184 | |
1185 | switch (cmd) { |
1186 | case GRESPROTO: |
1187 | case GRESADDRD: |
1188 | case GRESADDRS: |
1189 | case GRESSOCK: |
1190 | case GREDSOCK: |
1191 | if (kauth_authorize_network(curlwp->l_cred, |
1192 | KAUTH_NETWORK_INTERFACE, |
1193 | KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd, |
1194 | NULL) != 0) |
1195 | return EPERM; |
1196 | break; |
1197 | default: |
1198 | break; |
1199 | } |
1200 | |
1201 | s = splnet(); |
1202 | |
1203 | sp0 = sc->sc_soparm; |
1204 | sp0.sp_so = NULL; |
1205 | sp = &sp0; |
1206 | |
1207 | GRE_DPRINTF(sc, "\n" ); |
1208 | |
1209 | switch (cmd) { |
1210 | case SIOCINITIFADDR: |
1211 | GRE_DPRINTF(sc, "\n" ); |
1212 | if ((ifp->if_flags & IFF_UP) != 0) |
1213 | break; |
1214 | gre_clearconf(sp, false); |
1215 | ifp->if_flags |= IFF_UP; |
1216 | ifa->ifa_rtrequest = p2p_rtrequest; |
1217 | goto mksocket; |
1218 | case SIOCSIFFLAGS: |
1219 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) |
1220 | break; |
1221 | oproto = sp->sp_proto; |
1222 | otype = sp->sp_type; |
1223 | switch (ifr->ifr_flags & (IFF_LINK0|IFF_LINK2)) { |
1224 | case IFF_LINK0|IFF_LINK2: |
1225 | sp->sp_proto = IPPROTO_UDP; |
1226 | sp->sp_type = SOCK_DGRAM; |
1227 | break; |
1228 | case IFF_LINK2: |
1229 | sp->sp_proto = 0; |
1230 | sp->sp_type = 0; |
1231 | break; |
1232 | case IFF_LINK0: |
1233 | sp->sp_proto = IPPROTO_GRE; |
1234 | sp->sp_type = SOCK_RAW; |
1235 | break; |
1236 | default: |
1237 | GRE_DPRINTF(sc, "\n" ); |
1238 | error = EINVAL; |
1239 | goto out; |
1240 | } |
1241 | GRE_DPRINTF(sc, "\n" ); |
1242 | gre_clearconf(sp, false); |
1243 | if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == |
1244 | (IFF_UP|IFF_RUNNING) && |
1245 | (oproto == sp->sp_proto || sp->sp_proto == 0) && |
1246 | (otype == sp->sp_type || sp->sp_type == 0)) |
1247 | break; |
1248 | switch (sp->sp_proto) { |
1249 | case IPPROTO_UDP: |
1250 | case IPPROTO_GRE: |
1251 | goto mksocket; |
1252 | default: |
1253 | break; |
1254 | } |
1255 | break; |
1256 | case SIOCSIFMTU: |
1257 | /* XXX determine MTU automatically by probing w/ |
1258 | * XXX do-not-fragment packets? |
1259 | */ |
1260 | if (ifr->ifr_mtu < 576) { |
1261 | error = EINVAL; |
1262 | break; |
1263 | } |
1264 | /*FALLTHROUGH*/ |
1265 | case SIOCGIFMTU: |
1266 | if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET) |
1267 | error = 0; |
1268 | break; |
1269 | case SIOCADDMULTI: |
1270 | case SIOCDELMULTI: |
1271 | if (ifr == NULL) { |
1272 | error = EAFNOSUPPORT; |
1273 | break; |
1274 | } |
1275 | switch (ifreq_getaddr(cmd, ifr)->sa_family) { |
1276 | #ifdef INET |
1277 | case AF_INET: |
1278 | break; |
1279 | #endif |
1280 | #ifdef INET6 |
1281 | case AF_INET6: |
1282 | break; |
1283 | #endif |
1284 | default: |
1285 | error = EAFNOSUPPORT; |
1286 | break; |
1287 | } |
1288 | break; |
1289 | case GRESPROTO: |
1290 | gre_clearconf(sp, false); |
1291 | oproto = sp->sp_proto; |
1292 | otype = sp->sp_type; |
1293 | sp->sp_proto = ifr->ifr_flags; |
1294 | switch (sp->sp_proto) { |
1295 | case IPPROTO_UDP: |
1296 | ifp->if_flags |= IFF_LINK0|IFF_LINK2; |
1297 | sp->sp_type = SOCK_DGRAM; |
1298 | break; |
1299 | case IPPROTO_GRE: |
1300 | ifp->if_flags |= IFF_LINK0; |
1301 | ifp->if_flags &= ~IFF_LINK2; |
1302 | sp->sp_type = SOCK_RAW; |
1303 | break; |
1304 | case 0: |
1305 | ifp->if_flags &= ~IFF_LINK0; |
1306 | ifp->if_flags |= IFF_LINK2; |
1307 | sp->sp_type = 0; |
1308 | break; |
1309 | default: |
1310 | error = EPROTONOSUPPORT; |
1311 | break; |
1312 | } |
1313 | if ((oproto == sp->sp_proto || sp->sp_proto == 0) && |
1314 | (otype == sp->sp_type || sp->sp_type == 0)) |
1315 | break; |
1316 | switch (sp->sp_proto) { |
1317 | case IPPROTO_UDP: |
1318 | case IPPROTO_GRE: |
1319 | goto mksocket; |
1320 | default: |
1321 | break; |
1322 | } |
1323 | break; |
1324 | case GREGPROTO: |
1325 | ifr->ifr_flags = sp->sp_proto; |
1326 | break; |
1327 | case GRESADDRS: |
1328 | case GRESADDRD: |
1329 | gre_clearconf(sp, false); |
1330 | /* set tunnel endpoints and mark interface as up */ |
1331 | switch (cmd) { |
1332 | case GRESADDRS: |
1333 | sockaddr_copy(sstosa(&sp->sp_src), |
1334 | sizeof(sp->sp_src), ifreq_getaddr(cmd, ifr)); |
1335 | break; |
1336 | case GRESADDRD: |
1337 | sockaddr_copy(sstosa(&sp->sp_dst), |
1338 | sizeof(sp->sp_dst), ifreq_getaddr(cmd, ifr)); |
1339 | break; |
1340 | } |
1341 | checkaddr: |
1342 | if (sockaddr_any(sstosa(&sp->sp_src)) == NULL || |
1343 | sockaddr_any(sstosa(&sp->sp_dst)) == NULL) { |
1344 | error = EINVAL; |
1345 | break; |
1346 | } |
1347 | /* let gre_socreate() check the rest */ |
1348 | mksocket: |
1349 | GRE_DPRINTF(sc, "\n" ); |
1350 | /* If we're administratively down, or the configuration |
1351 | * is empty, there's no use creating a socket. |
1352 | */ |
1353 | if ((ifp->if_flags & IFF_UP) == 0 || gre_is_nullconf(sp)) |
1354 | goto sendconf; |
1355 | |
1356 | GRE_DPRINTF(sc, "\n" ); |
1357 | fd = 0; |
1358 | error = gre_socreate(sc, sp, &fd); |
1359 | if (error != 0) |
1360 | break; |
1361 | |
1362 | setsock: |
1363 | GRE_DPRINTF(sc, "\n" ); |
1364 | |
1365 | error = gre_ssock(ifp, sp, fd); |
1366 | |
1367 | if (cmd != GRESSOCK) { |
1368 | GRE_DPRINTF(sc, "\n" ); |
1369 | /* XXX v. dodgy */ |
1370 | if (fd_getfile(fd) != NULL) |
1371 | fd_close(fd); |
1372 | } |
1373 | |
1374 | if (error == 0) { |
1375 | sendconf: |
1376 | GRE_DPRINTF(sc, "\n" ); |
1377 | ifp->if_flags &= ~IFF_RUNNING; |
1378 | gre_reconf(sc, sp); |
1379 | } |
1380 | |
1381 | break; |
1382 | case GREGADDRS: |
1383 | ifreq_setaddr(cmd, ifr, sstosa(&sp->sp_src)); |
1384 | break; |
1385 | case GREGADDRD: |
1386 | ifreq_setaddr(cmd, ifr, sstosa(&sp->sp_dst)); |
1387 | break; |
1388 | case GREDSOCK: |
1389 | GRE_DPRINTF(sc, "\n" ); |
1390 | if (sp->sp_bysock) |
1391 | ifp->if_flags &= ~IFF_UP; |
1392 | gre_clearconf(sp, false); |
1393 | goto mksocket; |
1394 | case GRESSOCK: |
1395 | GRE_DPRINTF(sc, "\n" ); |
1396 | gre_clearconf(sp, true); |
1397 | fd = (int)ifr->ifr_value; |
1398 | sp->sp_bysock = true; |
1399 | ifp->if_flags |= IFF_UP; |
1400 | goto setsock; |
1401 | case SIOCSLIFPHYADDR: |
1402 | GRE_DPRINTF(sc, "\n" ); |
1403 | if (lifr->addr.ss_family != lifr->dstaddr.ss_family) { |
1404 | error = EAFNOSUPPORT; |
1405 | break; |
1406 | } |
1407 | sockaddr_copy(sstosa(&sp->sp_src), sizeof(sp->sp_src), |
1408 | sstosa(&lifr->addr)); |
1409 | sockaddr_copy(sstosa(&sp->sp_dst), sizeof(sp->sp_dst), |
1410 | sstosa(&lifr->dstaddr)); |
1411 | GRE_DPRINTF(sc, "\n" ); |
1412 | goto checkaddr; |
1413 | case SIOCDIFPHYADDR: |
1414 | GRE_DPRINTF(sc, "\n" ); |
1415 | gre_clearconf(sp, true); |
1416 | ifp->if_flags &= ~IFF_UP; |
1417 | goto mksocket; |
1418 | case SIOCGLIFPHYADDR: |
1419 | GRE_DPRINTF(sc, "\n" ); |
1420 | if (gre_is_nullconf(sp)) { |
1421 | error = EADDRNOTAVAIL; |
1422 | break; |
1423 | } |
1424 | sockaddr_copy(sstosa(&lifr->addr), sizeof(lifr->addr), |
1425 | sstosa(&sp->sp_src)); |
1426 | sockaddr_copy(sstosa(&lifr->dstaddr), sizeof(lifr->dstaddr), |
1427 | sstosa(&sp->sp_dst)); |
1428 | GRE_DPRINTF(sc, "\n" ); |
1429 | break; |
1430 | default: |
1431 | error = ifioctl_common(ifp, cmd, data); |
1432 | break; |
1433 | } |
1434 | out: |
1435 | GRE_DPRINTF(sc, "\n" ); |
1436 | splx(s); |
1437 | return error; |
1438 | } |
1439 | |
1440 | /* ARGSUSED */ |
1441 | void |
1442 | greattach(int count) |
1443 | { |
1444 | |
1445 | /* |
1446 | * Nothing to do here, initialization is handled by the |
1447 | * module initialization code in greinit() below). |
1448 | */ |
1449 | } |
1450 | |
1451 | static void |
1452 | greinit(void) |
1453 | { |
1454 | if_clone_attach(&gre_cloner); |
1455 | } |
1456 | |
1457 | static int |
1458 | gredetach(void) |
1459 | { |
1460 | int error = 0; |
1461 | |
1462 | if (gre_count != 0) |
1463 | error = EBUSY; |
1464 | |
1465 | if (error == 0) |
1466 | if_clone_detach(&gre_cloner); |
1467 | |
1468 | return error; |
1469 | } |
1470 | |
1471 | /* |
1472 | * Module infrastructure |
1473 | */ |
1474 | #include "if_module.h" |
1475 | |
1476 | IF_MODULE(MODULE_CLASS_DRIVER, gre, "" ) |
1477 | |