Line data Source code
1 : /* $OpenBSD: if_mobileip.c,v 1.8 2018/02/18 23:53:17 dlg Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2016 David Gwynne <dlg@openbsd.org>
5 : *
6 : * Permission to use, copy, modify, and distribute this software for any
7 : * purpose with or without fee is hereby granted, provided that the above
8 : * copyright notice and this permission notice appear in all copies.
9 : *
10 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 : */
18 :
19 : #include "mobileip.h"
20 :
21 : #include "bpfilter.h"
22 : #include "pf.h"
23 :
24 : #include <sys/param.h>
25 : #include <sys/mbuf.h>
26 : #include <sys/socket.h>
27 : #include <sys/sockio.h>
28 : #include <sys/kernel.h>
29 : #include <sys/systm.h>
30 : #include <sys/timeout.h>
31 : #include <sys/queue.h>
32 :
33 : #include <net/if.h>
34 : #include <net/if_types.h>
35 : #include <net/if_var.h>
36 : #include <net/route.h>
37 :
38 : #include <netinet/in.h>
39 : #include <netinet/ip.h>
40 : #include <netinet/ip_var.h>
41 :
42 : #if NBPFILTER > 0
43 : #include <net/bpf.h>
44 : #endif
45 :
46 : #if NPF > 0
47 : #include <net/pfvar.h>
48 : #endif
49 :
50 : #include <net/if_mobileip.h>
51 :
52 : struct mobileip_tunnel {
53 : unsigned int t_rtableid;
54 : struct in_addr t_src;
55 : struct in_addr t_dst;
56 :
57 : TAILQ_ENTRY(mobileip_tunnel)
58 : t_entry;
59 : };
60 :
61 : TAILQ_HEAD(mobileip_list, mobileip_tunnel);
62 :
63 : struct mobileip_softc {
64 : struct mobileip_tunnel sc_tunnel;
65 : struct ifnet sc_if;
66 : };
67 :
68 : static int mobileip_clone_create(struct if_clone *, int);
69 : static int mobileip_clone_destroy(struct ifnet *);
70 :
71 : static struct if_clone mobileip_cloner = IF_CLONE_INITIALIZER("mobileip",
72 : mobileip_clone_create, mobileip_clone_destroy);
73 :
74 : static inline int
75 : mobileip_cmp(const struct mobileip_tunnel *,
76 : const struct mobileip_tunnel *);
77 :
78 : struct mobileip_list mobileip_list = TAILQ_HEAD_INITIALIZER(mobileip_list);
79 :
80 : #define MOBILEIPMTU (1500 - (sizeof(struct mobileip_header) + \
81 : sizeof(struct mobileip_h_src))) \
82 :
83 : static int mobileip_ioctl(struct ifnet *, u_long, caddr_t);
84 : static int mobileip_up(struct mobileip_softc *);
85 : static int mobileip_down(struct mobileip_softc *);
86 : static int mobileip_set_tunnel(struct mobileip_softc *,
87 : struct if_laddrreq *);
88 : static int mobileip_get_tunnel(struct mobileip_softc *,
89 : struct if_laddrreq *);
90 : static int mobileip_del_tunnel(struct mobileip_softc *);
91 :
92 : static int mobileip_output(struct ifnet *, struct mbuf *,
93 : struct sockaddr *, struct rtentry *);
94 : static void mobileip_start(struct ifnet *);
95 : static int mobileip_encap(struct mobileip_softc *, struct mbuf *);
96 : static struct mobileip_softc *
97 : mobileip_find(const struct mobileip_tunnel *);
98 :
99 : /*
100 : * let's begin
101 : */
102 :
103 : int mobileip_allow = 0;
104 :
105 : void
106 0 : mobileipattach(int n)
107 : {
108 0 : if_clone_attach(&mobileip_cloner);
109 0 : }
110 :
111 : int
112 0 : mobileip_clone_create(struct if_clone *ifc, int unit)
113 : {
114 : struct mobileip_softc *sc;
115 :
116 0 : sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT|M_ZERO);
117 0 : if (!sc)
118 0 : return (ENOMEM);
119 :
120 0 : sc->sc_tunnel.t_rtableid = 0;
121 0 : sc->sc_tunnel.t_src.s_addr = INADDR_ANY;
122 0 : sc->sc_tunnel.t_dst.s_addr = INADDR_ANY;
123 :
124 0 : snprintf(sc->sc_if.if_xname, sizeof sc->sc_if.if_xname, "%s%d",
125 0 : ifc->ifc_name, unit);
126 0 : sc->sc_if.if_softc = sc;
127 0 : sc->sc_if.if_type = IFT_TUNNEL;
128 0 : sc->sc_if.if_addrlen = 0;
129 0 : sc->sc_if.if_mtu = MOBILEIPMTU;
130 0 : sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
131 0 : sc->sc_if.if_output = mobileip_output;
132 0 : sc->sc_if.if_start = mobileip_start;
133 0 : sc->sc_if.if_ioctl = mobileip_ioctl;
134 0 : sc->sc_if.if_rtrequest = p2p_rtrequest;
135 :
136 0 : if_attach(&sc->sc_if);
137 0 : if_alloc_sadl(&sc->sc_if);
138 :
139 : #if NBPFILTER > 0
140 0 : bpfattach(&sc->sc_if.if_bpf, &sc->sc_if, DLT_LOOP, sizeof(uint32_t));
141 : #endif
142 :
143 0 : NET_LOCK();
144 0 : TAILQ_INSERT_TAIL(&mobileip_list, &sc->sc_tunnel, t_entry);
145 0 : NET_UNLOCK();
146 :
147 0 : return (0);
148 0 : }
149 :
150 : int
151 0 : mobileip_clone_destroy(struct ifnet *ifp)
152 : {
153 0 : struct mobileip_softc *sc = ifp->if_softc;
154 :
155 0 : if_detach(ifp);
156 :
157 0 : NET_LOCK();
158 0 : if (ISSET(ifp->if_flags, IFF_RUNNING))
159 0 : mobileip_down(sc);
160 :
161 0 : TAILQ_REMOVE(&mobileip_list, &sc->sc_tunnel, t_entry);
162 0 : NET_UNLOCK();
163 :
164 0 : free(sc, M_DEVBUF, sizeof(*sc));
165 :
166 0 : return (0);
167 : }
168 :
169 : /*
170 : * do a checksum of a header.
171 : *
172 : * assumes len is aligned correctly, and not an odd number of bytes.
173 : */
174 : static inline uint16_t
175 0 : mobileip_cksum(const void *buf, size_t len)
176 : {
177 0 : const uint16_t *p = buf;
178 : uint32_t sum = 0;
179 :
180 0 : do {
181 0 : sum += bemtoh16(p++);
182 0 : } while (len -= 2);
183 :
184 : /* end-around-carry */
185 0 : sum = (sum >> 16) + (sum & 0xffff);
186 0 : sum += (sum >> 16);
187 0 : return (~sum);
188 : }
189 :
190 : static inline int
191 0 : mobileip_cmp(const struct mobileip_tunnel *a, const struct mobileip_tunnel *b)
192 : {
193 0 : if (a->t_src.s_addr > b->t_src.s_addr)
194 0 : return (1);
195 0 : if (a->t_src.s_addr < b->t_src.s_addr)
196 0 : return (-1);
197 :
198 0 : if (a->t_dst.s_addr > b->t_dst.s_addr)
199 0 : return (1);
200 0 : if (a->t_dst.s_addr < b->t_dst.s_addr)
201 0 : return (-1);
202 :
203 0 : if (a->t_rtableid > b->t_rtableid)
204 0 : return (1);
205 0 : if (a->t_rtableid < b->t_rtableid)
206 0 : return (-1);
207 :
208 0 : return (0);
209 0 : }
210 :
211 : static int
212 0 : mobileip_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
213 : struct rtentry *rt)
214 : {
215 : struct m_tag *mtag;
216 : int error = 0;
217 :
218 0 : if (!mobileip_allow) {
219 0 : m_freem(m);
220 : error = EACCES;
221 0 : goto end;
222 : }
223 :
224 0 : if (!ISSET(ifp->if_flags, IFF_RUNNING)) {
225 0 : m_freem(m);
226 : error = ENETDOWN;
227 0 : goto end;
228 : }
229 :
230 0 : if (dst->sa_family != AF_INET) {
231 0 : m_freem(m);
232 : error = EAFNOSUPPORT;
233 0 : goto end;
234 : }
235 :
236 : /* Try to limit infinite recursion through misconfiguration. */
237 0 : for (mtag = m_tag_find(m, PACKET_TAG_GRE, NULL); mtag;
238 0 : mtag = m_tag_find(m, PACKET_TAG_GRE, mtag)) {
239 0 : if (memcmp(mtag + 1, &ifp->if_index,
240 0 : sizeof(ifp->if_index)) == 0) {
241 0 : m_freem(m);
242 : error = EIO;
243 0 : goto end;
244 : }
245 : }
246 :
247 0 : mtag = m_tag_get(PACKET_TAG_GRE, sizeof(ifp->if_index), M_NOWAIT);
248 0 : if (mtag == NULL) {
249 0 : m_freem(m);
250 : error = ENOBUFS;
251 0 : goto end;
252 : }
253 0 : memcpy(mtag + 1, &ifp->if_index, sizeof(ifp->if_index));
254 0 : m_tag_prepend(m, mtag);
255 :
256 0 : error = if_enqueue(ifp, m);
257 : end:
258 0 : if (error)
259 0 : ifp->if_oerrors++;
260 0 : return (error);
261 : }
262 :
263 : static void
264 0 : mobileip_start(struct ifnet *ifp)
265 : {
266 0 : struct mobileip_softc *sc = ifp->if_softc;
267 : struct mbuf *m;
268 :
269 0 : while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) {
270 : #if NBPFILTER > 0
271 0 : if (ifp->if_bpf)
272 0 : bpf_mtap_af(ifp->if_bpf, AF_INET, m, BPF_DIRECTION_OUT);
273 : #endif
274 :
275 0 : if (mobileip_encap(sc, m) != 0)
276 0 : ifp->if_oerrors++;
277 : }
278 0 : }
279 :
280 : static int
281 0 : mobileip_encap(struct mobileip_softc *sc, struct mbuf *m)
282 : {
283 : struct ip *ip;
284 0 : struct mobileip_tunnel *tunnel = &sc->sc_tunnel;
285 : struct mobileip_header *mh;
286 : struct mobileip_h_src *msh;
287 : caddr_t hdr;
288 : int iphlen, hlen;
289 :
290 : /* look at the current IP header */
291 0 : m = m_pullup(m, sizeof(*ip));
292 0 : if (m == NULL)
293 0 : return (ENOBUFS);
294 :
295 : /* figure out how long it is */
296 0 : ip = mtod(m, struct ip *);
297 0 : iphlen = ip->ip_hl << 2;
298 :
299 : /* figure out how much extra space we'll need */
300 : hlen = sizeof(*mh);
301 0 : if (ip->ip_src.s_addr != tunnel->t_src.s_addr)
302 0 : hlen += sizeof(*msh);
303 :
304 : /* add the space */
305 0 : m = m_prepend(m, hlen, M_DONTWAIT);
306 0 : if (m == NULL)
307 0 : return (ENOBUFS);
308 :
309 : /* make the IP and mobileip headers contig */
310 0 : m = m_pullup(m, iphlen + hlen);
311 0 : if (m == NULL)
312 0 : return (ENOBUFS);
313 :
314 : /* move the IP header to the front */
315 0 : hdr = mtod(m, caddr_t);
316 0 : memmove(hdr, hdr + hlen, iphlen);
317 :
318 : /* fill in the headers */
319 0 : ip = (struct ip *)hdr;
320 0 : mh = (struct mobileip_header *)(hdr + iphlen);
321 0 : mh->mip_proto = ip->ip_p;
322 0 : mh->mip_flags = 0;
323 0 : mh->mip_hcrc = 0;
324 0 : mh->mip_dst = ip->ip_dst.s_addr;
325 :
326 0 : if (ip->ip_src.s_addr != tunnel->t_src.s_addr) {
327 0 : mh->mip_flags |= MOBILEIP_SP;
328 :
329 0 : msh = (struct mobileip_h_src *)(mh + 1);
330 0 : msh->mip_src = ip->ip_src.s_addr;
331 :
332 0 : ip->ip_src.s_addr = tunnel->t_src.s_addr;
333 0 : }
334 :
335 0 : htobem16(&mh->mip_hcrc, mobileip_cksum(mh, hlen));
336 :
337 0 : ip->ip_p = IPPROTO_MOBILE;
338 0 : htobem16(&ip->ip_len, bemtoh16(&ip->ip_len) + hlen);
339 0 : ip->ip_dst = tunnel->t_dst;
340 :
341 0 : m->m_flags &= ~(M_BCAST|M_MCAST);
342 0 : m->m_pkthdr.ph_rtableid = tunnel->t_rtableid;
343 :
344 : #if NPF > 0
345 0 : pf_pkt_addr_changed(m);
346 : #endif
347 :
348 0 : ip_send(m);
349 :
350 0 : return (0);
351 0 : }
352 :
353 : int
354 0 : mobileip_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
355 : {
356 0 : struct mobileip_softc *sc = ifp->if_softc;
357 0 : struct ifreq *ifr = (struct ifreq *)data;
358 0 : struct ifaddr *ifa = (struct ifaddr *)data;
359 : int error = 0;
360 :
361 0 : switch(cmd) {
362 : case SIOCSIFADDR:
363 0 : if (ifa->ifa_addr->sa_family != AF_INET) {
364 : error = EAFNOSUPPORT;
365 0 : break;
366 : }
367 :
368 0 : ifp->if_flags |= IFF_UP;
369 : /* FALLTHROUGH */
370 : case SIOCSIFFLAGS:
371 0 : if (ISSET(ifp->if_flags, IFF_UP)) {
372 0 : if (!ISSET(ifp->if_flags, IFF_RUNNING))
373 0 : error = mobileip_up(sc);
374 : else
375 : error = 0;
376 : } else {
377 0 : if (ISSET(ifp->if_flags, IFF_RUNNING))
378 0 : error = mobileip_down(sc);
379 : }
380 : break;
381 : case SIOCSIFDSTADDR:
382 : break;
383 : case SIOCSIFMTU:
384 0 : if (ifr->ifr_mtu < 576) {
385 : error = EINVAL;
386 0 : break;
387 : }
388 0 : ifp->if_mtu = ifr->ifr_mtu;
389 0 : break;
390 : case SIOCGIFMTU:
391 0 : ifr->ifr_mtu = sc->sc_if.if_mtu;
392 0 : break;
393 : case SIOCADDMULTI:
394 : case SIOCDELMULTI:
395 : break;
396 :
397 : case SIOCSLIFPHYADDR:
398 0 : error = mobileip_set_tunnel(sc, (struct if_laddrreq *)data);
399 0 : break;
400 : case SIOCGLIFPHYADDR:
401 0 : error = mobileip_get_tunnel(sc, (struct if_laddrreq *)data);
402 0 : break;
403 : case SIOCDIFPHYADDR:
404 0 : error = mobileip_del_tunnel(sc);
405 0 : break;
406 :
407 : case SIOCGLIFPHYTTL:
408 0 : ifr->ifr_ttl = -1;
409 0 : break;
410 :
411 : case SIOCSLIFPHYRTABLE:
412 0 : if (ifr->ifr_rdomainid < 0 ||
413 0 : ifr->ifr_rdomainid > RT_TABLEID_MAX ||
414 0 : !rtable_exists(ifr->ifr_rdomainid)) {
415 : error = EINVAL;
416 0 : break;
417 : }
418 0 : sc->sc_tunnel.t_rtableid = ifr->ifr_rdomainid;
419 0 : break;
420 : case SIOCGLIFPHYRTABLE:
421 0 : ifr->ifr_rdomainid = sc->sc_tunnel.t_rtableid;
422 0 : break;
423 :
424 : default:
425 : error = ENOTTY;
426 0 : break;
427 : }
428 :
429 0 : return (error);
430 : }
431 :
432 : static int
433 0 : mobileip_up(struct mobileip_softc *sc)
434 : {
435 0 : NET_ASSERT_LOCKED();
436 :
437 0 : SET(sc->sc_if.if_flags, IFF_RUNNING);
438 :
439 0 : return (0);
440 : }
441 :
442 : static int
443 0 : mobileip_down(struct mobileip_softc *sc)
444 : {
445 0 : NET_ASSERT_LOCKED();
446 :
447 0 : CLR(sc->sc_if.if_flags, IFF_RUNNING);
448 :
449 0 : ifq_barrier(&sc->sc_if.if_snd);
450 :
451 0 : return (0);
452 : }
453 :
454 : static int
455 0 : mobileip_set_tunnel(struct mobileip_softc *sc, struct if_laddrreq *req)
456 : {
457 0 : struct sockaddr_in *src = (struct sockaddr_in *)&req->addr;
458 0 : struct sockaddr_in *dst = (struct sockaddr_in *)&req->dstaddr;
459 :
460 : /* sa_family and sa_len must be equal */
461 0 : if (src->sin_family != dst->sin_family || src->sin_len != dst->sin_len)
462 0 : return (EINVAL);
463 :
464 0 : if (dst->sin_family != AF_INET)
465 0 : return (EAFNOSUPPORT);
466 0 : if (dst->sin_len != sizeof(*dst))
467 0 : return (EINVAL);
468 :
469 0 : if (in_nullhost(src->sin_addr) ||
470 0 : IN_MULTICAST(src->sin_addr.s_addr) ||
471 0 : in_nullhost(dst->sin_addr) ||
472 0 : IN_MULTICAST(dst->sin_addr.s_addr))
473 0 : return (EINVAL);
474 :
475 : /* commit */
476 0 : sc->sc_tunnel.t_src = src->sin_addr;
477 0 : sc->sc_tunnel.t_dst = dst->sin_addr;
478 :
479 0 : return (0);
480 0 : }
481 :
482 : static int
483 0 : mobileip_get_tunnel(struct mobileip_softc *sc, struct if_laddrreq *req)
484 : {
485 0 : struct sockaddr_in *src = (struct sockaddr_in *)&req->addr;
486 0 : struct sockaddr_in *dst = (struct sockaddr_in *)&req->dstaddr;
487 :
488 0 : if (sc->sc_tunnel.t_dst.s_addr == INADDR_ANY)
489 0 : return (EADDRNOTAVAIL);
490 :
491 0 : memset(src, 0, sizeof(*src));
492 0 : src->sin_family = AF_INET;
493 0 : src->sin_len = sizeof(*src);
494 0 : src->sin_addr = sc->sc_tunnel.t_src;
495 :
496 0 : memset(dst, 0, sizeof(*dst));
497 0 : dst->sin_family = AF_INET;
498 0 : dst->sin_len = sizeof(*dst);
499 0 : dst->sin_addr = sc->sc_tunnel.t_dst;
500 :
501 0 : return (0);
502 0 : }
503 :
504 : static int
505 0 : mobileip_del_tunnel(struct mobileip_softc *sc)
506 : {
507 : /* commit */
508 0 : sc->sc_tunnel.t_src.s_addr = INADDR_ANY;
509 0 : sc->sc_tunnel.t_dst.s_addr = INADDR_ANY;
510 :
511 0 : return (0);
512 : }
513 :
514 : static struct mobileip_softc *
515 0 : mobileip_find(const struct mobileip_tunnel *key)
516 : {
517 : struct mobileip_tunnel *t;
518 : struct mobileip_softc *sc;
519 :
520 0 : TAILQ_FOREACH(t, &mobileip_list, t_entry) {
521 0 : if (mobileip_cmp(key, t) != 0)
522 : continue;
523 :
524 0 : sc = (struct mobileip_softc *)t;
525 0 : if (!ISSET(sc->sc_if.if_flags, IFF_RUNNING))
526 : continue;
527 :
528 0 : return (sc);
529 : }
530 :
531 0 : return (NULL);
532 0 : }
533 :
534 : int
535 0 : mobileip_input(struct mbuf **mp, int *offp, int type, int af)
536 : {
537 0 : struct mobileip_tunnel key;
538 0 : struct mbuf *m = *mp;
539 : struct ifnet *ifp;
540 : struct mobileip_softc *sc;
541 : caddr_t hdr;
542 : struct ip *ip;
543 : struct mobileip_header *mh;
544 : struct mobileip_h_src *msh;
545 : int iphlen = 0;
546 : int hlen;
547 :
548 0 : if (!mobileip_allow)
549 : goto drop;
550 :
551 0 : ip = mtod(m, struct ip *);
552 :
553 0 : key.t_rtableid = m->m_pkthdr.ph_rtableid;
554 0 : key.t_src = ip->ip_dst;
555 0 : key.t_dst = ip->ip_src;
556 :
557 : /* NET_ASSERT_READ_LOCKED() */
558 0 : sc = mobileip_find(&key);
559 0 : if (sc == NULL)
560 : goto drop;
561 :
562 : /* it's ours now, we can do what we want */
563 :
564 0 : iphlen = ip->ip_hl << 2;
565 : hlen = sizeof(*mh);
566 0 : m = m_pullup(m, iphlen + hlen);
567 0 : if (m == NULL)
568 0 : return (IPPROTO_DONE);
569 :
570 0 : hdr = mtod(m, caddr_t);
571 0 : ip = (struct ip *)hdr;
572 0 : mh = (struct mobileip_header *)(hdr + iphlen);
573 :
574 0 : if (mh->mip_flags & ~MOBILEIP_SP)
575 : goto drop;
576 :
577 0 : if (ISSET(mh->mip_flags, MOBILEIP_SP)) {
578 : hlen += sizeof(*msh);
579 0 : m = m_pullup(m, iphlen + hlen);
580 0 : if (m == NULL)
581 0 : return (IPPROTO_DONE);
582 :
583 0 : hdr = mtod(m, caddr_t);
584 0 : ip = (struct ip *)hdr;
585 0 : mh = (struct mobileip_header *)(hdr + iphlen);
586 0 : msh = (struct mobileip_h_src *)(mh + 1);
587 :
588 0 : ip->ip_src.s_addr = msh->mip_src;
589 0 : }
590 :
591 0 : if (mobileip_cksum(mh, hlen) != 0)
592 : goto drop;
593 :
594 0 : ip->ip_p = mh->mip_proto;
595 0 : htobem16(&ip->ip_len, bemtoh16(&ip->ip_len) - hlen);
596 0 : ip->ip_dst.s_addr = mh->mip_dst;
597 :
598 0 : memmove(hdr + hlen, hdr, iphlen);
599 0 : m_adj(m, hlen);
600 :
601 0 : ifp = &sc->sc_if;
602 :
603 0 : CLR(m->m_flags, M_MCAST|M_BCAST);
604 0 : SET(m->m_pkthdr.csum_flags, M_IPV4_CSUM_IN_OK);
605 0 : m->m_pkthdr.ph_ifidx = ifp->if_index;
606 0 : m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
607 :
608 : #if NPF > 0
609 0 : pf_pkt_addr_changed(m);
610 : #endif
611 :
612 0 : ifp->if_ipackets++;
613 0 : ifp->if_ibytes += m->m_pkthdr.len;
614 :
615 : #if NBPFILTER > 0
616 0 : if (ifp->if_bpf)
617 0 : bpf_mtap_af(ifp->if_bpf, AF_INET, m, BPF_DIRECTION_IN);
618 : #endif
619 :
620 0 : ipv4_input(ifp, m);
621 :
622 0 : return (IPPROTO_DONE);
623 :
624 : drop:
625 0 : m_freem(m);
626 0 : return (IPPROTO_DONE);
627 0 : }
628 :
629 : #include <sys/sysctl.h>
630 : #include <netinet/ip_gre.h>
631 :
632 : int
633 0 : mobileip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
634 : void *newp, size_t newlen)
635 : {
636 0 : int allow;
637 : int error;
638 :
639 : /* All sysctl names at this level are terminal. */
640 0 : if (namelen != 1)
641 0 : return (ENOTDIR);
642 :
643 0 : switch (name[0]) {
644 : case MOBILEIPCTL_ALLOW:
645 0 : allow = mobileip_allow;
646 :
647 0 : error = sysctl_int(oldp, oldlenp, newp, newlen,
648 : &allow);
649 0 : if (error != 0)
650 0 : return (error);
651 :
652 0 : mobileip_allow = allow;
653 : break;
654 : default:
655 0 : return (ENOPROTOOPT);
656 : }
657 :
658 0 : return (0);
659 0 : }
|