[[email protected]: 802.11 transmit power API (long)]
David Young <[email protected]> Wed, 19 Feb 2003 12:01:34 -0600
| Newsgroups | gmane.network.wireless.bsd.general |
|---|---|
| Message-ID | <[email protected]> |
FYI. ----- Forwarded message from David Young <[email protected]> ----- Date: Tue, 18 Feb 2003 16:49:07 -0600 From: David Young <[email protected]> To: [email protected] Subject: 802.11 transmit power API (long) 802.11 Transmit Power Control API for NetBSD Abstract This document describes a universal API for adjusting the transmit power of 802.11 NICs. Transmit power control (TPC) helps operators re-use channels and meet power output regulations. The TPC API adds ioctls SIOCG80211TPC and SIOCS80211TPC for unitless power adjustments and for relative centibel and milliwatt power adjustments. It is possible to use the API to query the maximum power level and to calibrate power levels. This document contains sections Motivation, API Overview, API Reference, Implementation Details, Future Work, and Examples. Motivation Fine-grained transmit power control (TPC) improves the bandwidth, robustness, and versatility of 802.11 gear. TPC facilitates frequency re-use: it permits many stations to "whisper" to each other in the same space where only a few could "shout," which translates to an increase in network bandwidth. It allows for adaptation to fades caused by precipitation, freezing or melting ice and snow. It permits users to select from a wide range of high-gain antennas while still meeting Effective Isotropic Radiated Power (EIRP) limits set by regulators such as the Federal Communications Commission. TPC improves 802.11 networks. Widely-available 802.11 radios provide TPC to their hosts by different mechanisms. For example, the Cisco/Aironet cards provide a choice of a few milliwatt presets. Compare with the Prism chipset, which provides unitless, continuous power adjustments, provided the host takes over a power-control feedback loop from the firmware. New 802.11 chips coming from Broadcom, Atmel, and ADMtek may support TPC by still different mechanisms. The application programmer faces a huge task if he will support the idiosyncrasies of every radio. It is important, from his perspective, for the kernel to smooth over differences in TPC mechanisms. A desirable TPC API brings the benefits of transmit power control to applications, while it insulates applications from the low-level, driver-specific intricacies. API Overview Commands in the NetBSD TPC API let an application query the transmit power setting, set the transmit power setting, calibrate transmit power settings, and perform simple arithmetic on power settings. The TPC API is chiefly concerned with manipulating a unitless power setting between the highest and the lowest available settings. However, a driver and an application may exchange "hints" in centibels (a centibel is a tenth of a decibel) or in milliwatts whenever there is driver support for such hints. Hints are only adjustments to unitless power settings; they cannot be used for the driver and application to tell each other ANY absolute power level EXCEPT for the maximum power level. The rounding mode for hints is under application control. Power settings are chosen from a compact set of u_int32_ts. The API provides a few guarantees about the unitless settings: 1) the transmit power is a monotonically non-decreasing function of the setting, 2) IEEE80211_TPCSET_MIN is the minimum power setting, and 3) the maximum power setting is at most IEEE80211_TPCSET_MAX. It is an application's responsibility to map u_int32_ts to units of transmit power using, e.g., feedback from receivers, or hints from the driver. Drivers will give more or less unambiguous hints depending on the underlying hardware's capabilities. API Reference Commands are sent to the radio through a raw socket using ioctls SIOCS80211TPC and SIOCS80211TPC, #define SIOCS80211TPC _IOWR('i', 242, struct ieee80211_tpc) #define SIOCG80211TPC _IOWR('i', 243, struct ieee80211_tpc) which both take a pointer to a struct ieee80211_tpc. The kernel sends back results using the same structure. A ieee80211_tpc structure is defined struct ieee80211_tpc { char i_name[IFNAMSIZ]; u_int32_t i_flags; u_int32_t i_set; union { int32_t cb; /* 1/10 dB from maximum */ int32_t mw; /* mW offset from maximum */ } i_hint; }; /* i_flags */ #define IEEE80211_TPC_HINT_CB 0x1 /* use i_hint.cb */ #define IEEE80211_TPC_HINT_MW 0x2 /* use i_hint.mw */ #define IEEE80211_TPC_CONVERT 0x4 /* SIOCG80211TPC: convert arg */ #define IEEE80211_TPC_ROUNDUP 0x8 /* SIOC[GS]80211TPC: round up */ #define IEEE80211_TPC_ROUNDDOWN 0x10 /* SIOC[GS]80211TPC: round down */ #define IEEE80211_TPC_CALIBRATE IEEE80211_TPC_CONVERT /* SIOCS80211TPC: calibrate */ /* i_set */ #define IEEE80211_TPCSET_MIN ((u_int32_t)0) #define IEEE80211_TPCSET_MAX (~TPC_SET_MIN) int s, rc; struct ieee80211_tpc tpc; rc = ioctl(s, SIOCG80211TPC, &tpc); SIOCG80211TPC operates in two modes. The mode is selected by the flag IEEE80211_TPC_CONVERT. In the first mode (no flag) it reads the TPC setting from the driver, and in the second mode (CONVERT flag) it converts a setting given by the application. READ DRIVER POWER SETTING When IEEE80211_TPC_CONVERT is clear, SIOCG80211TPC asks the driver for the current TPC setting. If the flags do not indicate any adjustment with IEEE80211_TPC_HINT_CB or IEEE80211_TPC_HINT_MW, then SIOCG80211TPC writes i_set with the current setting, and returns. If the flags DO indicate an adjustment, SIOCG80211TPC adds i_hint to the current driver setting and rounds the result before writing it to i_set. Finally, SIOCG80211TPC computes the nearest offset from maximum power to i_set and writes it to i_hint. SIOCG80211TPC rounds i_set + i_hint to a driver setting according to the rounding mode given in the flags. The rounding mode is affected by the flags IEEE80211_TPC_ROUNDUP and IEEE80211_TPC_ROUNDDOWN. If either IEEE80211_TPC_ROUNDUP or IEEE80211_TPC_ROUNDDOWN is set, SIOCS80211TPC rounds the adjusted setting accordingly. If both are set, SIOCS80211TPC rounds to the nearest setting. If neither is set, and i_set + i_hint does not fall precisely on a driver setting, SIOCS80211TPC exits with EINVAL. SIOCS80211TPC tells which way it rounded, if it rounded, using either IEEE80211_TPC_ROUNDUP or IEEE80211_TPC_ROUNDDOWN. If the sum of the current setting and i_hint exceeds the driver's maximum setting, and IEEE80211_TPC_ROUNDDOWN is not set, then SIOCG80211TPC will exit with EINVAL. Likewise, SIOCG80211TPC will exit with EINVAL if the sum is below IEEE80211_TPCSET_MIN after adjustment, but IEEE80211_TPC_ROUNDUP is not set. CONVERT APPLICATION POWER SETTING When IEEE80211_TPC_CONVERT is set, SIOCG80211TPC behaves identically as it does when IEEE80211_TPC_CONVERT is clear, EXCEPT that * it treats i_set as the current TPC setting, and * if the caller passes an i_set equal to IEEE80211_TPCSET_MAX and a hint equal to 0, SIOCG80211TPC will try to write the ABSOLUTE magnitude of the maximum output power to i_hint. If the absolute maximum power is not known, SIOCG80211TPC will set errno to ENODEV before returning. The author feels that this special case is justified because it makes the conversion from IEEE80211_TPCSET_MAX informative; the cB/mW offset from IEEE80211_TPCSET_MAX is 0 by definition, so an application never needs to convert it. FLAGS (on entry) IEEE80211_TPC_CONVERT Use i_set instead of the driver's setting. IEEE80211_TPC_HINT_CB Add a cB offset to the setting and return a cB hint. IEEE80211_TPC_HINT_MW Add a milliwatt offset to the setting and return a milliwatt hint. IEEE80211_TPC_ROUNDUP After adjusting by i_hint, round up to a driver power setting. IEEE80211_TPC_ROUNDDOWN After adjusting by i_hint, round down to a driver power setting. (IEEE80211_TPC_HINT_CB and IEEE80211_TPC_HINT_MW are mutually exclusive.) FLAGS (on exit) IEEE80211_TPC_HINT_CB Returning a cB hint (cBm for IEEE80211_TPCSET_MAX). IEEE80211_TPC_HINT_MW Returning a milliwatt hint. IEEE80211_TPC_ROUNDUP After adjusting by i_hint, rounded up. IEEE80211_TPC_ROUNDDOWN After adjusting by i_hint, rounded down. (IEEE80211_TPC_ROUNDUP and IEEE80211_TPC_ROUNDDOWN are mutually exclusive.) (IEEE80211_TPC_HINT_CB and IEEE80211_TPC_HINT_MW are mutually exclusive.) RETURN VALUE SIOCG80211TPC sets errno to EINVAL if the application sets conflicting flags. SIOCG80211TPC sets errno to ENODEV if the application sets a hint flag which the driver does not support. SIOCG80211TPC sets a hint flag before returning if and only if it produced valid hints. Applications should always check the hint flags before interpreting the hint fields, because the flags may change from their values on entry. Drivers support hints optionally. int s, rc; struct ieee80211_tpc tpc; rc = ioctl(s, SIOCS80211TPC, &tpc); WRITE DRIVER POWER SETTING After adjusting i_set by any hint in i_hint, and rounding it according to the flags, SIOCS80211TPC writes a new TPC setting to the hardware. Rounding is affected by the flags IEEE80211_TPC_ROUNDUP and IEEE80211_TPC_ROUNDDOWN. If either IEEE80211_TPC_ROUNDUP or IEEE80211_TPC_ROUNDDOWN is set, SIOCS80211TPC rounds accordingly. If both are set, SIOCS80211TPC rounds to the nearest setting. If neither is set, SIOCS80211TPC exits with EINVAL if an adjustment does not result precisely in a driver setting. If a setting exceeds the driver's maximum setting, even after any adjustments, and IEEE80211_TPC_ROUNDDOWN is not set, then SIOCS80211TPC will exit with EINVAL. Likewise, SIOCS80211TPC will exit with EINVAL if a setting is below IEEE80211_TPCSET_MIN after adjustment, and IEEE80211_TPC_ROUNDUP is not set. CALIBRATE An application may calibrate the driver's unitless power settings using the flag IEEE80211_TPC_CALIBRATE. An application associates a power setting in i_set with an offset from maximum power in i_hint by setting flag IEEE80211_TPC_CALIBRATE. An application calibrates the absolute maximum power by writing its setting (or IEEE80211_TPCSET_MAX) to i_set and writing the absolute power to i_hint. When IEEE80211_TPC_CALIBRATE is set, ioctl will not change the current power setting. An application deletes the association with power setting i_set by using IEEE80211_TPC_CALIBRATE without a hint. RETURN VALUE When SIOCS80211TPC is called without IEEE80211_TPC_CALIBRATE, it writes the driver power setting it adopts into i_set. It writes a hint, as appropriate, into i_hint, and sets the flags accordingly. A driver may protect its calibrations from deletion by returning ENODEV. When an application tries to overwrite an existing calibration, ioctl returns EEXIST. Calibrations must be monotonically non-decreasing: if a driver tries to make a setting/level association that is out of order with existing associations, ioctl returns EINVAL. If a driver does not permit its own calibrations to be deleted, it returns ENODEV. If a non-root user attempts to calibrate power settings, ioctl returns EPERM. Implementation Details The maximum power level setting may change from channel to channel. That is, if i_set = 25 is acceptable for channel 1, it may not be acceptable for channel 3, where i_set = 20 is the maximum. When the driver changes channel, it should select the minimum of the power level last set by an ioctl and the maximum power allowed on the new channel. A driver should strive for the graph of power versus unitless power setting to be everywhere increasing, without any "plateaus". Future Work If there are good arguments for it, the TPC API should let apps set higher power levels than the factory calibrations. It is important to consider the impact of "turning it up to eleven" on other users of the spectrum (think about out-of-band emissions). Also consider an operator's legal liability, and the affects (if any) on a radio from operating its outside tolerances. The API should provide for applications to take over the automatic level control (ALC) loop from drivers. To support TPC decisions, receivers should tell received signal strength indications to transmitters. Perhaps a protocol for this is coming out of the IEEE? It is useful to label direct routes with TPC information, so that IP messages can be sent on their next hop with the least necessary power. Examples /* Here is the way you find the absolute minimum and maximum * power. * * First, find out the absolute maximum output power in cBm, * if it is available. */ int32_t maxpow, minpow; struct ieee80211_tpc tpc; tpc.i_flags = IEEE80211_TPC_CONVERT | IEEE80211_TPC_HINT_CB; tpc.i_set = IEEE80211_TPCSET_MAX; tpc.i_hint.db = 0; rc = ioctl(s, SIOCG80211TPC, &tpc); if (rc != 0) { if (errno == ENODEV) { printf("Maximum dBm is unknown.\n"); exit(0); } err(EXIT_FAILURE, "ioctl(, SIOCG80211TPC, )"); } if ((tpc.i_flags & IEEE80211_TPC_HINT_CB) == 0) { printf("Maximum dBm is unknown.\n"); exit(0); } maxpow = tpc.i_hint; printf("%d.%01d dBm maximum power\n", maxpow / 10, maxpow % 10); /* Find out the minimum output power as a cB difference from * the maximum. Add it to the absolute maximum to get the absolute * minimum. */ tpc.i_flags = IEEE80211_TPC_CONVERT | IEEE80211_TPC_HINT_CB; tpc.i_set = IEEE80211_TPCSET_MIN; tpc.i_hint.db = 0; rc = ioctl(s, SIOCG80211TPC, &tpc); if (rc != 0) err(EXIT_FAILURE, "ioctl(, SIOCG80211TPC, )"); if ((tpc.i_flags & IEEE80211_TPC_HINT_CB) == 0) { printf("Minimum dBm is unknown.\n"); exit(0); } minpow = maxpow + tpc.i_hint; printf("%d.%01d dBm minimum power\n", minpow / 10, minpow % 10); /* Set power to half maximum power. */ tpc.i_flags = IEEE80211_TPC_HINT_CB tpc.i_set = IEEE80211_TPCSET_MAX; tpc.i_hint.db = -30; rc = ioctl(s, SIOCS80211TPC, &tpc); if (rc != 0) err(EXIT_FAILURE, "ioctl(, SIOCG80211TPC, )"); /* Let's see how close we got. */ if ((tpc.i_flags & IEEE80211_TPC_HINT_CB) != 0) { printf("%d.%.01d dBm from 1/2 maximum power\n", (30 + minpow) / 10, minpow % 10); } -- David Young OJC Technologies [email protected] Engineering from the Right Brain Urbana, IL * (217) 278-3933 ----- End forwarded message ----- -- David Young OJC Technologies [email protected] Engineering from the Right Brain Urbana, IL * (217) 278-3933 -- *bsd wireless list, a bawug thing <http://www.bawug.org/> [un]subscribe: http://lists.bawug.org/mailman/listinfo/bsd-wireless/