1 /* $NetBSD: if_srt.c,v 1.11 2009/03/18 16:00:22 cegger Exp $ */
2 /* This file is in the public domain. */
5 __KERNEL_RCSID(0, "$NetBSD: if_srt.c,v 1.11 2009/03/18 16:00:22 cegger Exp $");
9 #if !defined(INET) && !defined(INET6)
10 #error "srt without INET/INET6?"
14 #define SRT_MAXUNIT 255
17 /* include-file bug workarounds */
18 #include <sys/types.h> /* sys/conf.h */
19 #include <sys/resource.h> /* sys/resourcevar.h
20 * (uvm/uvm_param.h, sys/mbuf.h)
22 #include <netinet/in.h> /* netinet/ip.h */
23 #include <sys/param.h> /* sys/mbuf.h */
24 #include <netinet/in_systm.h> /* netinet/ip.h */
28 #include <sys/errno.h>
29 #include <sys/fcntl.h>
30 #include <sys/param.h>
31 #include <sys/ioctl.h>
32 #include <netinet/ip.h>
33 #include <netinet/ip6.h>
34 #include <net/if_types.h>
35 #include <machine/stdarg.h>
40 /* until we know what to pass to bpfattach.... */
45 struct ifnet intf
; /* XXX interface botch */
49 unsigned int flags
; /* SSF_* values from if_srt.h */
50 #define SSF_UCHG (SSF_MTULOCK) /* userland-changeable bits */
51 unsigned int kflags
; /* bits private to this file */
52 #define SKF_CDEVOPEN 0x00000001
57 static struct srt_softc
*softcv
[SRT_MAXUNIT
+1];
58 static unsigned int global_flags
;
60 /* Internal routines. */
62 static unsigned int ipv4_masks
[33] = {
64 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, /* /1 - /4 */
65 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000, /* /5 - /8 */
66 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, /* /9 - /12 */
67 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, /* /13 - /16 */
68 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, /* /17 - /20 */
69 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00, /* /21 - /24 */
70 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, /* /25 - /28 */
71 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff /* /29 - /32 */
75 update_mtu(struct srt_softc
*sc
)
81 if (sc
->flags
& SSF_MTULOCK
)
84 for (i
=sc
->nrt
-1;i
>=0;i
--) {
86 if (r
->u
.dstifp
->if_mtu
< mtu
)
87 mtu
= r
->u
.dstifp
->if_mtu
;
89 sc
->intf
.if_mtu
= mtu
;
92 static struct srt_rt
*
93 find_rt(struct srt_softc
*sc
, int af
, ...)
101 ia
.s_addr
= 0; ia6
.s6_addr
[0] = 0; /* shut up incorrect -Wuninitialized */
105 ia
= va_arg(ap
,struct in_addr
);
108 ia6
= va_arg(ap
,struct in6_addr
);
111 panic("if_srt find_rt: impossible address family");
115 for (i
=0;i
<sc
->nrt
;i
++) {
121 if ((ia
.s_addr
& ipv4_masks
[r
->srcmask
]) ==
122 r
->srcmatch
.v4
.s_addr
)
126 if ((r
->srcmask
>= 8) &&
127 memcmp(&ia6
,&r
->srcmatch
.v6
,r
->srcmask
/ 8) != 0)
129 if ((r
->srcmask
% 8) &&
130 ((ia6
.s6_addr
[r
->srcmask
/ 8] ^
131 r
->srcmatch
.v6
.s6_addr
[r
->srcmask
/ 8]) &
132 0xff & (0xff00 >> (r
->srcmask
% 8))))
136 panic("if_srt find_rt: impossible address family 2");
143 /* Network device interface. */
146 srt_if_ioctl(struct ifnet
*ifp
, u_long cmd
, void *data
)
158 switch (ifa
->ifa_addr
->sa_family
) {
171 /* XXX do we need to do more here for either of these? */
174 if ((err
= ifioctl_common(ifp
, cmd
, data
)) == ENETRESET
)
186 const struct sockaddr
*to
,
189 struct srt_softc
*sc
;
193 if (! (ifp
->if_flags
& IFF_UP
)) {
197 switch (to
->sa_family
) {
201 ip
= mtod(m
,struct ip
*);
202 r
= find_rt(sc
,AF_INET
,ip
->ip_src
);
209 ip
= mtod(m
,struct ip6_hdr
*);
210 r
= find_rt(sc
,AF_INET6
,ip
->ip6_src
);
215 IF_DROP(&ifp
->if_snd
);
219 /* XXX Do we need to bpf_tap? Or do higher layers now handle that? */
220 /* if_gif.c seems to imply the latter. */
227 if (! (m
->m_flags
& M_PKTHDR
)) {
228 printf("srt_if_output no PKTHDR\n");
232 ifp
->if_obytes
+= m
->m_pkthdr
.len
;
233 if (! (r
->u
.dstifp
->if_flags
& IFF_UP
)) {
235 return 0; /* XXX ENETDOWN? */
237 /* XXX is 0 the right last arg here? */
238 return (*r
->u
.dstifp
->if_output
)(r
->u
.dstifp
,m
,&r
->dst
.sa
,0);
242 srt_clone_create(struct if_clone
*cl
, int unit
)
244 struct srt_softc
*sc
;
246 if (unit
< 0 || unit
> SRT_MAXUNIT
)
250 sc
= malloc(sizeof(struct srt_softc
), M_DEVBUF
, M_WAITOK
|M_ZERO
);
256 if_initname(&sc
->intf
,cl
->ifc_name
,unit
);
257 sc
->intf
.if_softc
= sc
;
258 sc
->intf
.if_mtu
= 65535;
259 sc
->intf
.if_flags
= IFF_POINTOPOINT
;
260 sc
->intf
.if_type
= IFT_OTHER
;
261 sc
->intf
.if_ioctl
= &srt_if_ioctl
;
262 sc
->intf
.if_output
= &srt_if_output
;
263 sc
->intf
.if_dlt
= DLT_RAW
;
264 if_attach(&sc
->intf
);
265 if_alloc_sadl(&sc
->intf
);
266 #if NBPFILTER > 0 /* see comment near top */
267 bpfattach(&sc
->intf
,0/*???*/,0/*???*/);
274 srt_clone_destroy(struct ifnet
*ifp
)
276 struct srt_softc
*sc
;
279 if ((ifp
->if_flags
& IFF_UP
) || (sc
->kflags
& SKF_CDEVOPEN
))
285 if (sc
->unit
< 0 || sc
->unit
> SRT_MAXUNIT
) {
286 panic("srt_clone_destroy: impossible unit %d\n",sc
->unit
);
288 if (softcv
[sc
->unit
] != sc
) {
289 panic("srt_clone_destroy: bad backpointer ([%d]=%p not %p)\n",
290 sc
->unit
,(void *)softcv
[sc
->unit
],(void *)sc
);
292 softcv
[sc
->unit
] = 0;
297 struct if_clone srt_clone
=
298 IF_CLONE_INITIALIZER("srt",&srt_clone_create
,&srt_clone_destroy
);
305 for (i
=SRT_MAXUNIT
;i
>=0;i
--)
308 if_clone_attach(&srt_clone
);
311 /* Special-device interface. */
314 srt_open(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
317 struct srt_softc
*sc
;
320 if (unit
< 0 || unit
> SRT_MAXUNIT
)
325 sc
->kflags
|= SKF_CDEVOPEN
;
330 srt_close(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
333 struct srt_softc
*sc
;
336 if (unit
< 0 || unit
> SRT_MAXUNIT
)
341 sc
->kflags
&= ~SKF_CDEVOPEN
;
346 srt_ioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
348 unsigned int f
, i
, n
, o
;
349 struct srt_softc
*sc
;
355 sc
= softcv
[minor(dev
)];
357 panic("srt_ioctl: softc disappeared");
360 if (! (flag
& FREAD
))
362 *(unsigned int *)data
= sc
->nrt
;
365 if (! (flag
& FREAD
))
367 dr
= (struct srt_rt
*) data
;
368 if (dr
->inx
>= sc
->nrt
)
370 scr
= sc
->rts
[dr
->inx
];
372 dr
->srcmatch
= scr
->srcmatch
;
373 dr
->srcmask
= scr
->srcmask
;
374 strncpy(&dr
->u
.dstifn
[0],&scr
->u
.dstifp
->if_xname
[0],IFNAMSIZ
);
375 memcpy(&dr
->dst
,&scr
->dst
,scr
->dst
.sa
.sa_len
);
378 if (! (flag
& FWRITE
))
380 dr
= (struct srt_rt
*) data
;
381 if (dr
->inx
> sc
->nrt
)
383 strncpy(&nbuf
[0],&dr
->u
.dstifn
[0],IFNAMSIZ
);
384 nbuf
[IFNAMSIZ
-1] = '\0';
385 if (dr
->dst
.sa
.sa_family
!= dr
->af
)
390 if (dr
->dst
.sa
.sa_len
!= sizeof(dr
->dst
.sin
))
392 if (dr
->srcmask
> 32)
398 if (dr
->dst
.sa
.sa_len
!= sizeof(dr
->dst
.sin6
))
400 if (dr
->srcmask
> 128)
407 ifp
= ifunit(&nbuf
[0]);
409 return ENXIO
; /* needs translation */
410 if (dr
->inx
== sc
->nrt
) {
412 tmp
= malloc((sc
->nrt
+1)*sizeof(*tmp
), M_DEVBUF
,
418 memcpy(tmp
, sc
->rts
, sc
->nrt
*sizeof(*tmp
));
419 free(sc
->rts
, M_DEVBUF
);
424 scr
= sc
->rts
[dr
->inx
];
426 scr
= malloc(sizeof(struct srt_rt
),M_DEVBUF
,M_WAITOK
);
431 sc
->rts
[dr
->inx
] = scr
;
434 scr
->srcmatch
= dr
->srcmatch
;
435 scr
->srcmask
= dr
->srcmask
;
437 memcpy(&scr
->dst
,&dr
->dst
,dr
->dst
.sa
.sa_len
);
441 if (! (flag
& FWRITE
))
443 i
= *(unsigned int *)data
;
451 memcpy(sc
->rts
+i
, sc
->rts
+i
+1,
452 (sc
->nrt
-i
)*sizeof(*sc
->rts
));
455 free(sc
->rts
, M_DEVBUF
);
457 sc
->intf
.if_flags
&= ~IFF_UP
;
462 if (! (flag
& FWRITE
))
464 f
= *(unsigned int *)data
& SSF_UCHG
;
465 global_flags
= (global_flags
& ~SSF_UCHG
) | (f
& SSF_GLOBAL
);
466 sc
->flags
= (sc
->flags
& ~SSF_UCHG
) | (f
& ~SSF_GLOBAL
);
469 if (! (flag
& FREAD
))
471 *(unsigned int *)data
= sc
->flags
| global_flags
;
474 if ((flag
& (FWRITE
|FREAD
)) != (FWRITE
|FREAD
))
476 o
= sc
->flags
| global_flags
;
477 n
= *(unsigned int *)data
& SSF_UCHG
;
478 global_flags
= (global_flags
& ~SSF_UCHG
) | (n
& SSF_GLOBAL
);
479 sc
->flags
= (sc
->flags
& ~SSF_UCHG
) | (n
& ~SSF_GLOBAL
);
480 *(unsigned int *)data
= o
;
489 const struct cdevsw srt_cdevsw
= {