#include <stdint.h>
#include <fwp_ac.h>
#include <fwp_conf.h>
+#include <stdbool.h>
/* TODO: Find out the real value and determine what influences it (MTU
* of the interface minus header sizes?). */
/* Default values from 802.11e */
-int aifsn[FWP_AC_NUM] = { 2, 2, 3, 7 };
-int cwmin[FWP_AC_NUM] = { 3, 7, 15, 15 };
+const int aifsn[FWP_AC_NUM] = { 2, 2, 3, 7 };
+const int cwmin[FWP_AC_NUM] = { 3, 7, 15, 15 };
/* Experimental konstants - weight of backoff */
-int pisvejc[FWP_AC_NUM] = { 10, 7, 4, 2 };
+const int pisvejc[FWP_AC_NUM] = { 6, 5, 2, 2 };
+/**
+ * Calucaltes frame duration in microseconds. If the real duration is
+ * represented by a fractional number, the value is rounded up.
+ *
+ * @param length Number of bytes in PSDU.
+ * @param rate_bps Transmit rate of PSDU. The rate should correspond
+ * to other parameters accoring to 19.3.2 (802.11g)
+ * @param erp_ofdm Whether Extended Rate PHY (part of 802.11g) and ERP-OFDM
+ * modulation is used.
+ * @param short_preamble Whether short preamble (HR/DSSS/short) is
+ * used (802.11b)
+ *
+ * @return The number of microseconds or a negative number in case of error.
+ */
+static int frame_duration(uint16_t length, int rate_bps, bool erp_ofdm, bool short_preamble)
+{
+ uint32_t duration_usec;
+
+ if (!erp_ofdm) {
+ duration_usec = ((int64_t)(length) * 8 * SEC_TO_USEC / rate_bps);
+ if (short_preamble) {
+ /* For HR/DSSS/short (2, 5.5 and 11 Mbit,
+ * 802.11b-1999), also for DSSS-OFDM rates and
+ * ERP-PBCC rates.
+ * Preamble sent at 1 MBit, header at 2 Mbit */
+ duration_usec += 72/*bits*/+48/*bits*//2;
+ } else {
+ /* For DSSS PHY (1 and 2 Mbit rates,
+ * 802.11-1999) and for DSS-OFDM and ERP-PBCC
+ * rates. Always sent at 1 MBit */
+ duration_usec += 144/*bits*/+48/*bits*/;
+ }
+ } else {
+#define MBIT_TO_INDEX(rate_Mbps) ((rate_Mbps)/3 - 2)
+ const int N_dbps[] = {
+ [MBIT_TO_INDEX(6)] = 24,
+ [MBIT_TO_INDEX(9)] = 36,
+ [MBIT_TO_INDEX(12)] = 48,
+ [MBIT_TO_INDEX(18)] = 72,
+ [MBIT_TO_INDEX(24)] = 96,
+ [MBIT_TO_INDEX(36)] = 144,
+ [MBIT_TO_INDEX(48)] = 192,
+ [MBIT_TO_INDEX(54)] = 216
+ };
+ int rate_idx = MBIT_TO_INDEX(rate_bps/1000/1000);
+#undef MBIT_TO_INDEX
+ if (rate_idx < 0 ||
+ rate_idx >= sizeof(N_dbps)/sizeof(*N_dbps) ||
+ N_dbps[rate_idx] == 0)
+ return -1;
+
+ duration_usec += 16 + 4; /* Preamble, SIGNAL */
+ int bits =
+ 16 + /* SERVICE */
+ length * 8 +
+ 6; /* tail bits */
+ int Nsym = (bits + N_dbps[rate_idx] - 1)/N_dbps[rate_idx];
+
+ duration_usec += Nsym * 4;
+
+ duration_usec += 6; /* signal extension */
+ }
+ return duration_usec;
+}
+
int fwp_adm_test(struct fwp_ctable *ct)
{
int i;
int utilization = 0;
-
+
+ const int rate = 1*1000*1000;
+ const bool erp_ofdm = false;
+ const bool short_preamble = false;
+
for (i = 0; i < ct->nr_contract; i++) {
int bytes, duration_usec, fragments;
struct fwp_contract *contract = &ct->entry[i].contract;
/* Calculate protocol overhead */
bytes = contract->budget;
- fragments = 1 + bytes / MTU;
+ fragments = (bytes + MTU - 1) / MTU;
+
+ if (fragments == 0)
+ continue;
+
+ const int data_overhead = UDP_HEADER_SIZE + IP_HEADER_SIZE +
+ LLC_HEADER_SIZE + MAC_FCS_SIZE + MAC_FCS_SIZE;
+
+ duration_usec = frame_duration(data_overhead + bytes%MTU, rate, erp_ofdm, short_preamble);
+ duration_usec += frame_duration(data_overhead + MTU, rate, erp_ofdm, short_preamble)*(fragments-1);
- bytes += (UDP_HEADER_SIZE + IP_HEADER_SIZE +
- LLC_HEADER_SIZE + MAC_FCS_SIZE + MAC_FCS_SIZE) * fragments;
- duration_usec = TXTIME_USEC(bytes);
/* Add average backoff - assume there is no collision */
duration_usec += (aifsn[ac] + cwmin[ac]/2)*ASLOTTIME_USEC*fragments*pisvejc[ac];
/* We use ACK and ignore burst */
- duration_usec += (ASIFSTIME_USEC + TXTIME_USEC(ACK_FRAME_SIZE)) * fragments;
- /* TODO: Also add PLCP Preamble 96 us and PLCP header ?? us to every packet (data + ack)*/
+ duration_usec += fragments * (ASIFSTIME_USEC +
+ frame_duration(ACK_FRAME_SIZE, rate, erp_ofdm, short_preamble));
+
/* TODO: If STA-to-STA, multiply it by two. Note that
* AP may use different values for backoff. */
if (contract->period_usec == 0) return FWP_CNT_REJECTED;
utilization += (long long)(duration_usec * 10000) / contract->period_usec;
}
- if (utilization >= 10000 * 95/100) {
+ if (utilization >= 10000 * 96/100) {
return FWP_CNT_REJECTED;
} else {
- return FWP_CNT_NEGOTIATED;
+ return FWP_CNT_NEGOTIATED;
}
}