summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/net80211/ieee80211.h46
-rw-r--r--sys/net80211/ieee80211_output.c177
-rw-r--r--sys/net80211/ieee80211_proto.h5
3 files changed, 223 insertions, 5 deletions
diff --git a/sys/net80211/ieee80211.h b/sys/net80211/ieee80211.h
index 5f1de1589a7..d8f80a7e849 100644
--- a/sys/net80211/ieee80211.h
+++ b/sys/net80211/ieee80211.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211.h,v 1.2 2004/10/20 22:21:13 fgsch Exp $ */
+/* $OpenBSD: ieee80211.h,v 1.3 2004/12/23 11:54:08 jsg Exp $ */
/* $NetBSD: ieee80211.h,v 1.6 2004/04/30 23:51:53 dyoung Exp $ */
/*-
@@ -56,6 +56,8 @@ struct ieee80211_plcp_hdr {
#define IEEE80211_PLCP_SFD 0xF3A0
#define IEEE80211_PLCP_SERVICE 0x00
+#define IEEE80211_PLCP_SERVICE_PBCC 0x08 /* PBCC encoded */
+#define IEEE80211_PLCP_SERVICE_LENEXT 0x80 /* length extension bit */
/*
* generic definitions for IEEE 802.11 frames
@@ -503,12 +505,16 @@ enum {
};
#define IEEE80211_WEP_KEYLEN 5 /* 40bit */
+#define IEEE80211_WEP_NKID 4 /* number of key ids */
+
+/* WEP header constants */
#define IEEE80211_WEP_IVLEN 3 /* 24bit */
#define IEEE80211_WEP_KIDLEN 1 /* 1 octet */
#define IEEE80211_WEP_CRCLEN 4 /* CRC-32 */
-#define IEEE80211_WEP_NKID 4 /* number of key ids */
-
#define IEEE80211_CRC_LEN 4
+#define IEEE80211_WEP_TOTLEN (IEEE80211_WEP_IVLEN + \
+ IEEE80211_WEP_KIDLEN + \
+ IEEE80211_WEP_CRCLEN)
/*
* Maximum acceptable MTU is:
@@ -542,6 +548,40 @@ enum {
#define IEEE80211_RTS_MIN 1
#define IEEE80211_RTS_MAX IEEE80211_MAX_LEN
+/*
+ * 802.11 frame duration definitions.
+ */
+
+struct ieee80211_duration {
+ uint16_t d_rts_dur;
+ uint16_t d_data_dur;
+ uint16_t d_plcp_len;
+ uint8_t d_plcp_svc;
+};
+
+/* One Time Unit (TU) is 1Kus = 1024 microseconds. */
+#define IEEE80211_DUR_TU 1024
+
+/* IEEE 802.11b durations for DSSS PHY in microseconds */
+#define IEEE80211_DUR_DS_LONG_PREAMBLE 144
+#define IEEE80211_DUR_DS_SHORT_PREAMBLE 72
+#define IEEE80211_DUR_DS_FAST_PLCPHDR 24
+#define IEEE80211_DUR_DS_SLOW_PLCPHDR 48
+#define IEEE80211_DUR_DS_SLOW_ACK 112
+#define IEEE80211_DUR_DS_FAST_ACK 56
+#define IEEE80211_DUR_DS_SLOW_CTS 112
+#define IEEE80211_DUR_DS_FAST_CTS 56
+#define IEEE80211_DUR_DS_SLOT 20
+#define IEEE80211_DUR_DS_SIFS 10
+#define IEEE80211_DUR_DS_PIFS (IEEE80211_DUR_DS_SIFS + IEEE80211_DUR_DS_SLOT)
+#define IEEE80211_DUR_DS_DIFS (IEEE80211_DUR_DS_SIFS + \
+ 2 * IEEE80211_DUR_DS_SLOT)
+#define IEEE80211_DUR_DS_EIFS (IEEE80211_DUR_DS_SIFS + \
+ IEEE80211_DUR_DS_SLOW_ACK + \
+ IEEE80211_DUR_DS_LONG_PREAMBLE + \
+ IEEE80211_DUR_DS_SLOW_PLCPHDR + \
+ IEEE80211_DUR_DIFS)
+
enum {
IEEE80211_AUTH_NONE = 0,
IEEE80211_AUTH_OPEN = 1,
diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c
index 7a236d349c5..0334d0aeb77 100644
--- a/sys/net80211/ieee80211_output.c
+++ b/sys/net80211/ieee80211_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_output.c,v 1.1 2004/06/22 22:53:52 millert Exp $ */
+/* $OpenBSD: ieee80211_output.c,v 1.2 2004/12/23 11:54:09 jsg Exp $ */
/* $NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $ */
/*-
@@ -260,6 +260,181 @@ bad:
}
/*
+ * Arguments in:
+ *
+ * paylen: payload length (no FCS, no WEP header)
+ *
+ * hdrlen: header length
+ *
+ * rate: MSDU speed, units 500kb/s
+ *
+ * flags: IEEE80211_F_SHPREAMBLE (use short preamble),
+ * IEEE80211_F_SHSLOT (use short slot length)
+ *
+ * Arguments out:
+ *
+ * d: 802.11 Duration field for data frame,
+ * PLCP Length for data frame,
+ * PLCP Service field for data frame,
+ * 802.11 Duration field for RTS
+ */
+static int
+ieee80211_compute_duration1(int len, uint32_t flags, int rate,
+ struct ieee80211_duration *d)
+{
+ int ack, bitlen, cts, data_dur, remainder;
+
+ /* RTS reserves medium for SIFS | CTS | SIFS | (DATA) | SIFS | ACK
+ * DATA reserves medium for SIFS | ACK
+ */
+
+ bitlen = len * 8;
+
+#if 0
+ /* RTS is always sent at 1 Mb/s. (XXX Really?) */
+ d->d_rts_plcp_len = sizeof(struct ieee80211_frame_rts) * 8;
+#endif
+ d->d_plcp_svc = 0;
+
+ switch (rate) {
+ case 2: /* 1 Mb/s */
+ case 4: /* 2 Mb/s */
+ data_dur = (bitlen * 2) / rate;
+
+ /* 1 - 2 Mb/s WLAN: send ACK/CTS at 1 Mb/s */
+ cts = IEEE80211_DUR_DS_SLOW_CTS;
+ ack = IEEE80211_DUR_DS_SLOW_ACK;
+ break;
+ case 44: /* 22 Mb/s */
+ d->d_plcp_svc = IEEE80211_PLCP_SERVICE_PBCC;
+ /*FALLTHROUGH*/
+ case 11: /* 5.5 Mb/s */
+ case 22: /* 11 Mb/s */
+ remainder = (bitlen * 2) % rate;
+
+ if (remainder != 0)
+ data_dur = (bitlen * 2) / rate + 1;
+ else
+ data_dur = (bitlen * 2) / rate;
+
+ if (rate == 22 && remainder <= 6)
+ d->d_plcp_svc |= IEEE80211_PLCP_SERVICE_LENEXT;
+
+ /* 5.5 - 11 Mb/s WLAN: send ACK/CTS at 2 Mb/s */
+ cts = IEEE80211_DUR_DS_FAST_CTS;
+ ack = IEEE80211_DUR_DS_FAST_ACK;
+ break;
+ default:
+ /* TBD */
+ return -1;
+ }
+
+ d->d_rts_dur = data_dur + 3 * (IEEE80211_DUR_DS_SIFS +
+ IEEE80211_DUR_DS_SHORT_PREAMBLE +
+ IEEE80211_DUR_DS_FAST_PLCPHDR) + cts + ack;
+ d->d_data_dur = data_dur + IEEE80211_DUR_DS_SIFS +
+ 2 * (IEEE80211_DUR_DS_SHORT_PREAMBLE +
+ IEEE80211_DUR_DS_FAST_PLCPHDR) + ack;
+
+ d->d_plcp_len = data_dur;
+
+ if ((flags & IEEE80211_F_SHPREAMBLE) != 0)
+ return 0;
+
+ d->d_rts_dur += 3 * (IEEE80211_DUR_DS_LONG_PREAMBLE -
+ IEEE80211_DUR_DS_SHORT_PREAMBLE) +
+ 3 * (IEEE80211_DUR_DS_SLOW_PLCPHDR -
+ IEEE80211_DUR_DS_FAST_PLCPHDR);
+ d->d_data_dur += 2 * (IEEE80211_DUR_DS_LONG_PREAMBLE -
+ IEEE80211_DUR_DS_SHORT_PREAMBLE) +
+ 2 * (IEEE80211_DUR_DS_SLOW_PLCPHDR -
+ IEEE80211_DUR_DS_FAST_PLCPHDR);
+ return 0;
+}
+
+/*
+ * Arguments in:
+ *
+ * wh: 802.11 header
+ *
+ * paylen: payload length (no FCS, no WEP header)
+ *
+ * rate: MSDU speed, units 500kb/s
+ *
+ * fraglen: fragment length, set to maximum (or higher) for no
+ * fragmentation
+ *
+ * flags: IEEE80211_F_WEPON (hardware adds WEP),
+ * IEEE80211_F_SHPREAMBLE (use short preamble),
+ * IEEE80211_F_SHSLOT (use short slot length)
+ *
+ * Arguments out:
+ *
+ * d0: 802.11 Duration fields (RTS/Data), PLCP Length, Service fields
+ * of first/only fragment
+ *
+ * dn: 802.11 Duration fields (RTS/Data), PLCP Length, Service fields
+ * of first/only fragment
+ */
+int
+ieee80211_compute_duration(struct ieee80211_frame *wh, int paylen,
+ uint32_t flags, int fraglen, int rate, struct ieee80211_duration *d0,
+ struct ieee80211_duration *dn, int *npktp)
+{
+ int rc;
+ int firstlen, hdrlen, lastlen, lastlen0, npkt, overlen;
+
+ if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
+ hdrlen = sizeof(struct ieee80211_frame_addr4);
+ else
+ hdrlen = sizeof(struct ieee80211_frame);
+
+ if ((flags & IEEE80211_F_WEPON) != 0) {
+ overlen = IEEE80211_WEP_TOTLEN + IEEE80211_CRC_LEN;
+#if 0 /* 802.11 lets us extend a fragment's length by the length of
+ * a WEP header, AFTER fragmentation. Might want to disable
+ * this while fancy link adaptations are running.
+ */
+ fraglen -= IEEE80211_WEP_TOTLEN;
+#endif
+#if 0 /* Ditto CRC? */
+ fraglen -= IEEE80211_CRC_LEN;
+#endif
+ } else
+ overlen = IEEE80211_CRC_LEN;
+
+ npkt = paylen / fraglen;
+ lastlen0 = paylen % fraglen;
+
+ if (npkt == 0) {
+ /* no fragments */
+ lastlen = paylen + overlen;
+ } else if (lastlen0 != 0) {
+ /* a short fragment */
+ lastlen = lastlen0 + overlen;
+ npkt++;
+ } else
+ lastlen = fraglen + overlen;
+
+ if (npktp != NULL)
+ *npktp = npkt;
+
+ if (npkt > 1)
+ firstlen = fraglen + overlen;
+ else
+ firstlen = paylen + overlen;
+
+ rc = ieee80211_compute_duration1(firstlen + hdrlen, flags, rate, d0);
+ if (rc == -1)
+ return rc;
+ if (npkt > 1) {
+ *dn = *d0;
+ return 0;
+ }
+ return ieee80211_compute_duration1(lastlen + hdrlen, flags, rate, dn);
+}
+
+/*
* Add a supported rates element id to a frame.
*/
u_int8_t *
diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h
index 181e8f0b26d..384779987c9 100644
--- a/sys/net80211/ieee80211_proto.h
+++ b/sys/net80211/ieee80211_proto.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_proto.h,v 1.2 2004/11/02 02:15:49 reyk Exp $ */
+/* $OpenBSD: ieee80211_proto.h,v 1.3 2004/12/23 11:54:09 jsg Exp $ */
/* $NetBSD: ieee80211_proto.h,v 1.3 2003/10/13 04:23:56 dyoung Exp $ */
/*-
@@ -80,6 +80,9 @@ extern void ieee80211_print_essid(u_int8_t *, int);
extern void ieee80211_dump_pkt(u_int8_t *, int, int, int);
extern int ieee80211_ibss_merge(struct ieee80211com *,
struct ieee80211_node *, u_int64_t);
+extern int ieee80211_compute_duration(struct ieee80211_frame *, int,
+ uint32_t, int, int, struct ieee80211_duration *,
+ struct ieee80211_duration *, int *);
extern const char *ieee80211_state_name[IEEE80211_S_MAX];
#endif /* _NET80211_IEEE80211_PROTO_H_ */