summaryrefslogtreecommitdiff
path: root/sys/net80211/ieee80211_output.c
diff options
context:
space:
mode:
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 *