Fix a bug in ieee80211_compute_duration: the 802.11 Duration field

in an 802.11 unicast data packet is equal to the duration of the
SIFS and Acknowledgement.  That is, the amount of time reserved
*after* the packet has finished transmitting.

Change the arguments to ieee80211_compute_duration: pass the entire
packet length, not just the payload length.  Add a 'debug' argument
to ieee80211_compute_duration and its helper subroutine,
ieee80211_compute_duration1.

If debug != 0, ieee80211_compute_duration printfs its arguments
and several local variables.

In rtw(4), load the 802.11 Duration field with the result from
ieee80211_compute_duration.
This commit is contained in:
dyoung 2004-12-23 06:08:52 +00:00
parent ce08175fd3
commit 24ba04b962
3 changed files with 36 additions and 25 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: rtw.c,v 1.18 2004/12/23 06:03:09 dyoung Exp $ */
/* $NetBSD: rtw.c,v 1.19 2004/12/23 06:08:52 dyoung Exp $ */
/*-
* Copyright (c) 2004, 2005 David Young. All rights reserved.
*
@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: rtw.c,v 1.18 2004/12/23 06:03:09 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: rtw.c,v 1.19 2004/12/23 06:08:52 dyoung Exp $");
#include "bpfilter.h"
@ -2530,10 +2530,11 @@ rtw_start(struct ifnet *ifp)
wh = mtod(m0, struct ieee80211_frame *);
if (ieee80211_compute_duration(wh,
m0->m_pkthdr.len - sizeof(wh),
if (ieee80211_compute_duration(wh, m0->m_pkthdr.len,
ic->ic_flags, ic->ic_fragthreshold,
rate, &stx->stx_d0, &stx->stx_dn, &npkt) == -1) {
rate, &stx->stx_d0, &stx->stx_dn, &npkt,
(sc->sc_if.if_flags & (IFF_DEBUG|IFF_LINK2)) ==
(IFF_DEBUG|IFF_LINK2)) == -1) {
DPRINTF2(sc, ("%s: fail compute duration\n", __func__));
goto post_load_err;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ieee80211_output.c,v 1.18 2004/12/19 08:08:06 dyoung Exp $ */
/* $NetBSD: ieee80211_output.c,v 1.19 2004/12/23 06:08:52 dyoung Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
@ -35,7 +35,7 @@
#ifdef __FreeBSD__
__FBSDID("$FreeBSD: src/sys/net80211/ieee80211_output.c,v 1.10 2004/04/02 23:25:39 sam Exp $");
#else
__KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.18 2004/12/19 08:08:06 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.19 2004/12/23 06:08:52 dyoung Exp $");
#endif
#include "opt_inet.h"
@ -343,26 +343,27 @@ ieee80211_compute_duration1(int len, uint32_t flags, int rate,
return -1;
}
d->d_plcp_len = data_dur;
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;
/* Note that this is the amount of time reserved *after*
* the packet is transmitted: just long enough for a SIFS
* and an ACK.
*/
d->d_data_dur = IEEE80211_DUR_DS_SIFS +
IEEE80211_DUR_DS_SHORT_PREAMBLE + IEEE80211_DUR_DS_FAST_PLCPHDR +
ack;
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);
d->d_rts_dur += 3 * IEEE80211_DUR_DS_PREAMBLE_DIFFERENCE +
3 * IEEE80211_DUR_DS_PLCPHDR_DIFFERENCE;
d->d_data_dur += IEEE80211_DUR_DS_PREAMBLE_DIFFERENCE +
IEEE80211_DUR_DS_PLCPHDR_DIFFERENCE;
return 0;
}
@ -391,18 +392,20 @@ ieee80211_compute_duration1(int len, uint32_t flags, int rate,
* of first/only fragment
*/
int
ieee80211_compute_duration(struct ieee80211_frame *wh, int paylen,
ieee80211_compute_duration(struct ieee80211_frame *wh, int len,
uint32_t flags, int fraglen, int rate, struct ieee80211_duration *d0,
struct ieee80211_duration *dn, int *npktp)
struct ieee80211_duration *dn, int *npktp, int debug)
{
int rc;
int firstlen, hdrlen, lastlen, lastlen0, npkt, overlen;
int firstlen, hdrlen, lastlen, lastlen0, npkt, overlen, paylen;
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);
paylen = len - hdrlen;
if ((flags & IEEE80211_F_PRIVACY) != 0) {
overlen = IEEE80211_WEP_TOTLEN + IEEE80211_CRC_LEN;
#if 0 /* 802.11 lets us extend a fragment's length by the length of
@ -438,10 +441,17 @@ ieee80211_compute_duration(struct ieee80211_frame *wh, int paylen,
else
firstlen = paylen + overlen;
if (debug) {
printf("%s: npkt %d firstlen %d lastlen0 %d lastlen %d "
"fraglen %d overlen %d len %d rate %d flags %08x\n",
__func__, npkt, firstlen, lastlen0, lastlen, fraglen,
overlen, len, rate, flags);
}
rc = ieee80211_compute_duration1(firstlen + hdrlen, flags, rate, d0);
if (rc == -1)
return rc;
if (npkt > 1) {
if (npkt <= 1) {
*dn = *d0;
return 0;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ieee80211_proto.h,v 1.6 2004/12/19 08:08:06 dyoung Exp $ */
/* $NetBSD: ieee80211_proto.h,v 1.7 2004/12/23 06:08:52 dyoung Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
* Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
@ -80,7 +80,7 @@ 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 *);
struct ieee80211_duration *, int *, int);
extern const char *ieee80211_state_name[IEEE80211_S_MAX];
#endif /* _NET80211_IEEE80211_PROTO_H_ */