diff options
Diffstat (limited to 'sys/net80211/ieee80211_output.c')
-rw-r--r-- | sys/net80211/ieee80211_output.c | 177 |
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 * |