summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbouyer <bouyer@NetBSD.org>2011-08-30 14:22:22 +0000
committerbouyer <bouyer@NetBSD.org>2011-08-30 14:22:22 +0000
commit23c35c52354bfdc92b8d8be7b692cf073ea99dca (patch)
tree8db608a4280f211e8c5f7942c1dd17a3a4fd8783
parentd5bb9cf50ec4c0871b2b9f0253ee84aae482c175 (diff)
Provide netbsd32 compat for bpf. Beside the ioctls, the structure
returned to userland by read(2) also needs to be converted. For this, the bpf descriptor is flagged as compat32 (or not) in the open and ioctl functions (where the user process's pid is also updated in the descriptor). When the bpf buffer is filled in, the 32bits or native header is used depending on the information stored in the descriptor. This won't work if a 64bit binary does the open and ioctls, and then exec a 32bit program which will do the read. But this is very unlikely to happen in real life ... Tested on i386 and loongson; with these changes my loongson can run dhclient and tcpdump with a n32 userland.
-rw-r--r--sys/compat/netbsd32/netbsd32_ioctl.c46
-rw-r--r--sys/compat/netbsd32/netbsd32_ioctl.h22
-rw-r--r--sys/net/bpf.c97
-rw-r--r--sys/net/bpf.h20
-rw-r--r--sys/net/bpfdesc.h5
5 files changed, 154 insertions, 36 deletions
diff --git a/sys/compat/netbsd32/netbsd32_ioctl.c b/sys/compat/netbsd32/netbsd32_ioctl.c
index 01a6a51cba6..1cabcc0828d 100644
--- a/sys/compat/netbsd32/netbsd32_ioctl.c
+++ b/sys/compat/netbsd32/netbsd32_ioctl.c
@@ -1,4 +1,4 @@
-/* $NetBSD: netbsd32_ioctl.c,v 1.59 2011/08/30 07:54:15 macallan Exp $ */
+/* $NetBSD: netbsd32_ioctl.c,v 1.60 2011/08/30 14:22:22 bouyer Exp $ */
/*
* Copyright (c) 1998, 2001 Matthew R. Green
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_ioctl.c,v 1.59 2011/08/30 07:54:15 macallan Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_ioctl.c,v 1.60 2011/08/30 14:22:22 bouyer Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -61,6 +61,7 @@ __KERNEL_RCSID(0, "$NetBSD: netbsd32_ioctl.c,v 1.59 2011/08/30 07:54:15 macallan
#include <net/if.h>
#include <net/route.h>
+#include <net/bpf.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/igmp.h>
@@ -294,6 +295,22 @@ netbsd32_to_wdog_conf(struct netbsd32_wdog_conf *s32p, struct wdog_conf *p, u_lo
p->wc_count = s32p->wc_count;
}
+static inline void
+netbsd32_to_bpf_program(struct netbsd32_bpf_program *s32p, struct bpf_program *p, u_long cmd)
+{
+
+ p->bf_insns = (void *)NETBSD32PTR64(s32p->bf_insns);
+ p->bf_len = s32p->bf_len;
+}
+
+static inline void
+netbsd32_to_bpf_dltlist(struct netbsd32_bpf_dltlist *s32p, struct bpf_dltlist *p, u_long cmd)
+{
+
+ p->bfl_list = (void *)NETBSD32PTR64(s32p->bfl_list);
+ p->bfl_len = s32p->bfl_len;
+}
+
/* wsdisplay stuff */
static inline void
netbsd32_to_wsdisplay_addscreendata(struct netbsd32_wsdisplay_addscreendata *asd32,
@@ -515,6 +532,22 @@ netbsd32_from_ieee80211_nwkey(struct ieee80211_nwkey *nwk,
}
static inline void
+netbsd32_from_bpf_program(struct bpf_program *p, struct netbsd32_bpf_program *s32p, u_long cmd)
+{
+
+ NETBSD32PTR32(s32p->bf_insns, p->bf_insns);
+ s32p->bf_len = p->bf_len;
+}
+
+static inline void
+netbsd32_from_bpf_dltlist(struct bpf_dltlist *p, struct netbsd32_bpf_dltlist *s32p, u_long cmd)
+{
+
+ NETBSD32PTR32(s32p->bfl_list, p->bfl_list);
+ s32p->bfl_len = p->bfl_len;
+}
+
+static inline void
netbsd32_from_u_long(u_long *p, netbsd32_u_long *s32p, u_long cmd)
{
@@ -825,6 +858,15 @@ netbsd32_ioctl(struct lwp *l, const struct netbsd32_ioctl_args *uap, register_t
case WDOGIOC_GWDOGS32:
IOCTL_STRUCT_CONV_TO(WDOGIOC_GWDOGS, wdog_conf);
+ case BIOCSETF32:
+ IOCTL_STRUCT_CONV_TO(BIOCSETF, bpf_program);
+ case BIOCSTCPF32:
+ IOCTL_STRUCT_CONV_TO(BIOCSTCPF, bpf_program);
+ case BIOCSUDPF32:
+ IOCTL_STRUCT_CONV_TO(BIOCSUDPF, bpf_program);
+ case BIOCGDLTLIST32:
+ IOCTL_STRUCT_CONV_TO(BIOCGDLTLIST, bpf_dltlist);
+
case WSDISPLAYIO_ADDSCREEN32:
IOCTL_STRUCT_CONV_TO(WSDISPLAYIO_ADDSCREEN, wsdisplay_addscreendata);
diff --git a/sys/compat/netbsd32/netbsd32_ioctl.h b/sys/compat/netbsd32/netbsd32_ioctl.h
index 5bd3357c253..e1da27616a7 100644
--- a/sys/compat/netbsd32/netbsd32_ioctl.h
+++ b/sys/compat/netbsd32/netbsd32_ioctl.h
@@ -1,4 +1,4 @@
-/* $NetBSD: netbsd32_ioctl.h,v 1.38 2011/08/30 07:54:15 macallan Exp $ */
+/* $NetBSD: netbsd32_ioctl.h,v 1.39 2011/08/30 14:22:22 bouyer Exp $ */
/*
* Copyright (c) 1998, 2001 Matthew R. Green
@@ -90,6 +90,23 @@ struct netbsd32_format_op {
#define DIOCWFORMAT32 _IOWR('d', 106, struct netbsd32_format_op)
#endif
+/* from <net/bpf.h> */
+struct netbsd32_bpf_program {
+ u_int bf_len;
+ netbsd32_pointer_t bf_insns;
+};
+
+struct netbsd32_bpf_dltlist {
+ u_int bfl_len;
+ netbsd32_pointer_t bfl_list;
+};
+
+#define BIOCSETF32 _IOW('B',103, struct netbsd32_bpf_program)
+#define BIOCSTCPF32 _IOW('B',114, struct netbsd32_bpf_program)
+#define BIOCSUDPF32 _IOW('B',115, struct netbsd32_bpf_program)
+#define BIOCGDLTLIST32 _IOWR('B',119, struct netbsd32_bpf_dltlist)
+
+
struct netbsd32_wsdisplay_addscreendata {
int idx; /* screen index */
netbsd32_charp screentype;
@@ -129,9 +146,6 @@ dev/wscons/wsconsio.h:228:#define WSDISPLAYIO_SCURSOR _IOW('W', 74, struct wsdis
dev/wscons/wsconsio.h:241:#define WSDISPLAYIO_SFONT _IOW('W', 77, struct wsdisplay_font)
-net/bpf.h:127:#define BIOCSETF _IOW('B',103, struct bpf_program)
-net/bpf.h:138:#define BIOCSTCPF _IOW('B',114, struct bpf_program)
-net/bpf.h:139:#define BIOCSUDPF _IOW('B',115, struct bpf_program)
net/if_ppp.h:110:#define PPPIOCSPASS _IOW('t', 71, struct bpf_program) /* set pass filter */
net/if_ppp.h:111:#define PPPIOCSACTIVE _IOW('t', 70, struct bpf_program) /* set active filt */
diff --git a/sys/net/bpf.c b/sys/net/bpf.c
index 8ee58eff529..01177f45802 100644
--- a/sys/net/bpf.c
+++ b/sys/net/bpf.c
@@ -1,4 +1,4 @@
-/* $NetBSD: bpf.c,v 1.165 2011/06/10 00:10:35 christos Exp $ */
+/* $NetBSD: bpf.c,v 1.166 2011/08/30 14:22:22 bouyer Exp $ */
/*
* Copyright (c) 1990, 1991, 1993
@@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: bpf.c,v 1.165 2011/06/10 00:10:35 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: bpf.c,v 1.166 2011/08/30 14:22:22 bouyer Exp $");
#if defined(_KERNEL_OPT)
#include "opt_bpf.h"
@@ -142,6 +142,7 @@ static int bpf_setif(struct bpf_d *, struct ifreq *);
static void bpf_timed_out(void *);
static inline void
bpf_wakeup(struct bpf_d *);
+static int bpf_hdrlen(struct bpf_d *);
static void catchpacket(struct bpf_d *, u_char *, u_int, u_int,
void *(*)(void *, const void *, size_t), struct timespec *);
static void reset_d(struct bpf_d *);
@@ -409,6 +410,10 @@ bpfopen(dev_t dev, int flag, int mode, struct lwp *l)
d->bd_seesent = 1;
d->bd_feedback = 0;
d->bd_pid = l->l_proc->p_pid;
+#ifdef _LP64
+ if (curproc->p_flag & PK_32)
+ d->bd_compat32 = 1;
+#endif
getnanotime(&d->bd_btime);
d->bd_atime = d->bd_mtime = d->bd_btime;
callout_init(&d->bd_callout, 0);
@@ -738,6 +743,12 @@ bpf_ioctl(struct file *fp, u_long cmd, void *addr)
*/
KERNEL_LOCK(1, NULL);
d->bd_pid = curproc->p_pid;
+#ifdef _LP64
+ if (curproc->p_flag & PK_32)
+ d->bd_compat32 = 1;
+ else
+ d->bd_compat32 = 0;
+#endif
s = splnet();
if (d->bd_state == BPF_WAITING)
@@ -1519,6 +1530,23 @@ _bpf_mtap_sl_out(struct bpf_if *bp, u_char *chdr, struct mbuf *m)
m_freem(m);
}
+static int
+bpf_hdrlen(struct bpf_d *d)
+{
+ int hdrlen = d->bd_bif->bif_hdrlen;
+ /*
+ * Compute the length of the bpf header. This is not necessarily
+ * equal to SIZEOF_BPF_HDR because we want to insert spacing such
+ * that the network layer header begins on a longword boundary (for
+ * performance reasons and to alleviate alignment restrictions).
+ */
+#ifdef _LP64
+ if (d->bd_compat32)
+ return (BPF_WORDALIGN32(hdrlen + SIZEOF_BPF_HDR32) - hdrlen);
+ else
+#endif
+ return (BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen);
+}
/*
* Move the packet data from interface memory (pkt) into the
* store buffer. Return 1 if it's time to wakeup a listener (buffer full),
@@ -1532,8 +1560,11 @@ catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen,
void *(*cpfn)(void *, const void *, size_t), struct timespec *ts)
{
struct bpf_hdr *hp;
+#ifdef _LP64
+ struct bpf_hdr32 *hp32;
+#endif
int totlen, curlen;
- int hdrlen = d->bd_bif->bif_hdrlen;
+ int hdrlen = bpf_hdrlen(d);
int do_wakeup = 0;
++d->bd_ccount;
@@ -1551,7 +1582,12 @@ catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen,
/*
* Round up the end of the previous packet to the next longword.
*/
- curlen = BPF_WORDALIGN(d->bd_slen);
+#ifdef _LP64
+ if (d->bd_compat32)
+ curlen = BPF_WORDALIGN32(d->bd_slen);
+ else
+#endif
+ curlen = BPF_WORDALIGN(d->bd_slen);
if (curlen + totlen > d->bd_bufsize) {
/*
* This packet will overflow the storage buffer.
@@ -1582,15 +1618,33 @@ catchpacket(struct bpf_d *d, u_char *pkt, u_int pktlen, u_int snaplen,
/*
* Append the bpf header.
*/
- hp = (struct bpf_hdr *)((char *)d->bd_sbuf + curlen);
- hp->bh_tstamp.tv_sec = ts->tv_sec;
- hp->bh_tstamp.tv_usec = ts->tv_nsec / 1000;
- hp->bh_datalen = pktlen;
- hp->bh_hdrlen = hdrlen;
- /*
- * Copy the packet data into the store buffer and update its length.
- */
- (*cpfn)((u_char *)hp + hdrlen, pkt, (hp->bh_caplen = totlen - hdrlen));
+#ifdef _LP64
+ if (d->bd_compat32) {
+ hp32 = (struct bpf_hdr32 *)((char *)d->bd_sbuf + curlen);
+ hp32->bh_tstamp.tv_sec = ts->tv_sec;
+ hp32->bh_tstamp.tv_usec = ts->tv_nsec / 1000;
+ hp32->bh_datalen = pktlen;
+ hp32->bh_hdrlen = hdrlen;
+ /*
+ * Copy the packet data into the store buffer and update its length.
+ */
+ (*cpfn)((u_char *)hp32 + hdrlen, pkt,
+ (hp32->bh_caplen = totlen - hdrlen));
+ } else
+#endif
+ {
+ hp = (struct bpf_hdr *)((char *)d->bd_sbuf + curlen);
+ hp->bh_tstamp.tv_sec = ts->tv_sec;
+ hp->bh_tstamp.tv_usec = ts->tv_nsec / 1000;
+ hp->bh_datalen = pktlen;
+ hp->bh_hdrlen = hdrlen;
+ /*
+ * Copy the packet data into the store buffer and update
+ * its length.
+ */
+ (*cpfn)((u_char *)hp + hdrlen, pkt,
+ (hp->bh_caplen = totlen - hdrlen));
+ }
d->bd_slen = curlen + totlen;
/*
@@ -1667,14 +1721,7 @@ _bpfattach(struct ifnet *ifp, u_int dlt, u_int hdrlen, struct bpf_if **driverp)
*bp->bif_driverp = 0;
- /*
- * Compute the length of the bpf header. This is not necessarily
- * equal to SIZEOF_BPF_HDR because we want to insert spacing such
- * that the network layer header begins on a longword boundary (for
- * performance reasons and to alleviate alignment restrictions).
- */
- bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen;
-
+ bp->bif_hdrlen = hdrlen;
#if 0
printf("bpf: %s attached\n", ifp->if_xname);
#endif
@@ -1732,13 +1779,7 @@ _bpf_change_type(struct ifnet *ifp, u_int dlt, u_int hdrlen)
bp->bif_dlt = dlt;
- /*
- * Compute the length of the bpf header. This is not necessarily
- * equal to SIZEOF_BPF_HDR because we want to insert spacing such
- * that the network layer header begins on a longword boundary (for
- * performance reasons and to alleviate alignment restrictions).
- */
- bp->bif_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen;
+ bp->bif_hdrlen = hdrlen;
}
/*
diff --git a/sys/net/bpf.h b/sys/net/bpf.h
index 382dcfdf61d..caceb487b82 100644
--- a/sys/net/bpf.h
+++ b/sys/net/bpf.h
@@ -1,4 +1,4 @@
-/* $NetBSD: bpf.h,v 1.57 2010/12/05 02:40:40 christos Exp $ */
+/* $NetBSD: bpf.h,v 1.58 2011/08/30 14:22:22 bouyer Exp $ */
/*
* Copyright (c) 1990, 1991, 1993
@@ -53,7 +53,10 @@ typedef u_int bpf_u_int32;
* even multiple of BPF_ALIGNMENT.
*/
#define BPF_ALIGNMENT sizeof(long)
+#define BPF_ALIGNMENT32 sizeof(int)
+
#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1))
+#define BPF_WORDALIGN32(x) (((x)+(BPF_ALIGNMENT32-1))&~(BPF_ALIGNMENT32-1))
#define BPF_MAXINSNS 512
#define BPF_DFLTBUFSIZE (1024*1024) /* default static upper limit */
@@ -152,6 +155,11 @@ struct bpf_timeval {
long tv_usec;
};
+struct bpf_timeval32 {
+ int32_t tv_sec;
+ int32_t tv_usec;
+};
+
struct bpf_hdr {
struct bpf_timeval bh_tstamp; /* time stamp */
uint32_t bh_caplen; /* length of captured portion */
@@ -159,6 +167,14 @@ struct bpf_hdr {
uint16_t bh_hdrlen; /* length of bpf header (this struct
plus alignment padding) */
};
+
+struct bpf_hdr32 {
+ struct bpf_timeval32 bh_tstamp; /* time stamp */
+ uint32_t bh_caplen; /* length of captured portion */
+ uint32_t bh_datalen; /* original length of packet */
+ uint16_t bh_hdrlen; /* length of bpf header (this struct
+ plus alignment padding) */
+};
/*
* Because the structure above is not a multiple of 4 bytes, some compilers
* will insist on inserting padding; hence, sizeof(struct bpf_hdr) won't work.
@@ -172,8 +188,10 @@ struct bpf_hdr {
defined(__mips__) || defined(__ns32k__) || defined(__vax__) || \
defined(__sh__) || (defined(__sparc__) && !defined(__sparc64__))
#define SIZEOF_BPF_HDR 18
+#define SIZEOF_BPF_HDR32 18
#else
#define SIZEOF_BPF_HDR sizeof(struct bpf_hdr)
+#define SIZEOF_BPF_HDR32 sizeof(struct bpf_hdr32)
#endif
#endif
diff --git a/sys/net/bpfdesc.h b/sys/net/bpfdesc.h
index 77a5cc3d206..5064acabe63 100644
--- a/sys/net/bpfdesc.h
+++ b/sys/net/bpfdesc.h
@@ -1,4 +1,4 @@
-/* $NetBSD: bpfdesc.h,v 1.32 2010/03/13 20:38:48 christos Exp $ */
+/* $NetBSD: bpfdesc.h,v 1.33 2011/08/30 14:22:22 bouyer Exp $ */
/*
* Copyright (c) 1990, 1991, 1993
@@ -97,6 +97,9 @@ struct bpf_d {
struct timespec bd_atime; /* access time */
struct timespec bd_mtime; /* modification time */
struct timespec bd_btime; /* birth time */
+#ifdef _LP64
+ int bd_compat32; /* 32-bit stream on LP64 system */
+#endif
};