summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorticso <ticso@FreeBSD.org>2003-06-04 01:17:37 +0000
committerticso <ticso@FreeBSD.org>2003-06-04 01:17:37 +0000
commitbb00c59c79a3aceacb0bb3712668d1a80352481f (patch)
tree886cc6b03c4460c9eed8881a0a71205b05c17d1c
parent16f34ab41364565ebcc08fe935fb3ed7646887aa (diff)
downloadFreeBSD-src-bb00c59c79a3aceacb0bb3712668d1a80352481f.zip
FreeBSD-src-bb00c59c79a3aceacb0bb3712668d1a80352481f.tar.gz
Change handling to support strong alignment architectures such as alpha and
sparc64. PR: alpha/50658 Submitted by: rizzo Tested on: alpha
-rw-r--r--sbin/ipfw/ipfw2.c46
-rw-r--r--sys/netinet/ip_dummynet.c8
-rw-r--r--sys/netinet/ip_fw.h22
-rw-r--r--sys/netinet/ip_fw2.c21
4 files changed, 74 insertions, 23 deletions
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index edec049..b33fdc0 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -348,6 +348,14 @@ struct _s_x rule_options[] = {
{ NULL, 0 }
};
+static __inline u_int64_t
+align_uint64(u_int64_t *pll) {
+ u_int64_t ret;
+
+ bcopy (pll, &ret, sizeof(ret));
+ return ret;
+};
+
/**
* match_token takes a table and a string, returns the value associated
* with the string (0 meaning an error in most cases)
@@ -813,8 +821,9 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
int flags = 0; /* prerequisites */
ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */
int or_block = 0; /* we are in an or block */
+ u_int32_t set_disable;
- u_int32_t set_disable = rule->set_disable;
+ bcopy(&rule->next_rule, &set_disable, sizeof(set_disable));
if (set_disable & (1 << rule->set)) { /* disabled */
if (!show_sets)
@@ -825,8 +834,8 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
printf("%05u ", rule->rulenum);
if (do_acct)
- printf("%*llu %*llu ", pcwidth, rule->pcnt, bcwidth,
- rule->bcnt);
+ printf("%*llu %*llu ", pcwidth, align_uint64(&rule->pcnt),
+ bcwidth, align_uint64(&rule->bcnt));
if (do_time) {
char timestr[30];
@@ -1213,14 +1222,18 @@ show_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth)
{
struct protoent *pe;
struct in_addr a;
+ uint16_t rulenum;
if (!do_expired) {
if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT))
return;
}
- printf("%05d %*llu %*llu (%ds)", d->rulenum, pcwidth, d->pcnt, bcwidth,
- d->bcnt, d->expire);
+ bcopy(&d->rule, &rulenum, sizeof(rulenum));
+
+ printf("%05d %*llu %*llu (%ds)", rulenum, pcwidth,
+ align_uint64(&d->pcnt), bcwidth,
+ align_uint64(&d->bcnt), d->expire);
switch (d->dyn_type) {
case O_LIMIT_PARENT:
printf(" PARENT %d", d->count);
@@ -1454,7 +1467,9 @@ sets_handler(int ac, char *av[])
err(EX_OSERR, "malloc");
if (getsockopt(s, IPPROTO_IP, IP_FW_GET, data, &nbytes) < 0)
err(EX_OSERR, "getsockopt(IP_FW_GET)");
- set_disable = ((struct ip_fw *)data)->set_disable;
+ bcopy(&((struct ip_fw *)data)->next_rule,
+ &set_disable, sizeof(set_disable));
+
for (i = 0, msg = "disable" ; i < 31; i++)
if ( (set_disable & (1<<i))) {
@@ -1620,23 +1635,27 @@ list(int ac, char *av[])
for (n = 0, r = data; n < nstat;
n++, r = (void *)r + RULESIZE(r)) {
/* packet counter */
- width = snprintf(NULL, 0, "%llu", r->pcnt);
+ width = snprintf(NULL, 0, "%llu",
+ align_uint64(&r->pcnt));
if (width > pcwidth)
pcwidth = width;
/* byte counter */
- width = snprintf(NULL, 0, "%llu", r->bcnt);
+ width = snprintf(NULL, 0, "%llu",
+ align_uint64(&r->bcnt));
if (width > bcwidth)
bcwidth = width;
}
}
if (do_dynamic && ndyn) {
for (n = 0, d = dynrules; n < ndyn; n++, d++) {
- width = snprintf(NULL, 0, "%llu", d->pcnt);
+ width = snprintf(NULL, 0, "%llu",
+ align_uint64(&d->pcnt));
if (width > pcwidth)
pcwidth = width;
- width = snprintf(NULL, 0, "%llu", d->bcnt);
+ width = snprintf(NULL, 0, "%llu",
+ align_uint64(&d->bcnt));
if (width > bcwidth)
bcwidth = width;
}
@@ -1690,9 +1709,12 @@ list(int ac, char *av[])
/* already warned */
continue;
for (n = 0, d = dynrules; n < ndyn; n++, d++) {
- if (d->rulenum > rnum)
+ uint16_t rulenum;
+
+ bcopy(&d->rule, &rulenum, sizeof(rulenum));
+ if (rulenum > rnum)
break;
- if (d->rulenum == rnum)
+ if (rulenum == rnum)
show_dyn_ipfw(d, pcwidth, bcwidth);
}
}
diff --git a/sys/netinet/ip_dummynet.c b/sys/netinet/ip_dummynet.c
index 0ea1868..78c7b4d 100644
--- a/sys/netinet/ip_dummynet.c
+++ b/sys/netinet/ip_dummynet.c
@@ -1027,7 +1027,11 @@ locate_flowset(int pipe_nr, struct ip_fw *rule)
if (cmd->opcode == O_LOG)
cmd += F_LEN(cmd);
+#ifdef __i386__
fs = ((ipfw_insn_pipe *)cmd)->pipe_ptr;
+#else
+ bcopy(& ((ipfw_insn_pipe *)cmd)->pipe_ptr, &fs, sizeof(fs));
+#endif
if (fs != NULL)
return fs;
@@ -1049,8 +1053,12 @@ locate_flowset(int pipe_nr, struct ip_fw *rule)
}
/* record for the future */
#if IPFW2
+#ifdef __i386__
((ipfw_insn_pipe *)cmd)->pipe_ptr = fs;
#else
+ bcopy(&fs, & ((ipfw_insn_pipe *)cmd)->pipe_ptr, sizeof(fs));
+#endif
+#else
if (fs != NULL)
rule->pipe_ptr = fs;
#endif
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
index f2b932e..3aa2799 100644
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -32,11 +32,16 @@
* The kernel representation of ipfw rules is made of a list of
* 'instructions' (for all practical purposes equivalent to BPF
* instructions), which specify which fields of the packet
- * (or its metatada) should be analysed.
+ * (or its metadata) should be analysed.
*
* Each instruction is stored in a structure which begins with
* "ipfw_insn", and can contain extra fields depending on the
* instruction type (listed below).
+ * Note that the code is written so that individual instructions
+ * have a size which is a multiple of 32 bits. This means that, if
+ * such structures contain pointers or other 64-bit entities,
+ * (there is just one instance now) they may end up unaligned on
+ * 64-bit architectures, so the must be handled with care.
*
* "enum ipfw_opcodes" are the opcodes supported. We can have up
* to 256 different opcodes.
@@ -211,7 +216,7 @@ typedef struct _ipfw_insn_if {
ipfw_insn o;
union {
struct in_addr ip;
- int unit;
+ int32_t unit;
} p;
char name[IFNAMSIZ];
} ipfw_insn_if;
@@ -220,10 +225,13 @@ typedef struct _ipfw_insn_if {
* This is used for pipe and queue actions, which need to store
* a single pointer (which can have different size on different
* architectures.
+ * Note that, because of previous instructions, pipe_ptr might
+ * be unaligned in the overall structure, so it needs to be
+ * manipulated with care.
*/
typedef struct _ipfw_insn_pipe {
ipfw_insn o;
- void *pipe_ptr;
+ void *pipe_ptr; /* XXX */
} ipfw_insn_pipe;
/*
@@ -278,7 +286,9 @@ typedef struct _ipfw_insn_log {
struct ip_fw {
struct ip_fw *next; /* linked list of rules */
struct ip_fw *next_rule; /* ptr to next [skipto] rule */
+#if 0 /* passed up using 'next_rule' */
u_int32_t set_disable; /* disabled sets (for userland) */
+#endif
u_int16_t act_ofs; /* offset of action in 32-bit units */
u_int16_t cmd_len; /* # of 32-bit words in cmd */
u_int16_t rulenum; /* rule number */
@@ -319,12 +329,12 @@ typedef struct _ipfw_dyn_rule ipfw_dyn_rule;
struct _ipfw_dyn_rule {
ipfw_dyn_rule *next; /* linked list of rules. */
- struct ipfw_flow_id id; /* (masked) flow id */
struct ip_fw *rule; /* pointer to rule */
ipfw_dyn_rule *parent; /* pointer to parent rule */
- u_int32_t expire; /* expire time */
u_int64_t pcnt; /* packet match counter */
u_int64_t bcnt; /* byte match counter */
+ struct ipfw_flow_id id; /* (masked) flow id */
+ u_int32_t expire; /* expire time */
u_int32_t bucket; /* which bucket in hash table */
u_int32_t state; /* state of this rule (typically a
* combination of TCP flags)
@@ -334,7 +344,9 @@ struct _ipfw_dyn_rule {
/* to generate keepalives) */
u_int16_t dyn_type; /* rule type */
u_int16_t count; /* refcount */
+#if 0 /* passed up with 'rule' */
u_int16_t rulenum; /* rule number (for userland) */
+#endif
};
/*
diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c
index 1b7b143..95a153e 100644
--- a/sys/netinet/ip_fw2.c
+++ b/sys/netinet/ip_fw2.c
@@ -2020,8 +2020,15 @@ flush_pipe_ptrs(struct dn_flow_set *match)
if (cmd->o.opcode != O_PIPE && cmd->o.opcode != O_QUEUE)
continue;
- if (match == NULL || cmd->pipe_ptr == match)
- cmd->pipe_ptr = NULL;
+ /*
+ * XXX Use bcmp/bzero to handle pipe_ptr to overcome
+ * possible alignment problems on 64-bit architectures.
+ * This code is seldom used so we do not worry too
+ * much about efficiency.
+ */
+ if (match == NULL ||
+ !bcmp(&cmd->pipe_ptr, &match, sizeof(match)) )
+ bzero(&cmd->pipe_ptr, sizeof(cmd->pipe_ptr));
}
}
@@ -2562,7 +2569,8 @@ ipfw_ctl(struct sockopt *sopt)
for (rule = layer3_chain; rule ; rule = rule->next) {
int i = RULESIZE(rule);
bcopy(rule, bp, i);
- ((struct ip_fw *)bp)->set_disable = set_disable;
+ bcopy(&set_disable, &(bp->next_rule),
+ sizeof(set_disable));
bp = (struct ip_fw *)((char *)bp + i);
}
if (ipfw_dyn_v) {
@@ -2574,21 +2582,22 @@ ipfw_ctl(struct sockopt *sopt)
for ( p = ipfw_dyn_v[i] ; p != NULL ;
p = p->next, dst++ ) {
bcopy(p, dst, sizeof *p);
- dst->rulenum = p->rule->rulenum;
+ bcopy(&(p->rule->rulenum), &(dst->rule),
+ sizeof(p->rule->rulenum));
/*
* store a non-null value in "next".
* The userland code will interpret a
* NULL here as a marker
* for the last dynamic rule.
*/
- dst->next = dst ;
+ bcopy(&dst, &dst->next, sizeof(dst));
last = dst ;
dst->expire =
TIME_LEQ(dst->expire, time_second) ?
0 : dst->expire - time_second ;
}
if (last != NULL) /* mark last dynamic rule */
- last->next = NULL;
+ bzero(&last->next, sizeof(last));
}
splx(s);
OpenPOWER on IntegriCloud