summaryrefslogtreecommitdiff
path: root/sys/net80211/ieee80211_output.c
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2004-12-23 11:54:10 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2004-12-23 11:54:10 +0000
commit807cdc363609813a12255e42680c9488df2b7e9e (patch)
treebd8fb5fb02801f81c359d50840a909da38669d9b /sys/net80211/ieee80211_output.c
parente3883b5913fd9691d3a4f794d9679e340a6fb780 (diff)
From dyoung@NetBSD:
Define for more bits in the Service field of the 802.11 PLCP Header. For use by the subroutine ieee80211_compute_duration, add struct ieee80211_duration, and #define a number of microsecond constants used for the transmit timing of 802.11 packets. Add the subroutine ieee80211_compute_duration, which computes for any packet the appropriate 802.11 Duration field, the PLCP Length field, as well as the Duration and Length fields for an RTS frame. atw(4), rtw(4), future drivers, and possibly ath(4) will share ieee80211_compute_duration. ok millert@
Diffstat (limited to 'sys/net80211/ieee80211_output.c')
-rw-r--r--sys/net80211/ieee80211_output.c177
1 files changed, 176 insertions, 1 deletions
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 *