tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: working example setup for source-based routing with ipfilter?
>> NetBSD's version is missing a change that makes it cooperate with
>> "keep state" style firewalling (eg, most NAT setups), but that is
>> unlikely to matter for v6. However, it may be effectively
>> unmaintained; it doesn't seem to have real locking calls in it, and
>> might not work right on little-endian machines - comparing it
>> against my version I see an ntohl which I think I added when I
>> started using it on i386 (for most of its existence I was using it
>> on sparc).
> Oh. Where is that ntohl ? Would you create a patch, please?
Here are diffs between the if_srt.c in the 5.1 source tarballs and the
version I'm using on 4.0.1. (This seems a little backward, but looking
at the diffs I think this may be the more useful way.) These are the
full diffs, in case you want (eg) the locking changes I mentioned -
-current may have proper locking, but in case not this may help.
There are actually two ntohls, which you can find by searching for
ntohl in this patch; one is in the hunk beginning @@ -91,12 +98,20 @@,
the other, @@ -407,8 +574,16 @@.
The change that makes it play nice with NAT is the call to
pfil_run_hooks and the following code inside PFIL_HOOKS; the containing
hunk is large, so you might be better off searching for pfil_run_hooks.
(If you really want, the hunk begins @@ -152,193 +182,323 @@.)
Hm, the explicit copyright status comments seem to have got lost in my
version. I wonder how that happened. I'll add them back. Just to be
totally clear on the point: any copyright interest I may have in these
diffs I hereby release into the public domain.
/~\ The ASCII Mouse
\ / Ribbon Campaign
X Against HTML mouse%rodents-montreal.org@localhost
/ \ Email! 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B
--- if_srt.c 2011-07-13 11:13:37.000000000 -0400
+++ /usr/src/sys/net/if_srt.c 2011-06-29 21:51:05.000000000 -0400
@@ -1,62 +1,69 @@
-/* $NetBSD: if_srt.c,v 1.8 2008/06/15 16:37:21 christos Exp $ */
-/* This file is in the public domain. */
-
-#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_srt.c,v 1.8 2008/06/15 16:37:21 christos Exp
$");
-
#include "opt_inet.h"
+#include "opt_pfil_hooks.h"
#if !defined(INET) && !defined(INET6)
-#error "srt without INET/INET6?"
+#error "srt with neither INET nor INET6"
#endif
#ifndef SRT_MAXUNIT
#define SRT_MAXUNIT 255
#endif
-/* include-file bug workarounds */
-#include <sys/types.h> /* sys/conf.h */
-#include <sys/resource.h> /* sys/resourcevar.h (uvm/uvm_param.h, sys/mbuf.h) */
-#include <netinet/in.h> /* netinet/ip.h */
-#include <sys/param.h> /* sys/mbuf.h */
-#include <netinet/in_systm.h> /* netinet/ip.h */
-
-#include <sys/conf.h>
+#include <net/if.h>
+#include <net/bpf.h>
+#include <sys/lock.h>
#include <sys/mbuf.h>
+#include <sys/conf.h>
#include <sys/errno.h>
+#include <sys/event.h>
#include <sys/fcntl.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/malloc.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <net/if_types.h>
+#include <machine/intr.h>
#include <machine/stdarg.h>
#include "if_srt.h"
#include "bpfilter.h"
+#include "opt_altq_enabled.h"
-/* until we know what to pass to bpfattach.... */
-#undef NBPFILTER
-#define NBPFILTER 0
+#ifdef PFIL_HOOKS
+/* XXX, but this is how ip_output.c does it... */
+extern struct pfil_head inet_pfil_hook;
+#endif
-typedef struct srt_rt RT;
typedef struct softc SOFTC;
+typedef struct srt_rt RT;
struct softc {
- struct ifnet intf; /* XXX interface botch */
+ struct ifnet intf;
+ struct simplelock lock;
int unit;
int nrt;
RT **rts;
- unsigned int flags; /* SSF_* values from if_srt.h */
+ unsigned int flags; /* SSF_* values from if_srt.h */
#define SSF_UCHG (SSF_MTULOCK) /* userland-changeable bits */
- unsigned int kflags; /* bits private to this file */
+ unsigned int kflags; /* internal */
#define SKF_CDEVOPEN 0x00000001
} ;
+/* Lock nesting:
+ softcv_lock
+ SOFTC locks
+ gblf_lock
+ That is, for example, never take softcv_lock when holding either a
+ SOFTC's lock or gblf_lock.
+ */
+static struct simplelock softcv_lock;
static SOFTC *softcv[SRT_MAXUNIT+1];
+static struct simplelock gblf_lock;
static unsigned int global_flags;
-/* Internal routines. */
+#define SRT_DEFMTU 1500
+#define SRT_MAXMTU 9000
static unsigned int ipv4_masks[33]
= { 0x00000000, /* /0 */
@@ -91,12 +98,20 @@
struct in_addr ia;
struct in6_addr ia6;
va_list ap;
+ unsigned int cmp4;
- ia.s_addr = 0; ia6.s6_addr[0] = 0; /* shut up incorrect -Wuninitialized */
+ /* gcc's -Wuninitialized thinks these may be used unitialized.
+ It's wrong, but how to explain that to it?
+ So we waste a few cycles. :( */
+ ia.s_addr = 0;
+ ia6.s6_addr[0] = 0;
+ cmp4 = 0;
+ /* End incorrect -Wuninitialized workaround */
va_start(ap,af);
switch (af)
{ case AF_INET:
ia = va_arg(ap,struct in_addr);
+ cmp4 = ntohl(ia.s_addr);
break;
case AF_INET6:
ia6 = va_arg(ap,struct in6_addr);
@@ -111,7 +126,7 @@
if (r->af != af) continue;
switch (af)
{ case AF_INET:
- if ((ia.s_addr & ipv4_masks[r->srcmask]) == r->srcmatch.v4.s_addr)
return(r);
+ if ((cmp4 & ipv4_masks[r->srcmask]) == r->srcmatch.v4.s_addr)
return(r);
break;
case AF_INET6:
if ((r->srcmask >= 8) && bcmp(&ia6,&r->srcmatch.v6,r->srcmask/8))
continue;
@@ -129,20 +144,35 @@
return(0);
}
-/* Network device interface. */
-
-static int srt_if_ioctl(struct ifnet *intf, u_long cmd, void *data)
+static int srt_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
- struct ifaddr *ifa;
- int s;
+#define ifa ((struct ifaddr *)data)
+#define ifr ((struct ifreq *)data)
int err;
+ int s;
+ SOFTC *sc;
err = 0;
s = splnet();
+ sc = ifp->if_softc;
+ simple_lock(&sc->lock);
switch (cmd)
{ case SIOCSIFADDR:
+ switch (ifa->ifa_addr->sa_family)
+ {
+#ifdef INET
+ case AF_INET:
+#endif
+#ifdef INET6
+ case AF_INET6:
+#endif
+ break;
+ default:
+ err = EAFNOSUPPORT;
+ break;
+ }
+ break;
case SIOCSIFDSTADDR:
- ifa = (void *) data;
switch (ifa->ifa_addr->sa_family)
{
#ifdef INET
@@ -152,193 +182,323 @@
case AF_INET6:
#endif
break;
+/* XXX we should support INET6 too */
default:
err = EAFNOSUPPORT;
break;
}
- /* XXX do we need to do more here for either of these? */
break;
case SIOCSIFMTU:
+ if ((ifr->ifr_mtu < 576) || (ifr->ifr_mtu > SRT_MAXMTU))
+ { err = EINVAL;
+ break;
+ }
+ /* XXX should do tun-style INET6 MTU check */
+ ifp->if_mtu = ifr->ifr_mtu;
+ break;
case SIOCGIFMTU:
- if ((err = ifioctl_common(intf, cmd, data)) == ENETRESET)
- err = 0;
+ ifr->ifr_mtu = ifp->if_mtu;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ if (! ifr)
+ { err = EAFNOSUPPORT; /* XXX */
+ break;
+ }
+ switch (ifr->ifr_addr.sa_family)
+ {
+#ifdef INET
+ case AF_INET:
+#endif
+#ifdef INET6
+ case AF_INET6:
+#endif
+ break;
+ default:
+ err = EAFNOSUPPORT;
+ break;
+ }
+ break;
+ case SIOCSIFFLAGS:
break;
default:
err = EINVAL;
break;
}
+#undef ifa
+#undef ifr
+ simple_unlock(&sc->lock);
splx(s);
return(err);
}
static int srt_if_output(
- struct ifnet *intf,
+ struct ifnet *ifp,
struct mbuf *m,
- const struct sockaddr *to,
- struct rtentry *rtp )
+ struct sockaddr *dst,
+ struct rtentry *rt)
{
SOFTC *sc;
RT *r;
+ int rv;
- sc = intf->if_softc;
- if (! (intf->if_flags & IFF_UP))
+ sc = ifp->if_softc;
+ if (! (ifp->if_flags & IFF_UP))
{ m_freem(m);
return(ENETDOWN);
}
- switch (to->sa_family)
+ simple_lock(&sc->lock);
+ switch (dst->sa_family)
{
#ifdef INET
case AF_INET:
-#endif
{ struct ip *ip;
ip = mtod(m,struct ip *);
r = find_rt(sc,AF_INET,ip->ip_src);
}
break;
+#endif
#ifdef INET6
case AF_INET6:
-#endif
{ struct ip6_hdr *ip;
ip = mtod(m,struct ip6_hdr *);
r = find_rt(sc,AF_INET6,ip->ip6_src);
}
break;
+#endif
default:
- IF_DROP(&intf->if_snd);
+ simple_unlock(&sc->lock);
+ IF_DROP(&ifp->if_snd);
m_freem(m);
return(EAFNOSUPPORT);
break;
}
- /* XXX Do we need to bpf_tap? Or do higher layers now handle that? */
- /* if_gif.c seems to imply the latter. */
- intf->if_opackets ++;
+ ifp->if_opackets ++;
if (! r)
- { intf->if_oerrors ++;
+ { ifp->if_oerrors ++;
+ simple_unlock(&sc->lock);
m_freem(m);
return(0);
}
if (! (m->m_flags & M_PKTHDR))
- { printf("srt_if_output no PKTHDR\n");
+ { simple_unlock(&sc->lock);
+ printf("srt_if_output no PKTHDR\n");
m_freem(m);
return(0);
}
- intf->if_obytes += m->m_pkthdr.len;
+ ifp->if_obytes += m->m_pkthdr.len;
if (! (r->u.dstifp->if_flags & IFF_UP))
- { m_freem(m);
+ { simple_unlock(&sc->lock);
+ m_freem(m);
return(0); /* XXX ENETDOWN? */
}
- /* XXX is 0 the right last arg here? */
- return((*r->u.dstifp->if_output)(r->u.dstifp,m,&r->dst.sa,0));
+#ifdef PFIL_HOOKS
+ rv = pfil_run_hooks(&inet_pfil_hook,&m,r->u.dstifp,PFIL_OUT);
+ if (rv)
+ { simple_unlock(&sc->lock);
+ return(rv);
+ }
+ if (dst->sa_family == AF_INET)
+ { struct ip *ip;
+ ip = mtod(m,struct ip *);
+ ip->ip_sum = 0;
+ ip->ip_sum = in_cksum(m,ip->ip_hl<<2);
+ m->m_pkthdr.csum_flags &= ~M_CSUM_IPv4;
+ }
+#endif
+ /*
+ * We have to hold sc->lock across the underlying interface's output
+ * call, because it uses r->dst.sa. This means we will deadlock if
+ * someone configures a loop and then sends a packet to it - but
+ * that's not so bad; the alternative is to recurse until we run out
+ * of stack and panic.
+ */
+ /* XXX is 0 ok as the last arg here? */
+ rv = (*r->u.dstifp->if_output)(r->u.dstifp,m,&r->dst.sa,0);
+ simple_unlock(&sc->lock);
+ return(rv);
}
-static int srt_clone_create(struct if_clone *cl, int unit)
+#ifdef ALTQ
+/* I'm not sure how relevant ALTQ is in view of the way srt works... */
+static void srt_if_start(struct ifnet *ifp)
+{
+ printf("srt if_start called\n");
+}
+#endif
+
+static int srt_clone_create(struct if_clone *ifc, int unit)
{
SOFTC *sc;
if ((unit < 0) || (unit > SRT_MAXUNIT)) return(ENXIO);
+ simple_lock(&softcv_lock);
if (softcv[unit]) return(EBUSY);
- sc = malloc(sizeof(SOFTC),M_DEVBUF,M_WAIT);
- bzero(&sc->intf,sizeof(sc->intf)); /* XXX */
+ simple_unlock(&softcv_lock);
+ sc = malloc(sizeof(SOFTC),M_DEVBUF,M_WAITOK);
+ simple_lock(&softcv_lock);
+ if (softcv[unit])
+ { simple_unlock(&softcv_lock);
+ free(sc,M_DEVBUF);
+ return(EBUSY);
+ }
sc->unit = unit;
sc->nrt = 0;
sc->rts = 0;
sc->flags = 0;
sc->kflags = 0;
- if_initname(&sc->intf,cl->ifc_name,unit);
+ bzero(&sc->intf,sizeof(sc->intf)); /* XXX interface botch */
+
snprintf(&sc->intf.if_xname[0],sizeof(sc->intf.if_xname),"%s%d",ifc->ifc_name,sc->unit);
sc->intf.if_softc = sc;
sc->intf.if_mtu = 65535;
- sc->intf.if_flags = IFF_POINTOPOINT;
- sc->intf.if_type = IFT_OTHER;
sc->intf.if_ioctl = &srt_if_ioctl;
sc->intf.if_output = &srt_if_output;
- sc->intf.if_dlt = DLT_RAW;
+#ifdef ALTQ
+ sc->ifnet.if_start = &srt_if_start;
+#endif
+ sc->intf.if_flags = IFF_POINTOPOINT;
+ sc->intf.if_type = IFT_OTHER; /* XXX is IFT_OTHER right? */
+ { extern int ifqmaxlen; /* XXX belongs in a .h file */
+ sc->intf.if_snd.ifq_maxlen = ifqmaxlen;
+ }
+ sc->intf.if_collisions = 0;
+ sc->intf.if_ierrors = 0;
+ sc->intf.if_oerrors = 0;
+ sc->intf.if_ipackets = 0;
+ sc->intf.if_opackets = 0;
+ sc->intf.if_ibytes = 0;
+ sc->intf.if_obytes = 0;
+ sc->intf.if_dlt = DLT_NULL;
+ IFQ_SET_READY(&sc->intf.if_snd);
if_attach(&sc->intf);
if_alloc_sadl(&sc->intf);
-#if NBPFILTER > 0 /* see comment near top */
- bpfattach(&sc->intf,0/*???*/,0/*???*/);
+#if NBPFILTER > 0
+ bpfattach(&sc->intf,DLT_NULL,sizeof(u_int32_t));
#endif
+ simple_lock_init(&sc->lock);
softcv[unit] = sc;
+ simple_unlock(&softcv_lock);
return(0);
}
-static int srt_clone_destroy(struct ifnet *intf)
+static int srt_clone_destroy(struct ifnet *ifp)
{
SOFTC *sc;
+ int s;
- sc = intf->if_softc;
- if ((intf->if_flags & IFF_UP) || (sc->kflags & SKF_CDEVOPEN)) return(EBUSY);
-#if NBPFILTER > 0
- bpfdetach(intf);
-#endif
- if_detach(intf);
+ simple_lock(&softcv_lock);
+ sc = ifp->if_softc;
if ((sc->unit < 0) || (sc->unit > SRT_MAXUNIT))
{ panic("srt_clone_destroy: impossible unit %d\n",sc->unit);
}
- if (softcv[sc->unit] != sc)
+ if (sc != softcv[sc->unit])
{ panic("srt_clone_destroy: bad backpointer ([%d]=%p not %p)\n",
sc->unit,(void *)softcv[sc->unit],(void *)sc);
}
+ simple_lock(&sc->lock);
+ if ((ifp->if_flags & IFF_UP) || (sc->kflags & SKF_CDEVOPEN))
+ { simple_unlock(&sc->lock);
+ simple_unlock(&softcv_lock);
+ return(EBUSY);
+ }
softcv[sc->unit] = 0;
+ simple_unlock(&softcv_lock);
+ s = splnet();
+ IF_PURGE(&ifp->if_snd);
+ ifp->if_flags &= ~IFF_RUNNING;
+ splx(s);
+#if NBPFILTER > 0
+ bpfdetach(ifp);
+#endif
+ if_detach(ifp);
+ simple_unlock(&sc->lock);
free(sc,M_DEVBUF);
return(0);
}
-struct if_clone srt_clone =
- IF_CLONE_INITIALIZER("srt",&srt_clone_create,&srt_clone_destroy);
+struct if_clone srt_cloner
+ = IF_CLONE_INITIALIZER("srt",&srt_clone_create,&srt_clone_destroy);
-extern void srtattach(void);
-void srtattach(void)
+void srtattach(int);
+void srtattach(int n __attribute__((__unused__)))
{
int i;
for (i=SRT_MAXUNIT;i>=0;i--) softcv[i] = 0;
global_flags = 0;
- if_clone_attach(&srt_clone);
+ simple_lock_init(&softcv_lock);
+ simple_lock_init(&gblf_lock);
+ if_clone_attach(&srt_cloner);
}
-/* Special-device interface. */
+/* These are unnecessary for declaration; they are here to provoke errors
+ if the definitions below get out of sync with the macros. */
+static dev_type_open(srt_ctl_open);
+static dev_type_close(srt_ctl_close);
+static dev_type_read(srt_ctl_read);
+static dev_type_write(srt_ctl_write);
+static dev_type_ioctl(srt_ctl_ioctl);
-static int srt_open(dev_t dev, int flag, int mode, struct lwp *l)
+static int srt_ctl_open(dev_t dev, int flag, int mode, struct lwp *l)
{
- int unit;
SOFTC *sc;
+ int unit;
unit = minor(dev);
- if ((unit < 0) || (unit > SRT_MAXUNIT)) return(ENXIO);
+ simple_lock(&softcv_lock);
sc = softcv[unit];
- if (! sc) return(ENXIO);
+ if (! sc)
+ { simple_unlock(&softcv_lock);
+ return(ENXIO);
+ }
+ simple_lock(&sc->lock);
sc->kflags |= SKF_CDEVOPEN;
+ simple_unlock(&sc->lock);
+ simple_unlock(&softcv_lock);
return(0);
}
-static int srt_close(dev_t dev, int flag, int mode, struct lwp *l)
+static int srt_ctl_close(
+ dev_t dev __attribute__((__unused__)),
+ int flag __attribute__((__unused__)),
+ int mode __attribute__((__unused__)),
+ struct lwp *l __attribute__((__unused__)) )
{
int unit;
SOFTC *sc;
unit = minor(dev);
if ((unit < 0) || (unit > SRT_MAXUNIT)) return(ENXIO);
+ simple_lock(&softcv_lock);
sc = softcv[unit];
- if (! sc) return(ENXIO);
+ if (! sc)
+ { simple_unlock(&softcv_lock);
+ return(ENXIO);
+ }
+ simple_lock(&sc->lock);
sc->kflags &= ~SKF_CDEVOPEN;
+ simple_unlock(&sc->lock);
+ simple_unlock(&softcv_lock);
return(0);
}
-static int srt_ioctl(
- dev_t dev,
- u_long cmd,
- void *data,
- int flag,
- struct lwp *l )
+static int srt_ctl_read(dev_t dev __attribute__((__unused__)), struct uio *uio
__attribute__((__unused__)), int flag __attribute__((__unused__)))
+{
+ return(EIO);
+}
+
+static int srt_ctl_write(dev_t dev __attribute__((__unused__)), struct uio
*uio __attribute__((__unused__)), int flag __attribute__((__unused__)))
+{
+ return(EIO);
+}
+
+static int srt_ctl_ioctl_core(SOFTC *sc, u_long cmd, caddr_t data, int flag,
struct lwp *l)
{
- SOFTC *sc;
RT *dr;
RT *scr;
- struct ifnet *intf;
+ struct ifnet *ifp;
char nbuf[IFNAMSIZ];
- sc = softcv[minor(dev)];
- if (! sc) panic("srt_ioctl: softc disappeared");
switch (cmd)
{ case SRT_GETNRT:
if (! (flag & FREAD)) return(EBADF);
@@ -353,6 +513,14 @@
dr->af = scr->af;
dr->srcmatch = scr->srcmatch;
dr->srcmask = scr->srcmask;
+ switch (scr->af)
+ {
+#ifdef INET
+ case AF_INET:
+ dr->srcmatch.v4.s_addr = htonl(scr->srcmatch.v4.s_addr);
+ break;
+#endif
+ }
strncpy(&dr->u.dstifn[0],&scr->u.dstifp->if_xname[0],IFNAMSIZ);
memcpy(&dr->dst,&scr->dst,scr->dst.sa.sa_len);
return(0);
@@ -378,17 +546,16 @@
if (dr->srcmask > 128) return(EIO);
break;
#endif
- break;
default:
return(EAFNOSUPPORT);
break;
}
- intf = ifunit(&nbuf[0]);
- if (intf == 0) return(ENXIO); /* needs translation */
+ ifp = ifunit(&nbuf[0]);
+ if (! ifp) return(ENXIO); /* needs translation */
if (dr->inx == sc->nrt)
{ RT **tmp;
tmp = malloc((sc->nrt+1)*sizeof(*tmp),M_DEVBUF,M_WAITOK);
- if (tmp == 0) return(ENOBUFS);
+ if (! tmp) return(ENOBUFS);
tmp[sc->nrt] = 0;
if (sc->nrt > 0)
{ memcpy(tmp,sc->rts,sc->nrt*sizeof(*tmp));
@@ -407,8 +574,16 @@
}
scr->af = dr->af;
scr->srcmatch = dr->srcmatch;
+ switch (scr->af)
+ {
+#ifdef INET
+ case AF_INET:
+ scr->srcmatch.v4.s_addr = ntohl(scr->srcmatch.v4.s_addr);
+ break;
+#endif
+ }
scr->srcmask = dr->srcmask;
- scr->u.dstifp = intf;
+ scr->u.dstifp = ifp;
memcpy(&scr->dst,&dr->dst,dr->dst.sa.sa_len);
update_mtu(sc);
return(0);
@@ -436,23 +611,29 @@
{ unsigned int f;
if (! (flag & FWRITE)) return(EBADF);
f = *(unsigned int *)data & SSF_UCHG;
+ simple_lock(&gblf_lock);
global_flags = (global_flags & ~SSF_UCHG) | (f & SSF_GLOBAL);
+ simple_unlock(&gblf_lock);
sc->flags = (sc->flags & ~SSF_UCHG) | (f & ~SSF_GLOBAL);
}
return(0);
break;
case SRT_GFLAGS:
if (! (flag & FREAD)) return(EBADF);
+ simple_lock(&gblf_lock);
*(unsigned int *)data = sc->flags | global_flags;
+ simple_unlock(&gblf_lock);
return(0);
break;
case SRT_SGFLAGS:
{ unsigned int o;
unsigned int n;
if ((flag & (FWRITE|FREAD)) != (FWRITE|FREAD)) return(EBADF);
+ simple_lock(&gblf_lock);
o = sc->flags | global_flags;
n = *(unsigned int *)data & SSF_UCHG;
global_flags = (global_flags & ~SSF_UCHG) | (n & SSF_GLOBAL);
+ simple_unlock(&gblf_lock);
sc->flags = (sc->flags & ~SSF_UCHG) | (n & ~SSF_GLOBAL);
*(unsigned int *)data = o;
}
@@ -465,15 +646,32 @@
return(ENOTTY);
}
+static int srt_ctl_ioctl(
+ dev_t dev,
+ u_long cmd,
+ caddr_t data,
+ int flag,
+ struct lwp *l )
+{
+ SOFTC *sc;
+ int err;
+ int unit;
+
+ unit = minor(dev);
+ if ((unit < 0) || (unit > SRT_MAXUNIT)) return(ENXIO);
+ simple_lock(&softcv_lock);
+ sc = softcv[unit];
+ if (! sc)
+ { simple_unlock(&softcv_lock);
+ return(ENXIO);
+ }
+ simple_lock(&sc->lock);
+ simple_unlock(&softcv_lock);
+ err = srt_ctl_ioctl_core(sc,cmd,data,flag,l);
+ simple_unlock(&sc->lock);
+ return(err);
+}
+
const struct cdevsw srt_cdevsw
- = { &srt_open,
- &srt_close,
- nullread,
- nullwrite,
- &srt_ioctl,
- nullstop,
- notty,
- nullpoll,
- nommap,
- nullkqfilter,
- D_OTHER };
+ = { &srt_ctl_open, &srt_ctl_close, &srt_ctl_read, &srt_ctl_write,
+ &srt_ctl_ioctl, nostop, notty, nullpoll, nommap, nokqfilter, D_OTHER };
Home |
Main Index |
Thread Index |
Old Index