diff options
-rw-r--r-- | sys/net80211/ieee80211.h | 46 | ||||
-rw-r--r-- | sys/net80211/ieee80211_output.c | 177 | ||||
-rw-r--r-- | sys/net80211/ieee80211_proto.h | 5 |
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_ */ |