Merge branch 'master' into net80211-update
authorRui Paulo <rpaulo@FreeBSD.org>
Tue, 13 Apr 2010 18:34:34 +0000 (19:34 +0100)
committerRui Paulo <rpaulo@FreeBSD.org>
Tue, 13 Apr 2010 18:34:34 +0000 (19:34 +0100)
302 files changed:
etc/Makefile
etc/rc.d/netif
etc/rc.subr
etc/regdomain.xml [new file with mode: 0644]
sbin/ifconfig/Makefile
sbin/ifconfig/ifclone.c
sbin/ifconfig/ifconfig.8
sbin/ifconfig/ifconfig.c
sbin/ifconfig/ifconfig.h
sbin/ifconfig/ifieee80211.c
sbin/ifconfig/ifmedia.c
sbin/ifconfig/regdomain.c [new file with mode: 0644]
sbin/ifconfig/regdomain.h [new file with mode: 0644]
sys/Makefile
sys/bus/pccard/pccarddevs
sys/bus/pccard/pccarddevs.h
sys/conf/files
sys/conf/kmod.mk
sys/conf/options
sys/config/GENERIC
sys/config/LINT
sys/config/WIRELESS [new file with mode: 0644]
sys/dev/netif/Makefile
sys/dev/netif/ath/ath/Makefile
sys/dev/netif/ath/ath/if_ath.c
sys/dev/netif/ath/ath/if_ath_pci.c
sys/dev/netif/ath/ath/if_athioctl.h
sys/dev/netif/ath/ath/if_athrate.h
sys/dev/netif/ath/ath/if_athvar.h
sys/dev/netif/ath/hal/Makefile
sys/dev/netif/ath/hal/ah_osdep.c
sys/dev/netif/ath/hal/ah_osdep.h
sys/dev/netif/ath/hal/ath_hal/ah.c
sys/dev/netif/ath/hal/ath_hal/ah.h
sys/dev/netif/ath/hal/ath_hal/ah_debug.h
sys/dev/netif/ath/hal/ath_hal/ah_decode.h
sys/dev/netif/ath/hal/ath_hal/ah_desc.h
sys/dev/netif/ath/hal/ath_hal/ah_devid.h
sys/dev/netif/ath/hal/ath_hal/ah_eeprom.h
sys/dev/netif/ath/hal/ath_hal/ah_eeprom_v1.c
sys/dev/netif/ath/hal/ath_hal/ah_eeprom_v1.h
sys/dev/netif/ath/hal/ath_hal/ah_eeprom_v14.c
sys/dev/netif/ath/hal/ath_hal/ah_eeprom_v14.h
sys/dev/netif/ath/hal/ath_hal/ah_eeprom_v3.c
sys/dev/netif/ath/hal/ath_hal/ah_eeprom_v3.h
sys/dev/netif/ath/hal/ath_hal/ah_eeprom_v4k.c [copied from sys/dev/netif/ath/hal/ath_hal/ah_eeprom_v14.c with 80% similarity]
sys/dev/netif/ath/hal/ath_hal/ah_eeprom_v4k.h [new file with mode: 0644]
sys/dev/netif/ath/hal/ath_hal/ah_internal.h
sys/dev/netif/ath/hal/ath_hal/ah_regdomain.c
sys/dev/netif/ath/hal/ath_hal/ah_soc.h
sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210.h
sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_attach.c
sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_beacon.c
sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_interrupts.c
sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_keycache.c
sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_misc.c
sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_phy.c
sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_power.c
sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_recv.c
sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_reset.c
sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210_xmit.c
sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210desc.h
sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210phy.h
sys/dev/netif/ath/hal/ath_hal/ar5210/ar5210reg.h
sys/dev/netif/ath/hal/ath_hal/ar5210/ar5k_0007.ini
sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211.h
sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_attach.c
sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_beacon.c
sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_interrupts.c
sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_keycache.c
sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_misc.c
sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_phy.c
sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_power.c
sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_recv.c
sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_reset.c
sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211_xmit.c
sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211desc.h
sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211phy.h
sys/dev/netif/ath/hal/ath_hal/ar5211/ar5211reg.h
sys/dev/netif/ath/hal/ath_hal/ar5211/boss.ini
sys/dev/netif/ath/hal/ath_hal/ar5212/ar2316.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar2317.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar2413.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar2425.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5111.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5112.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212.h
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212.ini
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_ani.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_attach.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_beacon.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_eeprom.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_gpio.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_interrupts.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_keycache.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_misc.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_phy.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_power.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_recv.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_reset.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_rfgain.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212_xmit.c
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212desc.h
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212phy.h
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5212reg.h
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5311reg.h
sys/dev/netif/ath/hal/ath_hal/ar5212/ar5413.c
sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312.h
sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312_attach.c
sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312_eeprom.c
sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312_gpio.c
sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312_interrupts.c
sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312_misc.c
sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312_power.c
sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312_reset.c
sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312phy.h
sys/dev/netif/ath/hal/ath_hal/ar5312/ar5312reg.h
sys/dev/netif/ath/hal/ath_hal/ar5312/ar5315_gpio.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar2133.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416.h
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416.ini
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_ani.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_attach.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_beacon.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_cal.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_cal.h
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_cal_adcdc.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_cal_adcgain.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_cal_iq.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_eeprom.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_gpio.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_interrupts.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_keycache.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_misc.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_phy.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_power.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_recv.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_reset.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416_xmit.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416desc.h
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416phy.h
sys/dev/netif/ath/hal/ath_hal/ar5416/ar5416reg.h
sys/dev/netif/ath/hal/ath_hal/ar5416/ar9160.ini
sys/dev/netif/ath/hal/ath_hal/ar5416/ar9160_attach.c
sys/dev/netif/ath/hal/ath_hal/ar5416/ar9280.c [new file with mode: 0644]
sys/dev/netif/ath/hal/ath_hal/ar5416/ar9280.h [new file with mode: 0644]
sys/dev/netif/ath/hal/ath_hal/ar5416/ar9280_attach.c [new file with mode: 0644]
sys/dev/netif/ath/hal/ath_hal/ar5416/ar9280v1.ini [new file with mode: 0644]
sys/dev/netif/ath/hal/ath_hal/ar5416/ar9280v2.ini [new file with mode: 0644]
sys/dev/netif/ath/hal/ath_hal/ar5416/ar9285.c [new file with mode: 0644]
sys/dev/netif/ath/hal/ath_hal/ar5416/ar9285.h [new file with mode: 0644]
sys/dev/netif/ath/hal/ath_hal/ar5416/ar9285.ini [new file with mode: 0644]
sys/dev/netif/ath/hal/ath_hal/ar5416/ar9285_attach.c [new file with mode: 0644]
sys/dev/netif/ath/hal/ath_hal/ar5416/ar9285_reset.c [new file with mode: 0644]
sys/dev/netif/ath/hal/ath_hal/ar5416/ar9285v2.ini [new file with mode: 0644]
sys/dev/netif/ath/rate_sample/Makefile
sys/dev/netif/ath/rate_sample/sample.c
sys/dev/netif/ath/rate_sample/sample.h
sys/dev/netif/ral/if_ral_pci.c
sys/dev/netif/ral/rt2560.c
sys/dev/netif/ral/rt2560reg.h
sys/dev/netif/ral/rt2560var.h
sys/dev/netif/ral/rt2661.c
sys/dev/netif/ral/rt2661reg.h
sys/dev/netif/ral/rt2661var.h
sys/dev/netif/wi/Makefile
sys/dev/netif/wi/if_wavelan_ieee.h [new file with mode: 0644]
sys/dev/netif/wi/if_wi.c
sys/dev/netif/wi/if_wi_pccard.c
sys/dev/netif/wi/if_wi_pci.c
sys/dev/netif/wi/if_wireg.h
sys/dev/netif/wi/if_wivar.h
sys/dev/netif/wi/spectrum24t_cf.h [deleted file]
sys/firmware/Makefile [new file with mode: 0644]
sys/kern/kern_condvar.c [new file with mode: 0644]
sys/kern/kern_linker.c
sys/kern/subr_firmware.c [new file with mode: 0644]
sys/kern/uipc_mbuf.c
sys/libkern/memmove.c [new file with mode: 0644]
sys/libkern/strcasecmp.c [copied from sys/net/if_clone.h with 53% similarity]
sys/net/bpf.c
sys/net/faith/if_faith.c
sys/net/gif/if_gif.c
sys/net/if.c
sys/net/if_clone.c
sys/net/if_clone.h
sys/net/if_media.h
sys/net/if_var.h
sys/netinet6/in6.c
sys/netproto/802_11/Makefile
sys/netproto/802_11/_ieee80211.h
sys/netproto/802_11/ieee80211.h
sys/netproto/802_11/ieee80211_action.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_adhoc.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_ageq.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_amrr.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_crypto.h
sys/netproto/802_11/ieee80211_dfs.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_dragonfly.h
sys/netproto/802_11/ieee80211_hostap.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_ht.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_input.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_ioctl.h
sys/netproto/802_11/ieee80211_mesh.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_monitor.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_node.h
sys/netproto/802_11/ieee80211_phy.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_power.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_proto.h
sys/netproto/802_11/ieee80211_radiotap.h
sys/netproto/802_11/ieee80211_ratectl.h
sys/netproto/802_11/ieee80211_regdomain.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_rssadapt.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_scan.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_sta.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_superg.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_tdma.h [new file with mode: 0644]
sys/netproto/802_11/ieee80211_var.h
sys/netproto/802_11/ieee80211_wds.h [new file with mode: 0644]
sys/netproto/802_11/if_wavelan_ieee.h [deleted file]
sys/netproto/802_11/wlan/Makefile
sys/netproto/802_11/wlan/ieee80211.c
sys/netproto/802_11/wlan/ieee80211_action.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_adhoc.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_ageq.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_amrr.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_crypto.c
sys/netproto/802_11/wlan/ieee80211_crypto_none.c
sys/netproto/802_11/wlan/ieee80211_ddb.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_dfs.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_dragonfly.c
sys/netproto/802_11/wlan/ieee80211_hostap.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_ht.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_hwmp.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_input.c
sys/netproto/802_11/wlan/ieee80211_ioctl.c
sys/netproto/802_11/wlan/ieee80211_mesh.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_monitor.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_node.c
sys/netproto/802_11/wlan/ieee80211_output.c
sys/netproto/802_11/wlan/ieee80211_phy.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_power.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_proto.c
sys/netproto/802_11/wlan/ieee80211_radiotap.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_ratectl.c
sys/netproto/802_11/wlan/ieee80211_ratectl_none.c
sys/netproto/802_11/wlan/ieee80211_regdomain.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_rssadapt.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_scan.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_scan_sta.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_sta.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_superg.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_tdma.c [new file with mode: 0644]
sys/netproto/802_11/wlan/ieee80211_wds.c [new file with mode: 0644]
sys/netproto/802_11/wlan_acl/Makefile
sys/netproto/802_11/wlan_acl/ieee80211_acl.c
sys/netproto/802_11/wlan_ccmp/Makefile
sys/netproto/802_11/wlan_ccmp/ieee80211_crypto_ccmp.c
sys/netproto/802_11/wlan_ratectl/Makefile [deleted file]
sys/netproto/802_11/wlan_ratectl/amrr/Makefile [deleted file]
sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_amrr_param.h [deleted file]
sys/netproto/802_11/wlan_ratectl/amrr/ieee80211_ratectl_amrr.c [deleted file]
sys/netproto/802_11/wlan_ratectl/onoe/Makefile [deleted file]
sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_onoe_param.h [deleted file]
sys/netproto/802_11/wlan_ratectl/onoe/ieee80211_ratectl_onoe.c [deleted file]
sys/netproto/802_11/wlan_ratectl/sample/Makefile [deleted file]
sys/netproto/802_11/wlan_ratectl/sample/ieee80211_ratectl_sample.c [deleted file]
sys/netproto/802_11/wlan_ratectl/sample/ieee80211_sample_param.h [deleted file]
sys/netproto/802_11/wlan_tkip/Makefile
sys/netproto/802_11/wlan_tkip/ieee80211_crypto_tkip.c
sys/netproto/802_11/wlan_wep/Makefile
sys/netproto/802_11/wlan_wep/ieee80211_crypto_wep.c
sys/netproto/802_11/wlan_xauth/Makefile
sys/netproto/802_11/wlan_xauth/ieee80211_xauth.c
sys/sys/condvar.h [new file with mode: 0644]
sys/sys/eventhandler.h
sys/sys/fbsd_firmware.h [new file with mode: 0644]
sys/sys/libkern.h
sys/sys/linker.h
sys/sys/mbuf.h
sys/sys/mount.h
sys/sys/socket.h
sys/sys/sockio.h
sys/tools/fw_stub.awk [new file with mode: 0644]
usr.sbin/802_11/Makefile
usr.sbin/802_11/hostapd/Makefile
usr.sbin/802_11/hostapd/driver_dragonfly.c
usr.sbin/802_11/hostapd/hostapd.8
usr.sbin/802_11/hostapd/hostapd.conf.5
usr.sbin/802_11/l2_packet.c
usr.sbin/802_11/wpa_passphrase/Makefile [new file with mode: 0644]
usr.sbin/802_11/wpa_passphrase/wpa_passphrase.8 [new file with mode: 0644]
usr.sbin/802_11/wpa_supplicant/Makefile
usr.sbin/802_11/wpa_supplicant/Packet32.c
usr.sbin/802_11/wpa_supplicant/Packet32.h
usr.sbin/802_11/wpa_supplicant/driver_dragonfly.c
usr.sbin/802_11/wpa_supplicant/driver_wired.c [new file with mode: 0644]
usr.sbin/802_11/wpa_supplicant/driver_wired.c.patch [deleted file]
usr.sbin/802_11/wpa_supplicant/events.c.patch [deleted file]
usr.sbin/802_11/wpa_supplicant/ntddndis.h
usr.sbin/802_11/wpa_supplicant/wpa_supplicant.8
usr.sbin/802_11/wpa_supplicant/wpa_supplicant.conf.5

index ef3e258..d18f284 100644 (file)
@@ -32,7 +32,7 @@ BIN1= amd.map auth.conf \
        inetd.conf login.access login.conf \
        motd modems netconfig networks newsyslog.conf \
        nscd.conf pf.conf phones printcap profile \
-       remote sensorsd.conf \
+       regdomain.xml remote sensorsd.conf \
        shells sysctl.conf syslog.conf usbd.conf \
        etc.${MACHINE_ARCH}/ttys
 .if defined(BINARY_UPGRADE) # location of these depends on upgrade method
index bf2ea1c..4c18ee6 100644 (file)
@@ -158,6 +158,7 @@ ifn_start()
        ifconfig_up ${ifn} && cfg=0
        ifalias_up ${ifn} && cfg=0
        ipx_up ${ifn} && cfg=0
+       childif_create ${ifn} && cfg=0
 
        return $cfg
 }
@@ -174,9 +175,92 @@ ifn_stop()
        ifalias_down ${ifn} && cfg=0
        ifconfig_down ${ifn} && cfg=0
        ifscript_down ${ifn} && cfg=0
+       childif_destroy ${ifn} && cfg=0
 
        return $cfg
 }
 
+# get_if_var if var [default]
+#      Return the value of the pseudo-hash corresponding to $if where
+#      $var is a string containg the sub-string "IF" which will be
+#      replaced with $if after the characters defined in _punct are
+#      replaced with '_'. If the variable is unset, replace it with
+#      $default if given.
+get_if_var()
+{
+       local _if _punct _var _default prefix suffix
+
+       if [ $# -ne 2 -a $# -ne 3 ]; then
+               err 3 'USAGE: get_if_var name var [default]'
+       fi
+
+       _if=$1
+       _punct=". - / +"
+       for _punct_c in $_punct; do
+               _if=`ltr ${_if} ${_punct_c} '_'`
+       done
+       _var=$2
+       _default=$3
+
+       prefix=${_var%%IF*}
+       suffix=${_var##*IF}
+       eval echo \${${prefix}${_if}${suffix}-${_default}}
+}
+
+# childif_create
+#      Create and configure child interfaces.  Return 0 if child
+#      interfaces are created.
+#
+childif_create()
+{
+       local cfg child child_vlans child_wlans create_args debug_flags ifn i
+       cfg=1
+       ifn=$1
+
+       # Create wireless interfaces
+       child_wlans=`get_if_var $ifn wlans_IF`
+
+       for child in ${child_wlans}; do
+               create_args="wlandev $ifn `get_if_var $child create_args_IF`"
+               debug_flags="`get_if_var $child wlandebug_IF`"
+
+               if expr $child : 'wlan[0-9][0-9]*$' >/dev/null 2>&1; then
+                       ifconfig $child create ${create_args} && cfg=0
+                       if [ -n "${debug_flags}" ]; then
+                               wlandebug -i $child ${debug_flags}
+                       fi
+               else
+                       i=`ifconfig wlan create ${create_args}`
+                       if [ -n "${debug_flags}" ]; then
+                               wlandebug -i $i ${debug_flags}
+                       fi
+                       ifconfig $i name $child && cfg=0
+               fi
+               ifn_start $child
+       done
+
+       return ${cfg}
+}
+
+# childif_destroy
+#      Destroy child interfaces.
+#
+childif_destroy()
+{
+       local cfg child child_vlans child_wlans ifn
+       cfg=1
+
+       child_wlans=`get_if_var $ifn wlans_IF`
+       for child in ${child_wlans}; do
+               if ! `ifconfig -n $child > /dev/null 2>&1`; then
+                       continue
+               fi
+               ifn_stop $child
+               ifconfig $child destroy && cfg=0
+       done
+
+       return ${cfg}
+}
+
 load_rc_config $name
 run_rc_command $*
index 8ab3639..7b0e295 100644 (file)
@@ -969,6 +969,29 @@ run_rc_script()
        esac
 }
 
+# ltr str src dst
+#      Change every $src in $str to $dst.
+#      Useful when /usr is not yet mounted and we cannot use tr(1), sed(1) nor
+#      awk(1).
+ltr()
+{
+       local _str _src _dst _out _com
+       _str=$1
+       _src=$2
+       _dst=$3
+       _out=""
+
+       IFS=${_src}
+       for _com in ${_str}; do
+               if [ -z "${_out}" ]; then
+                       _out="${_com}"
+               else
+                       _out="${_out}${_dst}${_com}"
+               fi
+       done
+       echo "${_out}"
+}
+
 #
 # load_rc_config
 #      Source in the configuration file for a given command.
diff --git a/etc/regdomain.xml b/etc/regdomain.xml
new file mode 100644 (file)
index 0000000..2ca74b9
--- /dev/null
@@ -0,0 +1,1754 @@
+<!--
+  Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
+  All rights reserved.
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions
+  are met:
+  1. Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+  2. Redistributions in binary form must reproduce the above copyright
+     notice, this list of conditions and the following disclaimer in the
+     documentation and/or other materials provided with the distribution.
+  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  $FreeBSD: head/etc/regdomain.xml 187846 2009-01-28 19:25:51Z sam $
+  $DragonFly$
+-->
+
+<regulatory-data>
+
+<!-- Regdomain/SKU definitions -->
+
+<regulatory-domains>
+
+<!--
+  DEBUG holds all available channels; the driver/device
+  defines what the capabilities and tx power caps are.
+  Regdomain code gets this information with the
+  IEEE80211_IOC_DRIVERCAPS ioctl.
+-->
+<rd id="debug">
+  <name>DEBUG</name>
+  <sku>0x1ff</sku>
+</rd>
+
+<rd id="fcc">
+  <name>FCC</name>
+  <sku>0x10</sku>
+  <defcc ref="US"/>
+  <netband mode="11b">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_B</flags>
+    </band>
+  </netband>
+  <netband mode="11g">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+  </netband>
+  <netband mode="11a">
+    <band>
+      <freqband ref="F1_5180_5240"/>
+      <maxpower>17</maxpower>
+    </band>
+    <band>
+      <freqband ref="F1_5745_5805"/>
+      <maxpower>23</maxpower>
+    </band>
+    <band>
+      <freqband ref="F1_5825_5825"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+  </netband>
+  <netband mode="11ng">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+  </netband>
+  <netband mode="11na">
+    <band>
+      <freqband ref="F1_5180_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5180_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+  </netband>
+</rd>
+
+<!-- FCC3 is FCC w/ DFS on Upper-UNI -->
+
+<rd id="fcc3">
+  <name>FCC3</name>
+  <sku>0x3a</sku>
+  <netband mode="11b">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_B</flags>
+    </band>
+  </netband>
+  <netband mode="11g">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+  </netband>
+  <netband mode="11a">
+    <band>
+      <freqband ref="F1_5180_5240"/>
+      <maxpower>17</maxpower>
+    </band>
+    <band>
+      <freqband ref="F1_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5825_5825"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+  </netband>
+  <netband mode="11ng">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+  </netband>
+  <netband mode="11na">
+    <band>
+      <freqband ref="F1_5180_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5180_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+  </netband>
+</rd>
+
+<!-- FCC4 is 2.4GHz FCC w/ Public Safety Band (PSB) -->
+
+<rd id="fcc4">
+  <name>FCC4</name>
+  <sku>0x12</sku>
+  <netband mode="11b">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_B</flags>
+    </band>
+  </netband>
+  <netband mode="11g">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+  </netband>
+  <netband mode="11a">
+    <band>
+      <freqband ref="F1_4950_4980"/>
+      <maxpower>23</maxpower>
+    </band>
+    <band>
+      <freqband ref="F1_4945_4985_10"/>
+      <maxpower>27</maxpower>
+    </band>
+    <band>
+      <freqband ref="F1_4942_4987_5"/>
+      <maxpower>30</maxpower>
+    </band>
+  </netband>
+  <netband mode="11ng">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+  </netband>
+</rd>
+
+<rd id="japan">
+  <name>JAPAN</name>
+  <sku>0x40</sku>
+  <defcc ref="JP"/>
+  <netband mode="11b">
+    <band>
+      <freqband ref="F1_2412_2472"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_B</flags>
+    </band>
+    <band>
+      <freqband ref="F1_2484_2484"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_B</flags>
+    </band>
+  </netband>
+  <netband mode="11g">
+    <band>
+      <freqband ref="F1_2412_2472"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+  </netband>
+  <netband mode="11a">
+    <band>
+      <freqband ref="F1_5180_5240"/>
+      <maxpower>23</maxpower>
+    </band>
+    <band>
+      <freqband ref="F1_5260_5320"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+  </netband>
+  <netband mode="11ng">
+    <band>
+      <freqband ref="F1_2412_2472"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_2412_2472"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+  </netband>
+  <netband mode="11na">
+    <band>
+      <freqband ref="F1_5180_5240"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5180_5240"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5260_5320"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5260_5320"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+  </netband>
+</rd>
+
+<rd id="etsi">
+  <name>ETSI</name>
+  <sku>0x30</sku>
+  <netband mode="11b">
+    <band>
+       <freqband ref="F1_2412_2472"/>
+       <maxpower>30</maxpower>
+       <flags>IEEE80211_CHAN_B</flags>
+    </band>
+  </netband>
+  <netband mode="11g">
+    <band>
+      <freqband ref="F1_2412_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+  </netband>
+  <netband mode="11a">
+    <band>
+      <freqband ref="F1_5180_5240"/>
+      <maxpower>17</maxpower>
+    </band>
+    <band>
+      <freqband ref="F1_5260_5320"/>
+      <maxpower>24</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5500_5700"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+  </netband>
+  <netband mode="11ng">
+    <band>
+      <freqband ref="F1_2412_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+  </netband>
+  <netband mode="11na">
+    <band>
+      <freqband ref="F1_5180_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5180_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5260_5320"/>
+      <maxpower>24</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5260_5320"/>
+      <maxpower>24</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5500_5700"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5500_5680"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+  </netband>
+</rd>
+
+<!-- ETSI w/o HT40 in 5GHz -->
+
+<rd id="etsi2">
+  <name>ETSI2</name>
+  <sku>0x32</sku>
+  <netband mode="11b">
+    <band>
+      <freqband ref="F1_2412_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_B</flags>
+    </band>
+  </netband>
+  <netband mode="11g">
+    <band>
+      <freqband ref="F1_2412_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+  </netband>
+  <netband mode="11a">
+    <band>
+      <freqband ref="F1_5120_5240"/>
+      <maxpower>17</maxpower>
+    </band>
+    <band>
+      <freqband ref="F1_5260_5320"/>
+      <maxpower>24</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5500_5700"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+  </netband>
+  <netband mode="11ng">
+    <band>
+      <freqband ref="F1_2412_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+  </netband>
+  <netband mode="11na">
+    <band>
+      <freqband ref="F1_5120_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5260_5320"/>
+      <maxpower>24</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5500_5700"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+  </netband>
+</rd>
+
+<!-- ETSI - channel 36 -->
+
+<rd id="etsi3">
+  <name>ETSI3</name>
+  <sku>0x33</sku>
+  <defcc ref="RO"/>
+  <netband mode="11b">
+    <band>
+      <freqband ref="F1_2412_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_B</flags>
+    </band>
+  </netband>
+  <netband mode="11g">
+    <band>
+      <freqband ref="F1_2412_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+  </netband>
+  <netband mode="11a">
+    <band>
+      <freqband ref="F1_5200_5240"/>
+      <maxpower>17</maxpower>
+    </band>
+    <band>
+      <freqband ref="F1_5280_5320"/>
+      <maxpower>24</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5500_5700"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+  </netband>
+  <netband mode="11ng">
+    <band>
+      <freqband ref="F1_2412_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+  </netband>
+  <netband mode="11na">
+    <band>
+      <freqband ref="F1_5200_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5200_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5280_5320"/>
+      <maxpower>24</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5280_5320"/>
+      <maxpower>24</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5500_5700"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5500_5680"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+  </netband>
+</rd>
+
+<rd id="apac">
+  <name>APAC</name>
+  <sku>0x50</sku>
+  <netband mode="11b">
+    <band>
+      <freqband ref="F1_2412_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_B</flags>
+    </band>
+  </netband>
+  <netband mode="11g">
+    <band>
+      <freqband ref="F1_2412_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+  </netband>
+  <netband mode="11a">
+    <band>
+      <freqband ref="F1_5180_5240"/>
+      <maxpower>17</maxpower>
+    </band>
+    <band>
+      <freqband ref="F1_5260_5320"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5745_5805"/>
+      <maxpower>23</maxpower>
+    </band>
+    <band>
+      <freqband ref="F1_5825_5825"/>
+      <maxpower>23</maxpower>
+    </band>
+  </netband>
+  <netband mode="11ng">
+    <band>
+      <freqband ref="F1_2412_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+  </netband>
+  <netband mode="11na">
+    <band>
+      <freqband ref="F1_5180_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5180_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5260_5320"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5260_5320"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+  </netband>
+</rd>
+
+<!-- APAC w/ DFS on Mid-band -->
+
+<rd id="apac2">
+  <name>APAC2</name>
+  <sku>0x51</sku>
+  <netband mode="11b">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_B</flags>
+    </band>
+  </netband>
+  <netband mode="11g">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+  </netband>
+  <netband mode="11a">
+    <band>
+      <freqband ref="F1_5120_5240"/>
+      <maxpower>17</maxpower>
+    </band>
+    <band>
+      <freqband ref="F1_5260_5320"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5745_5805"/>
+      <maxpower>23</maxpower>
+    </band>
+    <band>
+      <freqband ref="F1_5825_5825"/>
+      <maxpower>23</maxpower>
+    </band>
+  </netband>
+  <netband mode="11ng">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+  </netband>
+  <netband mode="11na">
+    <band>
+      <freqband ref="F1_5120_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5120_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5260_5320"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5260_5320"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+  </netband>
+</rd>
+
+<!-- APAC w/o ISM band -->
+
+<rd id="apac3">
+  <name>APAC3</name>
+  <sku>0x5d</sku>
+  <netband mode="11b">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_B</flags>
+    </band>
+  </netband>
+  <netband mode="11g">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+  </netband>
+  <netband mode="11a">
+    <band>
+      <freqband ref="F1_5180_5240"/>
+      <maxpower>17</maxpower>
+    </band>
+    <band>
+      <freqband ref="F1_5260_5320"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+      <flags>IEEE80211_CHAN_DFS</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5745_5805"/>
+      <maxpower>23</maxpower>
+    </band>
+  </netband>
+  <netband mode="11ng">
+    <band>
+      <freqband ref="F1_2412_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+  </netband>
+  <netband mode="11na">
+    <band>
+      <freqband ref="F1_5180_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5180_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5260_5320"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5260_5320"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+  </netband>
+</rd>
+
+<rd id="korea">
+  <name>KOREA</name>
+  <sku>0x45</sku>
+  <defcc ref="KR"/>
+  <netband mode="11b">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_B</flags>
+    </band>
+    <band>
+      <freqband ref="F1_2467_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_B</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+  </netband>
+  <netband mode="11g">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+    <band>
+      <freqband ref="F1_2467_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+  </netband>
+  <netband mode="11a">
+    <band>
+      <freqband ref="F1_5180_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5260_5320"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5500_5620"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+  </netband>
+  <netband mode="11ng">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="F1_2467_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+  </netband>
+  <netband mode="11na">
+    <band>
+      <freqband ref="F1_5180_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5260_5320"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5500_5620"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+  </netband>
+</rd>
+
+<!-- Rest Of World -->
+
+<rd id="row">
+  <name>ROW</name>
+  <sku>0x8a</sku>
+  <netband mode="11b">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_B</flags>
+    </band>
+  </netband>
+  <netband mode="11g">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+  </netband>
+  <netband mode="11a">
+    <band>
+      <freqband ref="F1_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+  </netband>
+  <netband mode="11ng">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+  </netband>
+  <netband mode="11na">
+    <band>
+      <freqband ref="F1_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+  </netband>
+</rd>
+
+<rd id="none">
+  <name>NONE</name>
+  <sku>0xf0</sku>
+  <netband mode="11b">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_B</flags>
+    </band>
+    <band>
+      <freqband ref="F1_2467_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_B</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+  </netband>
+  <netband mode="11g">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+    <band>
+      <freqband ref="F1_2467_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+  </netband>
+  <netband mode="11a">
+    <band>
+      <freqband ref="F1_5120_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5260_5320"/>
+      <maxpower>24</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5500_5700"/>
+      <maxpower>24</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5825_5825"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+  </netband>
+  <netband mode="11ng">
+    <band>
+      <freqband ref="F1_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT20</flags>
+    </band>
+    <band>
+      <freqband ref="H4_2412_2462"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT40</flags>
+    </band>
+    <band>
+      <freqband ref="F1_2467_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="H4_2467_2472"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+      <flags>IEEE80211_CHAN_HT40</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+  </netband>
+  <netband mode="11na">
+    <band>
+      <freqband ref="F1_5120_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5120_5240"/>
+      <maxpower>17</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5260_5320"/>
+      <maxpower>24</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5260_5320"/>
+      <maxpower>24</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5500_5700"/>
+      <maxpower>24</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5500_5680"/>
+      <maxpower>24</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5745_5805"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="F1_5825_5825"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT20</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+    <band>
+      <freqband ref="H4_5825_5825"/>
+      <maxpower>23</maxpower>
+      <flags>IEEE80211_CHAN_HT40</flags>
+      <flags>IEEE80211_CHAN_PASSIVE</flags>
+    </band>
+  </netband>
+</rd>
+
+<rd id="sr9">
+  <name>SR9</name>
+  <sku>0x0298</sku>
+  <netband mode="11g">
+    <band>
+      <freqband ref="S1_907_922_5"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+    <band>
+      <freqband ref="S1_907_922_10"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+    <band>
+      <freqband ref="S1_912_917"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+  </netband>
+</rd>
+
+<rd id="xr9">
+  <name>XR9</name>
+  <sku>0x299</sku>
+  <netband mode="11g">
+    <band>
+      <freqband ref="S1_907_922_5"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+    <band>
+      <freqband ref="S1_907_922_10"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+    <band>
+      <freqband ref="S1_912_917"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+  </netband>
+</rd>
+
+<rd id="gz901">
+  <name>GZ901</name>
+  <sku>0x29a</sku>
+  <netband mode="11g">
+    <band>
+      <freqband ref="S1_908_923_5"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+    <band>
+      <freqband ref="S1_913_918_10"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+    <band>
+      <freqband ref="S1_913_918"/>
+      <maxpower>30</maxpower>
+      <flags>IEEE80211_CHAN_G</flags>
+    </band>
+  </netband>
+</rd>
+</regulatory-domains>
+
+<country-codes>
+<!--
+  ISO 3166 Country/Region codes and regdomain mapping.
+  http://ftp.ics.uci.edu/pub/ietf/http/related/iso3166.txt
+  has the list of codes.
+  XXX this table is incomplete
+-->
+<country id="AL">
+  <isocc>8</isocc> <name>Albania</name> <rd ref="none"/>
+</country>
+<country id="DZ">
+  <isocc>12</isocc> <name>Algeria</name> <rd ref="none"/>
+</country>
+<country id="AR">
+  <isocc>32</isocc> <name>Argentina</name> <rd ref="none"/>
+</country>
+<country id="AM">
+  <isocc>51</isocc> <name>Armenia</name> <rd ref="etsi"/>
+</country>
+<country id="AU">
+  <isocc>36</isocc> <name>Australia</name> <rd ref="row"/>
+</country>
+<country id="AT">
+  <isocc>40</isocc> <name>Austria</name> <rd ref="etsi2"/>
+</country>
+<country id="AZ">
+  <isocc>31</isocc> <name>Azerbaijan</name> <rd ref="etsi"/>
+</country>
+<country id="BH">
+  <isocc>48</isocc> <name>Bahrain</name> <rd ref="none"/>
+</country>
+<country id="BD">
+  <isocc>50</isocc> <name>Bangladesh</name> <rd ref="row"/>
+</country>
+<country id="BY">
+  <isocc>112</isocc> <name>Belarus</name> <rd ref="none"/>
+</country>
+<country id="BE">
+  <isocc>56</isocc> <name>Belgium</name> <rd ref="etsi"/>
+</country>
+<country id="BZ">
+  <isocc>84</isocc> <name>Belize</name> <rd ref="none"/>
+</country>
+<country id="BO">
+  <isocc>68</isocc> <name>Bolivia</name> <rd ref="none"/>
+</country>
+<country id="BR">
+  <isocc>76</isocc> <name>Brazil</name> <rd ref="fcc"/>
+</country>
+<country id="BN">
+  <isocc>96</isocc> <name>Brunei</name> <rd ref="apac"/>
+</country>
+<country id="BG">
+  <isocc>100</isocc> <name>Bulgaria</name> <rd ref="etsi"/>
+</country>
+<country id="CA">
+  <isocc>124</isocc> <name>Canada</name> <rd ref="fcc"/>
+</country>
+<country id="CL">
+  <isocc>152</isocc> <name>Chile</name> <rd ref="row"/>
+</country>
+<country id="CN">
+  <isocc>156</isocc> <name>China</name> <rd ref="row"/>
+</country>
+<country id="CO">
+  <isocc>170</isocc> <name>Colombia</name> <rd ref="fcc"/>
+</country>
+<country id="CR">
+  <isocc>188</isocc> <name>Costa Rica</name> <rd ref="none"/>
+</country>
+<country id="HR">
+  <isocc>191</isocc> <name>Croatia</name> <rd ref="etsi"/>
+</country>
+<country id="CY">
+  <isocc>196</isocc> <name>Cyprus</name> <rd ref="etsi"/>
+</country>
+<country id="CZ">
+  <isocc>203</isocc> <name>Czech Republic</name> <rd ref="etsi"/>
+</country>
+<country id="DK">
+  <isocc>208</isocc> <name>Denmark</name> <rd ref="etsi"/>
+</country>
+<country id="DO">
+  <isocc>214</isocc> <name>Dominican Republic</name> <rd ref="none"/>
+</country>
+<country id="EC">
+  <isocc>218</isocc> <name>Ecuador</name> <rd ref="none"/>
+</country>
+<country id="EG">
+  <isocc>818</isocc> <name>Egypt</name> <rd ref="none"/>
+</country>
+<country id="SV">
+  <isocc>222</isocc> <name>El Salvador</name> <rd ref="none"/>
+</country>    
+<country id="EE">
+  <isocc>233</isocc> <name>Estonia</name> <rd ref="etsi"/>
+</country>
+<country id="FI">
+  <isocc>246</isocc> <name>Finland</name> <rd ref="etsi"/>
+</country>
+<country id="FR">
+  <isocc>250</isocc> <name>France</name> <rd ref="etsi"/>
+</country>
+<country id="F2">
+  <isocc>255</isocc> <name>France2</name> <rd ref="etsi"/>
+</country>
+<country id="GE">
+  <isocc>268</isocc> <name>Georgia</name> <rd ref="etsi"/>
+</country>
+<country id="DE">
+  <isocc>276</isocc> <name>Germany</name> <rd ref="etsi"/>
+</country>
+<country id="GR">
+  <isocc>300</isocc> <name>Greece</name> <rd ref="etsi"/>
+</country>
+<country id="GT">
+  <isocc>320</isocc> <name>Guatemala</name> <rd ref="none"/>
+</country>
+<country id="HN">
+  <isocc>340</isocc> <name>Honduras</name> <rd ref="none"/>
+</country>
+<country id="HK">
+  <isocc>344</isocc> <name>Hong Kong</name> <rd ref="apac"/>
+</country>
+<country id="HU">
+  <isocc>348</isocc> <name>Hungary</name> <rd ref="etsi"/>
+</country>
+<country id="IS">
+  <isocc>352</isocc> <name>Iceland</name> <rd ref="etsi"/>
+</country>
+<country id="IN">
+  <isocc>356</isocc> <name>India</name> <rd ref="apac"/>
+</country>
+<country id="ID">
+  <isocc>360</isocc> <name>Indonesia</name> <rd ref="none"/>
+</country>
+<country id="IR">
+  <isocc>364</isocc> <name>Iran</name> <rd ref="none"/>
+</country>
+<country id="IE">
+  <isocc>372</isocc> <name>Ireland</name> <rd ref="etsi"/>
+</country>
+<country id="IL">
+  <isocc>376</isocc> <name>Israel</name> <rd ref="none"/>
+</country>
+<country id="IT">
+  <isocc>380</isocc> <name>Italy</name> <rd ref="etsi"/>
+</country>
+<country id="JM">
+  <isocc>388</isocc> <name>Jamaica</name> <rd ref="none"/>
+</country>
+<country id="JP">
+  <isocc>392</isocc> <name>Japan</name> <rd ref="japan"/>
+</country>
+<country id="J1">
+  <isocc>393</isocc> <name>Japan1</name> <rd ref="japan"/>
+</country>
+<country id="J2">
+  <isocc>394</isocc> <name>Japan2</name> <rd ref="japan"/>
+</country>    
+<country id="J3">
+  <isocc>395</isocc> <name>Japan3</name> <rd ref="japan"/>
+</country>
+<country id="J4">
+  <isocc>396</isocc> <name>Japan4</name> <rd ref="japan"/>
+</country>
+<country id="J5">
+  <isocc>397</isocc> <name>Japan5</name> <rd ref="japan"/>
+</country>    
+<country id="JO">
+  <isocc>400</isocc> <name>Jordan</name> <rd ref="none"/>
+</country>
+<country id="KZ">
+  <isocc>398</isocc> <name>Kazakhstan</name> <rd ref="none"/>
+</country>
+<country id="KP">
+  <isocc>408</isocc> <name>North Korea</name> <rd ref="korea"/>
+</country>
+<country id="KR">
+  <isocc>410</isocc> <name>Korea Republic</name> <rd ref="korea"/>
+</country>
+<country id="K2">
+  <isocc>411</isocc> <name>Korea Republic2</name> <rd ref="none"/>
+</country>
+<country id="KW">
+  <isocc>414</isocc> <name>Kuwait</name> <rd ref="none"/>
+</country>
+<country id="LV">
+  <isocc>428</isocc> <name>Latvia</name> <rd ref="etsi2"/>
+</country>
+<country id="LB">
+  <isocc>422</isocc> <name>Lebanon</name> <rd ref="none"/>
+</country>
+<country id="LI">
+  <isocc>438</isocc> <name>Liechtenstein</name> <rd ref="etsi"/>
+</country>
+<country id="LT">
+  <isocc>440</isocc> <name>Lithuania</name> <rd ref="etsi"/>
+</country>
+<country id="LU">
+  <isocc>442</isocc> <name>Luxemborg</name> <rd ref="etsi"/>
+</country>
+<country id="MO">
+  <isocc>446</isocc> <name>Macau</name> <rd ref="none"/>
+</country>
+<country id="MK">
+  <isocc>807</isocc> <name>Macedonia</name> <rd ref="none"/>
+</country>
+<country id="MY">
+  <isocc>458</isocc> <name>Malaysia</name> <rd ref="apac3"/>
+</country>
+<country id="MT">
+  <isocc>470</isocc> <name>Malta</name> <rd ref="etsi"/>
+</country>
+<country id="MX">
+  <isocc>484</isocc> <name>Mexico</name> <rd ref="fcc"/>
+</country>
+<country id="MC">
+  <isocc>492</isocc> <name>Monaco</name> <rd ref="none"/>
+</country>
+<country id="MA">
+  <isocc>504</isocc> <name>Morocco</name> <rd ref="etsi"/>
+</country>
+<country id="NP">
+  <isocc>524</isocc> <name>Nepal</name> <rd ref="row"/>
+</country>
+<country id="NL">
+  <isocc>528</isocc> <name>Netherlands</name> <rd ref="etsi"/>
+</country>
+<country id="NZ">
+  <isocc>554</isocc> <name>New Zealand</name> <rd ref="apac"/>
+</country>
+<country id="NO">
+  <isocc>578</isocc> <name>Norway</name> <rd ref="etsi"/>
+</country>
+<country id="OM">
+  <isocc>512</isocc> <name>Oman</name> <rd ref="none"/>
+</country>
+<country id="PK">
+  <isocc>586</isocc> <name>Pakistan</name> <rd ref="row"/>
+</country>
+<country id="PA">
+  <isocc>591</isocc> <name>Panama</name> <rd ref="none"/>
+</country>
+<country id="PE">
+  <isocc>604</isocc> <name>Peru</name> <rd ref="none"/>
+</country>
+<country id="PH">
+  <isocc>608</isocc> <name>Phillipines</name> <rd ref="apac2"/>
+</country>
+<country id="PL">
+  <isocc>616</isocc> <name>Poland</name> <rd ref="etsi"/>
+</country>
+<country id="PT">
+  <isocc>620</isocc> <name>Portugal</name> <rd ref="etsi"/>
+</country>
+<country id="PR">
+  <isocc>630</isocc> <name>Puerto Rico</name> <rd ref="fcc"/>
+</country>
+<country id="QA">
+  <isocc>634</isocc> <name>Quatar</name> <rd ref="none"/>
+</country>
+<country id="RO">
+  <isocc>642</isocc> <name>Romania</name> <rd ref="etsi"/>
+</country>
+<country id="RU">
+  <isocc>643</isocc> <name>Rusia</name> <rd ref="none"/>
+</country>
+<country id="SA">
+  <isocc>682</isocc> <name>Saudi Arabia</name> <rd ref="none"/>
+</country>
+<country id="SG">
+  <isocc>702</isocc> <name>Singapore</name> <rd ref="apac2"/>
+</country>
+<country id="SK">
+  <isocc>703</isocc> <name>Slovak Republic</name> <rd ref="etsi2"/>
+</country>
+<country id="SI">
+  <isocc>705</isocc> <name>Slovenia</name> <rd ref="etsi"/>
+</country>
+<country id="ZA">
+  <isocc>710</isocc> <name>South Africa</name> <rd ref="none"/>
+</country>
+<country id="ES">
+  <isocc>724</isocc> <name>Spain</name> <rd ref="etsi2"/>
+</country>
+<country id="LK">
+  <isocc>144</isocc> <name>Sri Lanka</name> <rd ref="apac2"/>
+</country>
+<country id="SE">
+  <isocc>752</isocc> <name>Sweden</name> <rd ref="etsi"/>
+</country>
+<country id="CH">
+  <isocc>756</isocc> <name>Switzerland</name> <rd ref="etsi"/>
+</country>
+<country id="SY">
+  <isocc>760</isocc> <name>Syria</name> <rd ref="none"/>
+</country>
+<country id="TW">
+  <isocc>158</isocc> <name>Taiwan</name> <rd ref="row"/>
+</country>
+<country id="TH">
+  <isocc>764</isocc> <name>Thailand</name> <rd ref="none"/>
+</country>
+<country id="TT">
+  <isocc>780</isocc> <name>Tobago</name> <rd ref="none"/>
+</country>
+<country id="TN">
+  <isocc>788</isocc> <name>Tunisia</name> <rd ref="none"/>
+</country>
+<country id="TR">
+  <isocc>792</isocc> <name>Turkey</name> <rd ref="etsi"/>
+</country>
+<country id="UA">
+  <isocc>804</isocc> <name>Ukraine</name> <rd ref="none"/>
+</country>
+<country id="AE">
+  <isocc>784</isocc> <name>United Arab Emirates</name> <rd ref="none"/>
+</country>
+<country id="GB">
+  <isocc>826</isocc> <name>United Kingdom</name> <rd ref="etsi"/>
+</country>
+<country id="US">
+  <isocc>840</isocc> <name>United States</name> <rd ref="fcc"/>
+</country>
+<country id="UY">
+  <isocc>858</isocc> <name>Uruguay</name> <rd ref="none"/>
+</country>
+<country id="UZ">
+  <isocc>860</isocc> <name>Uzbekistan</name> <rd ref="none"/>
+</country>    
+<country id="VE">
+  <isocc>862</isocc> <name>Venezuela</name> <rd ref="fcc"/>
+</country>
+<country id="VN">
+  <isocc>704</isocc> <name>Viet Nam</name> <rd ref="apac2"/>
+</country>
+<country id="YE">
+  <isocc>887</isocc> <name>Yemen</name> <rd ref="none"/>
+</country>
+<country id="ZW">
+  <isocc>716</isocc> <name>Zimbabwe</name> <rd ref="none"/>
+</country>
+
+<country id="DEBUG">
+  <isocc>0</isocc> <name>Debug</name> <rd ref="debug"/>
+</country>
+</country-codes>
+
+<!--
+  Band specifications referenced above.
+  NB: keep sorted by starting frequency, legacy before HT 
+-->
+<shared-frequency-bands>
+<freqband id="F1_4942_4987_5">
+  <freqstart>4942</freqstart> <freqend>4987</freqend>
+  <chanwidth>5</chanwidth> <chansep>5</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+  <flags>IEEE80211_CHAN_QUARTER</flags>
+</freqband>
+<freqband id="F1_4945_4985_10">
+  <freqstart>4945</freqstart> <freqend>4985</freqend>
+  <chanwidth>10</chanwidth> <chansep>5</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+  <flags>IEEE80211_CHAN_HALF</flags>
+</freqband>
+<freqband id="F1_4950_4980">
+  <freqstart>4950</freqstart> <freqend>4980</freqend>
+  <chanwidth>20</chanwidth> <chansep>5</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="F1_5120_5240">
+  <freqstart>5120</freqstart> <freqend>5240</freqend>
+  <chanwidth>20</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="H4_5120_5240">
+  <freqstart>5120</freqstart> <freqend>5240</freqend>
+  <chanwidth>40</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="F1_5180_5240">
+  <freqstart>5180</freqstart> <freqend>5240</freqend>
+  <chanwidth>20</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="H4_5180_5240">
+  <freqstart>5180</freqstart> <freqend>5240</freqend>
+  <chanwidth>40</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="F1_5200_5240">
+  <freqstart>5200</freqstart> <freqend>5240</freqend>
+  <chanwidth>20</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="H4_5200_5240">
+  <freqstart>5200</freqstart> <freqend>5240</freqend>
+  <chanwidth>40</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="F1_5260_5320">
+  <freqstart>5260</freqstart> <freqend>5320</freqend>
+  <chanwidth>20</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="H4_5260_5320">
+  <freqstart>5260</freqstart> <freqend>5320</freqend>
+  <chanwidth>40</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="F1_5260_5700">
+  <freqstart>5260</freqstart> <freqend>5700</freqend>
+  <chanwidth>20</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="F1_5280_5320">
+  <freqstart>5280</freqstart> <freqend>5320</freqend>
+  <chanwidth>20</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="H4_5280_5320">
+  <freqstart>5280</freqstart> <freqend>5320</freqend>
+  <chanwidth>40</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="F1_5500_5620">
+  <freqstart>5500</freqstart> <freqend>5620</freqend>
+  <chanwidth>20</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="H4_5500_5620">
+  <freqstart>5500</freqstart> <freqend>5620</freqend>
+  <chanwidth>40</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="H4_5500_5680">
+  <freqstart>5500</freqstart> <freqend>5680</freqend>
+  <chanwidth>40</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="F1_5500_5700">
+  <freqstart>5500</freqstart> <freqend>5700</freqend>
+  <chanwidth>20</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="H4_5725_5825">
+  <freqstart>5725</freqstart> <freqend>5825</freqend>
+  <chanwidth>40</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="F1_5745_5805">
+  <freqstart>5745</freqstart> <freqend>5805</freqend>
+  <chanwidth>20</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="H4_5745_5805">
+  <freqstart>5745</freqstart> <freqend>5805</freqend>
+  <chanwidth>40</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="H4_5745_5825">
+  <freqstart>5745</freqstart> <freqend>5825</freqend>
+  <chanwidth>40</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="F1_5825_5825">
+  <freqstart>5825</freqstart> <freqend>5825</freqend>
+  <chanwidth>20</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="H4_5825_5825">
+  <freqstart>5825</freqstart> <freqend>5825</freqend>
+  <chanwidth>40</chanwidth> <chansep>20</chansep>
+  <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+
+<freqband id="F1_2312_2372">
+  <freqstart>2312</freqstart> <freqend>2372</freqend>
+  <chanwidth>20</chanwidth> <chansep>5</chansep>
+</freqband>
+<freqband id="F1_2412_2462">
+  <freqstart>2412</freqstart> <freqend>2462</freqend>
+  <chanwidth>20</chanwidth> <chansep>5</chansep>
+</freqband>
+<freqband id="H4_2412_2462">
+  <freqstart>2412</freqstart> <freqend>2462</freqend>
+  <chanwidth>40</chanwidth> <chansep>5</chansep>
+</freqband>
+<freqband id="F1_2412_2472">
+  <freqstart>2412</freqstart> <freqend>2472</freqend>
+  <chanwidth>20</chanwidth> <chansep>5</chansep>
+</freqband>
+<freqband id="H4_2412_2472">
+  <freqstart>2412</freqstart> <freqend>2472</freqend>
+  <chanwidth>40</chanwidth> <chansep>5</chansep>
+</freqband>
+<freqband id="F1_2467_2472">
+  <freqstart>2467</freqstart> <freqend>2472</freqend>
+  <chanwidth>20</chanwidth> <chansep>5</chansep>
+</freqband>
+<freqband id="H4_2467_2472">
+  <freqstart>2467</freqstart> <freqend>2472</freqend>
+  <chanwidth>40</chanwidth> <chansep>5</chansep>
+</freqband>
+<freqband id="F1_2484_2484">
+  <freqstart>2484</freqstart> <freqend>2484</freqend>
+  <chanwidth>20</chanwidth> <chansep>5</chansep>
+</freqband>
+<freqband id="F1_2512_2732">
+  <freqstart>2512</freqstart> <freqend>2732</freqend>
+  <chanwidth>20</chanwidth> <chansep>5</chansep>
+</freqband>
+
+<freqband id="S1_907_922_5">
+  <freqstart>907</freqstart> <freqend>922</freqend>
+  <chanwidth>5</chanwidth> <chansep>5</chansep>
+  <flags>IEEE80211_CHAN_GSM</flags>
+  <flags>IEEE80211_CHAN_QUARTER</flags>
+</freqband>
+<freqband id="S1_907_922_10">
+  <freqstart>907</freqstart> <freqend>922</freqend>
+  <chanwidth>10</chanwidth> <chansep>5</chansep>
+  <flags>IEEE80211_CHAN_GSM</flags>
+  <flags>IEEE80211_CHAN_HALF</flags>
+</freqband>
+<freqband id="S1_912_917">
+  <freqstart>912</freqstart> <freqend>917</freqend>
+  <chanwidth>20</chanwidth> <chansep>5</chansep>
+  <flags>IEEE80211_CHAN_GSM</flags>
+</freqband>
+
+<freqband id="S1_908_923_5">
+  <freqstart>908</freqstart> <freqend>923</freqend>
+  <chanwidth>5</chanwidth> <chansep>5</chansep>
+  <flags>IEEE80211_CHAN_GSM</flags>
+  <flags>IEEE80211_CHAN_QUARTER</flags>
+</freqband>
+<freqband id="S1_913_918_10">
+  <freqstart>913</freqstart> <freqend>918</freqend>
+  <chanwidth>10</chanwidth> <chansep>5</chansep>
+  <flags>IEEE80211_CHAN_GSM</flags>
+  <flags>IEEE80211_CHAN_HALF</flags>
+</freqband>
+<freqband id="S1_913_918">
+  <freqstart>913</freqstart> <freqend>918</freqend>
+  <chanwidth>20</chanwidth> <chansep>5</chansep>
+  <flags>IEEE80211_CHAN_GSM</flags>
+</freqband>
+
+</shared-frequency-bands>
+
+</regulatory-data>
index 6285dca..444cb11 100644 (file)
@@ -22,7 +22,8 @@ SRCS+=        ifclone.c               # clone device support
 #SRCS+=        ifmac.c                 # MAC support
 SRCS+= ifmedia.c               # SIOC[GS]IFMEDIA support
 SRCS+= ifvlan.c                # SIOC[GS]ETVLAN support
-SRCS+= ifieee80211.c           # SIOC[GS]IEEE80211 support
+SRCS+= ifieee80211.c           # SIOC[GS]IEEE80211 support
+SRCS+= regdomain.c
 
 SRCS+= ifcarp.c                # SIOC[GS]VH support
 #SRCS+=        ifpfsync.c              # pfsync(4) support
@@ -31,8 +32,8 @@ SRCS+=        ifbridge.c              # bridge support
 
 SRCS+= af_ipx.c                # IPX support
 
-DPADD= ${LIBIPX}
-LDADD= -lipx
+DPADD= ${LIBIPX} ${LIBBSDXML} ${LIBSBUF}
+LDADD= -lipx -lbsdxml -lsbuf
 
 MAN=   ifconfig.8
 
index 76ae3a7..903f2b9 100644 (file)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sbin/ifconfig/ifclone.c,v 1.1 2004/12/08 19:18:07 sam Exp $
- * $DragonFly: src/sbin/ifconfig/ifclone.c,v 1.1 2006/04/02 03:33:59 sephe Exp $
+ * $FreeBSD: head/sbin/ifconfig/ifclone.c 194799 2009-06-23 23:49:52Z delphij $
+ * $DragonFly$
  */
 
+#include <sys/queue.h>
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
@@ -86,49 +87,87 @@ list_cloners(void)
        free(buf);
 }
 
+struct clone_defcb {
+       char ifprefix[IFNAMSIZ];
+       clone_callback_func *clone_cb;
+       SLIST_ENTRY(clone_defcb) next;
+};
+
+static SLIST_HEAD(, clone_defcb) clone_defcbh =
+   SLIST_HEAD_INITIALIZER(clone_defcbh);
+
 void
-clone_create(void)
+clone_setdefcallback(const char *ifprefix, clone_callback_func *p)
 {
-       int s;
+       struct clone_defcb *dcp;
 
-       s = socket(AF_INET, SOCK_DGRAM, 0);
-       if (s == -1)
-               err(1, "socket(AF_INET,SOCK_DGRAM)");
+       dcp = malloc(sizeof(*dcp));
+       strlcpy(dcp->ifprefix, ifprefix, IFNAMSIZ-1);
+       dcp->clone_cb = p;
+       SLIST_INSERT_HEAD(&clone_defcbh, dcp, next);
+}
+
+/*
+ * Do the actual clone operation.  Any parameters must have been
+ * setup by now.  If a callback has been setup to do the work
+ * then defer to it; otherwise do a simple create operation with
+ * no parameters.
+ */
+static void
+ifclonecreate(int s, void *arg)
+{
+       struct ifreq ifr;
+       struct clone_defcb *dcp;
+       clone_callback_func *clone_cb = NULL;
 
        memset(&ifr, 0, sizeof(ifr));
        (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
-       if (ioctl(s, SIOCIFCREATE, &ifr) < 0)
-               err(1, "SIOCIFCREATE");
+
+       if (clone_cb == NULL) {
+               /* Try to find a default callback */
+               SLIST_FOREACH(dcp, &clone_defcbh, next) {
+                       if (strncmp(dcp->ifprefix, ifr.ifr_name,
+                           strlen(dcp->ifprefix)) == 0) {
+                               clone_cb = dcp->clone_cb;
+                               break;
+                       }
+               }
+       }
+       if (clone_cb == NULL) {
+               /* NB: no parameters */
+               if (ioctl(s, SIOCIFCREATE2, &ifr) < 0)
+                       err(1, "SIOCIFCREATE2");
+       } else {
+               clone_cb(s, &ifr);
+       }
 
        /*
-        * If we get a different name back then we put in, we probably
-        * want to print it out, but we might change our mind later so
-        * we just signal our interest and leave the printout for later.
+        * If we get a different name back than we put in, print it.
         */
-       if (strcmp(name, ifr.ifr_name) != 0) {
-               printname = 1;
+       if (strncmp(name, ifr.ifr_name, sizeof(name)) != 0) {
                strlcpy(name, ifr.ifr_name, sizeof(name));
+               printf("%s\n", name);
        }
-
-       close(s);
 }
 
-static void
-clone_destroy(const char *val, int d, int s, const struct afswtch *rafp)
+static
+DECL_CMD_FUNC(clone_create, arg, d)
 {
+       callback_register(ifclonecreate, NULL);
+}
 
+static
+DECL_CMD_FUNC(clone_destroy, arg, d)
+{
        (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
        if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
                err(1, "SIOCIFDESTROY");
-       /*
-        * If we create and destroy an interface in the same command,
-        * there isn't any reason to print it's name.
-        */
-       printname = 0;
 }
 
 static struct cmd clone_cmds[] = {
+       DEF_CLONE_CMD("create", 0,      clone_create),
        DEF_CMD("destroy",      0,      clone_destroy),
+       DEF_CLONE_CMD("plumb",  0,      clone_create),
        DEF_CMD("unplumb",      0,      clone_destroy),
 };
 
@@ -138,13 +177,13 @@ clone_Copt_cb(const char *optarg __unused)
        list_cloners();
        exit(0);
 }
-static struct option clone_Copt = { "C", "[-C]", clone_Copt_cb };
+static struct option clone_Copt = { .opt = "C", .opt_usage = "[-C]", .cb = clone_Copt_cb };
 
 static __constructor void
 clone_ctor(void)
 {
 #define        N(a)    (sizeof(a) / sizeof(a[0]))
-       int i;
+       size_t i;
 
        for (i = 0; i < N(clone_cmds);  i++)
                cmd_register(&clone_cmds[i]);
index 36cc199..f089d9c 100644 (file)
@@ -29,7 +29,7 @@
 .\" $FreeBSD: src/sbin/ifconfig/ifconfig.8,v 1.124 2006/10/10 09:44:08 ru Exp $
 .\" $DragonFly: src/sbin/ifconfig/ifconfig.8,v 1.25 2008/11/14 12:52:04 sephe Exp $
 .\"
-.Dd September 30, 2007
+.Dd March 2, 2010
 .Dt IFCONFIG 8
 .Os
 .Sh NAME
@@ -564,8 +564,144 @@ If the interface was reset when previously marked down,
 the hardware will be re-initialized.
 .El
 .Pp
-The following parameters are specific to IEEE 802.11 wireless interfaces:
+The following parameters are specific to cloning
+IEEE 802.11 wireless interfaces with the
+.Cm create
+request:
 .Bl -tag -width indent
+.It Cm wlandev Ar device
+Use
+.Ar device
+as the parent for the cloned device.
+.It Cm wlanmode Ar mode
+Specify the operating mode for this cloned device.
+.Ar mode
+is one of
+.Cm sta ,
+.Cm ahdemo 
+(or
+.Cm adhoc-demo ),
+.Cm ibss ,
+(or
+.Cm adhoc ),
+.Cm ap ,
+(or
+.Cm hostap ),
+.Cm wds ,
+.Cm tdma ,
+.Cm mesh ,
+and
+.Cm monitor .
+The operating mode of a cloned interface cannot be changed.
+The
+.Cm tdma
+mode is actually implemented as an
+.Cm adhoc-demo
+interface with special properties.
+.It Cm wlanbssid Ar bssid
+The 802.11 mac address to use for the bssid.
+This must be specified at create time for a legacy
+.Cm wds
+device.
+.It Cm wlanaddr Ar address
+The local mac address.
+If this is not specified then a mac address will automatically be assigned
+to the cloned device.
+Typically this address is the same as the address of the parent device
+but if the
+.Cm bssid
+parameter is specified then the driver will craft a unique address for
+the device (if supported).
+.It Cm wdslegacy
+Mark a
+.Cm wds
+device as operating in ``legacy mode''.
+Legacy 
+.Cm wds
+devices have a fixed peer relationship and do not, for example, roam
+if their peer stops communicating.
+For completeness a Dynamic WDS (DWDS) interface may marked as
+.Fl wdslegacy .
+.It Cm bssid
+Request a unique local mac address for the cloned device.
+This is only possible if the device supports multiple mac addresses.
+To force use of the parent's mac address use
+.Fl bssid .
+.It Cm beacons
+Mark the cloned interface as depending on hardware support to
+track received beacons.
+To have beacons tracked in software use
+.Fl beacons .
+For 
+.Cm hostap
+mode 
+.Fl beacons
+can also be used to indicate no beacons should
+be transmitted; this can be useful when creating a WDS configuration but
+.Cm wds
+interfaces can only be created as companions to an access point.
+.El
+.Pp
+The following parameters are specific to IEEE 802.11 wireless interfaces
+cloned with a
+.Cm create
+operation:
+.Bl -tag -width indent
+.It Cm ampdu
+Enable sending and receiving AMPDU frames when using 802.11n (default).
+The 802.11n specification states a compliant station must be capable
+of receiving AMPDU frames but transmision is optional.
+Use
+.Fl ampdu
+to disable all use of AMPDU with 802.11n.
+For testing and/or to work around interoperability problems one can use
+.Cm ampdutx
+and
+.Cm ampdurx
+to control use of AMPDU in one direction.
+.It Cm ampdudensity Ar density
+Set the AMPDU density parameter used when operating with 802.11n.
+This parameter controls the inter-packet gap for AMPDU frames.
+The sending device normally controls this setting but a receiving station
+may request wider gaps.
+Legal values for
+.Ar density
+are 0, .25, .5, 1, 2, 4, 8, and 16 (microseconds).
+A value of
+.Cm -
+is treated the same as 0.
+.It Cm ampdulimit Ar limit
+Set the limit on packet size for receiving AMPDU frames when operating
+with 802.11n.
+Legal values for
+.Ar limit
+are 8192, 16384, 32768, and 65536 but one can also specify
+just the unique prefix: 8, 16, 32, 64.
+Note the sender may limit the size of AMPDU frames to be less
+than the maximum specified by the receiving station.
+.It Cm amsdu
+Enable sending and receiving AMSDU frames when using 802.11n.
+By default AMSDU is received but not transmitted.
+Use
+.Fl amsdu
+to disable all use of AMSDU with 802.11n.
+For testing and/or to work around interoperability problems one can use
+.Cm amsdutx
+and
+.Cm amsdurx
+to control use of AMSDU in one direction.
+.It Cm amsdulimit Ar limit
+Set the limit on packet size for sending and receiving AMSDU frames
+when operating with 802.11n.
+Legal values for
+.Ar limit
+are 7935 and 3839 (bytes).
+Note the sender may limit the size of AMSDU frames to be less
+than the maximum specified by the receiving station.
+Note also that devices are not required to support the 7935 limit,
+only 3839 is required by the specification and the larger value
+may require more memory to be dedicated to support functionality
+that is rarely used.
 .It Cm apbridge
 When operating as an access point, pass packets between
 wireless clients directly (default).
@@ -577,7 +713,7 @@ is useful when traffic is to be processed with
 packet filtering.
 .It Cm authmode Ar mode
 Set the desired authentication mode in infrastructure mode.
-Not all adaptors support all modes.
+Not all adapters support all modes.
 The set of
 valid modes is
 .Cm none , open , shared
@@ -595,6 +731,47 @@ modes are only useful when using an authentication service
 (a supplicant for client operation or an authenticator when
 operating as an access point).
 Modes are case insensitive.
+.It Cm bgscan
+Enable background scanning when operating as a station.
+Background scanning is a technique whereby a station associated to
+an access point will temporarily leave the channel to scan for
+neighboring stations.
+This allows a station to maintain a cache of nearby access points
+so that roaming between access points can be done without
+a lengthy scan operation.
+Background scanning is done only when a station is not busy and
+any outbound traffic will cancel a scan operation.
+Background scanning should never cause packets to be lost though
+there may be some small latency if outbound traffic interrupts a
+scan operation.
+By default background scanning is enabled if the device is capable.
+To disable background scanning, use
+.Fl bgscan .
+Background scanning is controlled by the
+.Cm bgscanidle
+and
+.Cm bgscanintvl
+parameters.
+Background scanning must be enabled for roaming; this is an artifact
+of the current implementation and may not be required in the future.
+.It Cm bgscanidle Ar idletime
+Set the minimum time a station must be idle (not transmitting or
+receiving frames) before a background scan is initiated.
+The
+.Ar idletime
+parameter is specified in milliseconds.
+By default a station must be idle at least 250 milliseconds before
+a background scan is initiated.
+The idle time may not be set to less than 100 milliseconds.
+.It Cm bgscanintvl Ar interval
+Set the interval at which background scanning is attempted.
+The
+.Ar interval
+parameter is specified in seconds.
+By default a background scan is considered every 300 seconds (5 minutes).
+The 
+.Ar interval
+may not be set to less than 15 seconds.
 .It Cm bintval Ar interval
 Set the interval at which beacon frames are sent when operating in
 ad-hoc or ap mode.
@@ -604,13 +781,13 @@ parameter is specified in TU's (1024 usecs).
 By default beacon frames are transmitted every 100 TU's.
 .It Cm bmissthreshold Ar count
 Set the number of consecutive missed beacons at which the station
-will attempt to roam (i.e. search for a new access point).
+will attempt to roam (i.e., search for a new access point).
 The
 .Ar count
-parameter is must be in the range 1 to 255;
-though the upper bound may be reduced according to device capabilities..
-The default threshold is 7 consecutive missed beacons;
-but this may be overridden by the device driver.
+parameter must be in the range 1 to 255; though the
+upper bound may be reduced according to device capabilities.
+The default threshold is 7 consecutive missed beacons; but
+this may be overridden by the device driver.
 Another name for the
 .Cm bmissthreshold
 parameter is
@@ -658,18 +835,118 @@ Channels range from 1 to 255, but the exact selection available
 depends on the region your adaptor was manufactured for.
 Setting
 the channel to
-.Li 0 ,
-.Cm any ,
+.Li any ,
 or
 .Cm -
-will give you the default for your adaptor.
-Some
-adaptors ignore this setting unless you are in ad-hoc mode.
+will clear any desired channel and, if the device is marked up,
+force a scan for a channel to operate on.
 Alternatively the frequency, in megahertz, may be specified
 instead of the channel number.
+.Pp
+When there are several ways to use a channel the channel
+number/frequency may be appended with attributes to clarify.
+For example, if a device is capable of operating on channel 6
+with 802.11n and 802.11g then one can specify that g-only use
+should be used by specifying ``6:g''.
+Similarly the channel width can be specified by appending it
+with ``/''; e.g. ``6/40'' specifies a 40MHz wide channel,
+These attributes can be combined as in: ``6:ht/40''.
+The full set of flags specified following a `:'' are:
+.Cm a
+(802.11a),
+.Cm b
+(802.11b),
+.Cm d
+(Atheros Dynamic Turbo mode),
+.Cm g
+(802.11g),
+.Cm h
+or
+.Cm n
+(802.11n aka HT),
+.Cm s
+(Atheros Static Turbo mode),
+and
+.Cm t
+(Atheros Dynamic Turbo mode, or appended to ``st'' and ``dt'').
+The full set of channel widths following a '/' are:
+.Cm 5 
+(5MHz aka quarter-rate channel),
+.Cm 10 
+(10MHz aka half-rate channel),
+.Cm 20 
+(20MHz mostly for use in specifying ht20),
+and
+.Cm 40 
+(40MHz mostly for use in specifying ht40),
+In addition,
+a 40MHz HT channel specification may include the location
+of the extension channel by appending ``+'' or ``-'' for above and below,
+respectively; e.g. ``2437:ht/40+'' specifies 40MHz wide HT operation 
+with the center channel at frequency 2437 and the extension channel above.
+.It Cm country Ar name
+Set the country code to use in calculating the regulatory constraints
+for operation.
+In particular the set of available channels, how the wireless device
+will operation on the channels, and the maximum transmit power that
+can be used on a channel are defined by this setting.
+Country/Region codes are specified as a 2-character abbreviation
+defined by ISO 3166 or using a longer, but possibly ambiguous, spelling;
+e.g. "ES" and "Spain".
+The set of country codes are taken from /etc/regdomain.xml and can also
+be viewed with the ``list countries'' request.
+Note that not all devices support changing the country code from a default
+setting; typically stored in EEPROM.
+See also
+.Cm regdomain ,
+.Cm indoor ,
+.Cm outdoor ,
+and
+.Cm anywhere .
+.It Cm dfs
+Enable Dynamic Frequency Selection (DFS) as specified in 802.11h.
+DFS embodies several facilities including detection of overlapping
+radar signals, dynamic transmit power control, and channel selection
+according to a least-congested criteria.
+DFS support is mandatory for some 5Ghz frequencies in certain
+locales (e.g. ETSI).
+By default DFS is enabled according to the regulatory definitions
+specified in /etc/regdomain.xml and the curent country code, regdomain,
+and channel.
+Note the underlying device (and driver) must support radar detection
+for full DFS support to work.
+To be fully compliant with the local regulatory agency frequencies that
+require DFS should not be used unless it is fully supported.
+Use
+.Fl dfs
+to disable this functionality for testing.
+.It Cm dotd
+Enable support for the 802.11d specification (default).
+When this support is enabled in station mode, beacon frames that advertise
+a country code different than the currently configured country code will
+cause an event to be dispatched to user applications.
+This event can be used by the station to adopt that country code and
+operate according to the associated regulatory constraints.
+When operating as an access point with 802.11d enabled the beacon and
+probe response frames transmitted will advertise the current regulatory
+domain settings.
+To disable 802.11d use
+.Fl dotd .
+.It Cm doth
+Enable 802.11h support including spectrum management.
+When 802.11h is enabled beacon and probe response frames will have
+the SpectrumMgt bit set in the capabilities field and
+country and power constraint information elements will be present.
+802.11h support also includes handling Channel Switch Announcements (CSA)
+which are a mechanism to coordinate channel changes by an access point.
+By default 802.11h is enabled if the device is capable.
+To disable 802.11h use
+.Fl doth .
 .It Cm deftxkey Ar index
 Set the default key to use for transmission.
 Typically this is only set when using WEP encryption.
+Note that you must set a default transmit key
+for the system to know which key to use in encrypting outbound traffic.
 The
 .Cm weptxkey
 is an alias for this request; it is provided for backwards compatibility.
@@ -683,6 +960,65 @@ The
 specifies the number of beacon intervals between DTIM
 and must be in the range 1 to 15.
 By default DTIM is 1 (i.e., DTIM occurs at each beacon).
+.It Cm dturbo
+Enable the use of Atheros Dynamic Turbo mode when communicating with
+another Dynamic Turbo-capable station.
+Dynamic Turbo mode is an Atheros-specific mechanism by which
+stations switch between normal 802.11 operation and a ``boosted''
+mode in which a 40MHz wide channel is used for communication.
+Stations using Dynamic Turbo mode operate boosted only when the
+channel is free of non-dturbo stations; when a non-dturbo station
+is identified on the channel all stations will automatically drop
+back to normal operation.
+By default, Dynamic Turbo mode is not enabled, even if the device is capable.
+Note that turbo mode (dynamic or static) is only allowed on some
+channels depending on the regulatory constraints; use the
+.Cm list chan
+command to identify the channels where turbo mode may be used.
+To disable Dynamic Turbo mode use
+.Fl dturbo .
+.It Cm dwds
+Enable Dynamic WDS (DWDS) support.
+DWDS is a facility by which 4-address traffic can be carried between
+stations operating in infrastructure mode.
+A station first associates to an access point and authenticates using
+normal procedures (e.g. WPA).
+Then 4-address frames are passed to carry traffic for stations
+operating on either side of the wireless link.
+DWDS extends the normal WDS mechanism by leveraging existing security
+protocols and eliminating static binding.
+.Pp
+When DWDS is enabled on an access point 4-address frames received from
+an authorized station will generate a ``DWDS discovery'' event to user
+applications.
+This event should be used to create a WDS interface that is bound
+to the remote station (and usually plumbed into a bridge).
+Once the WDS interface is up and running 4-address traffic then logically
+flows through that interface.
+.Pp
+When DWDS is enabled on a station, traffic with a destination address
+different from the peer station are encapsulated in a 4-address frame
+and transmitted to the peer.
+All 4-address traffic uses the security information of the stations
+(e.g. cryptographic keys).
+A station is associated using 802.11n facilities may transport
+4-address traffic using these same mechanisms; this depends on available
+resources and capabilities of the device.
+The DWDS implementation guards against layer 2 routing loops of
+multicast traffic.
+.It Cm ff
+Enable the use of Atheros Fast Frames when communicating with
+another Fast Frames-capable station.
+Fast Frames are an encapsulation technique by which two 802.3
+frames are transmitted in a single 802.11 frame.
+This can noticeably improve throughput but requires that the
+receiving station understand how to decapsulate the frame.
+Fast frame use is negotiated using the Atheros 802.11 vendor-specific
+protocol extension so enabling use is safe when communicating with
+non-Atheros devices.
+By default, use of fast frames is enabled if the device is capable.
+To explicitly disable fast frames, use
+.Fl ff .
 .It Cm fragthreshold Ar length
 Set the threshold for which transmitted frames are broken into fragments.
 The
@@ -696,7 +1032,7 @@ to
 or
 .Cm -
 disables transmit fragmentation.
-Not all adaptors honor the fragmentation threshold.
+Not all adapters honor the fragmentation threshold.
 .It Cm hidessid
 When operating as an access point, do not broadcast the SSID
 in beacon frames or respond to probe request frames unless
@@ -705,6 +1041,76 @@ By default, the SSID is included in beacon frames and
 undirected probe request frames are answered.
 To re-enable the broadcast of the SSID etc., use
 .Fl hidessid .
+.It Cm ht
+Enable use of High Throughput (HT) when using 802.11n (default).
+The 802.11n specification includes mechanisms for operation
+on 20MHz and 40MHz wide channels using different signalling mechanisms
+than specified in 802.11b, 802.11g, and 802.11a.
+Stations negotiate use of these facilities, termed HT20 and HT40,
+when they associate.
+To disable all use of 802.11n use
+.Fl ht .
+To disable use of HT20 (e.g. to force only HT40 use) use
+.Fl ht20 .
+To disable use of HT40 use
+.Fl ht40 .
+.Pp
+HT configuration is used to ``auto promote'' operation
+when several choices are available.
+For example, if a station associates to an 11n-capable access point
+it controls whether the station uses legacy operation, HT20, or HT40.
+When an 11n-capable device is setup as an access point and
+Auto Channel Selection is used to locate a channel to operate on,
+HT configuration controls whether legacy, HT20, or HT40 operation is setup
+on the selected channel.
+If a fixed channel is specified for a station then HT configuration can
+be given as part of the channel specification; e.g. 6:ht/20 to setup
+HT20 operation on channel 6.
+.It Cm htcompat
+Enable use of compatibility support for pre-802.11n devices (default).
+The 802.11n protocol specification went through several incompatible iterations.
+Some vendors implemented 11n support to older specifications that
+will not interoperate with a purely 11n-compliant station.
+In particular the information elements included in management frames
+for old devices are different.
+When compatibility support is enabled both standard and compatible data
+will be provided.
+Stations that associate using the compatiblity mechanisms are flagged
+in ``list sta''.
+To disable compatiblity support use
+.Fl htcompat .
+.It Cm htprotmode Ar technique
+For interfaces operating in 802.11n, use the specified
+.Ar technique
+for protecting HT frames in a mixed legacy/HT network.
+The set of valid techniques is
+.Cm off ,
+and
+.Cm rts
+(RTS/CTS, default).
+Technique names are case insensitive.
+.It Cm inact
+Enable inactivity processing for stations associated to an
+access point (default).
+When operating as an access point the 802.11 layer monitors
+the activity of each associated station.
+When a station is inactive for 5 minutes it will send several
+``probe frames'' to see if the station is still present.
+If no response is received then the station is deauthenticated.
+Applications that prefer to handle this work can disable this
+facility by using
+.Fl inact .
+.It Cm indoor
+Set the location to use in calculating regulatory constraints.
+The location is also advertised in beacon and probe response frames
+when 802.11d is enabled with
+.Cm dotd .
+See also
+.Cm outdoor ,
+.Cm anywhere ,
+.Cm country ,
+and
+.Cm regdomain .
 .It Cm list active
 Display the list of channels available for use taking into account
 any restrictions set with the
@@ -728,8 +1134,8 @@ mode.
 Channels identified as
 .Ql 11a Turbo
 may be used only for Atheros' Static Turbo mode
-specified with
-.Cm mediaopt turbo ) .
+(specified with
+. Cm mediaopt turbo ) .
 Channels marked with a
 .Ql *
 have a regulatory constraint that they be passively scanned.
@@ -739,6 +1145,12 @@ typically by hearing a beacon frame from an access point operating
 on the channel.
 .Cm list freq
 is another way of requesting this information.
+By default a compacted list of channels is displayed; if the
+.Fl v
+option is specified then all channels are shown.
+.It Cm list countries
+Display the set of country codes and regulatory domains that can be
+used in regulatory configuration.
 .It Cm list mac
 Display the current MAC Access Control List state.
 Each address is prefixed with a character that indicates the
@@ -750,63 +1162,186 @@ indicates the address is denied access,
 .Ql *
 indicates the address is present but the current policy open
 (so the ACL is not consulted).
+.It Cm list mesh
+Displays the mesh routing table, used for forwarding packets on a mesh
+network.
+.It Cm list regdomain
+Display the current regulatory settings including the available channels
+and transmit power caps.
+.It Cm list roam
+Display the parameters that govern roaming operation.
+.It Cm list txparam
+Display the parameters that govern transmit operation.
+.It Cm list txpower
+Display the transmit power caps for each channel.
 .It Cm list scan
 Display the access points and/or ad-hoc neighbors
 located in the vicinity.
-The
-.Fl v
-flag may be used to display long SSIDs.
-This information may be updated automatically by the adaptor
-and/or with a
+This information may be updated automatically by the adapter
+with a
 .Cm scan
-request.
+request or through background scanning.
+Depending on the capabilities of the stations the following
+flags can be included in the output:
+.Bl -tag -width 3n
+.It Li A
+Authorized.
+Indicates that the station is permitted to send/receive data frames.
+.It Li E
+Extended Rate Phy (ERP).
+Indicates that the station is operating in an 802.11g network
+using extended transmit rates.
+.It Li H
+High Throughput (HT).
+Indicates that the station is using HT transmit rates.
+If a `+' follows immediately after then the station associated
+using deprecated mechanisms supported only when
+.Cm htcompat
+is enabled.
+.It Li P
+Power Save.
+Indicates that the station is operating in power save mode.
+.It Li Q
+Quality of Service (QoS).
+Indicates that the station is using QoS encapsulation for
+data frame.
+QoS encapsulation is enabled only when WME mode is enabled.
+.It Li T
+Transitional Security Network (TSN).
+Indicates that the station associated using TSN; see also
+.Cm tsn
+below.
+.It Li W
+Wi-Fi Protected Setup (WPS).
+Indicates that the station associated using WPS.
+.El
+.Pp
+By default interesting information elements captured from the neighboring
+stations are displayed at the end of each row.
+Possible elements include:
+.Cm WME
+(station supports WME),
+.Cm WPA
+(station supports WPA),
+.Cm WPS
+(station supports WPS),
+.Cm RSN
+(station supports 802.11i/RSN),
+.Cm HTCAP
+(station supports 802.11n/HT communication),
+.Cm ATH
+(station supports Atheros protocol extensions),
+.Cm VEN
+(station supports unknown vendor-specific extensions).
+If the
+.Fl v
+flag is used all the information elements and their
+contents will be shown.
+Specifying the
+.Fl v
+flag also enables display of long SSIDs.
+The
 .Cm list ap
-is another way of requesting this information.
+command is another way of requesting this information.
 .It Cm list sta
 When operating as an access point display the stations that are
 currently associated.
 When operating in ad-hoc mode display stations identified as
 neighbors in the IBSS.
+When operating in mesh mode display stations identified as
+neighbors in the MBSS.
+When operating in station mode display the access point.
+Capabilities advertised by the stations are described under
+the
+.Cm scan
+request.
+Depending on the capabilities of the stations the following
+flags can be included in the output:
+.Bl -tag -width 3n
+.It Li A
+Authorized.
+Indicates that the station is permitted to send/receive data frames.
+.It Li E
+Extended Rate Phy (ERP).
+Indicates that the station is operating in an 802.11g network
+using extended transmit rates.
+.It Li H
+High Throughput (HT).
+Indicates that the station is using HT transmit rates.
+If a `+' follows immediately after then the station associated
+using deprecated mechanisms supported only when
+.Cm htcompat
+is enabled.
+.It Li P
+Power Save.
+Indicates that the station is operating in power save mode.
+.It Li Q
+Quality of Service (QoS).
+Indicates that the station is using QoS encapsulation for
+data frame.
+QoS encapsulation is enabled only when WME mode is enabled.
+.It Li T
+Transitional Security Network (TSN).
+Indicates that the station associated using TSN; see also
+.Cm tsn
+below.
+.It Li W
+Wi-Fi Protected Setup (WPS).
+Indicates that the station associated using WPS.
+.El
+.Pp
+By default information elements received from associated stations
+are displayed in a short form; the
+.Fl v
+flag causes this information to be displayed symbolically.
 .It Cm list wme
-Display the current parameters to use when operating in WME mode.
+Display the current channel parameters to use when operating in WME mode.
+If the
+.Fl v
+option is specified then both channel and BSS parameters are displayed
+for each AC (first channel, then BSS).
 When WME mode is enabled for an adaptor this information will be
 displayed with the regular status; this command is mostly useful
 for examining parameters when WME mode is disabled.
 See the description of the
 .Cm wme
 directive for information on the various parameters.
+.It Cm maxretry Ar count
+Set the maximum number of tries to use in sending unicast frames.
+The default setting is 6 but drivers may override this with a value
+they choose.
 .It Cm mcastrate Ar rate
 Set the rate for transmitting multicast/broadcast frames.
-Rates are specified as megabits/second in decimal; e.g.\& 5.5 for 5.5 Mbit/s.
+Rates are specified as megabits/second in decimal; e.g.\& 5.5 for 5.5 Mb/s.
 This rate should be valid for the current operating conditions;
 if an invalid rate is specified drivers are free to chose an
 appropriate rate.
+.It Cm mgtrate Ar rate
+Set the rate for transmitting management and/or control frames.
+Rates are specified as megabits/second in decimal; e.g.\& 5.5 for 5.5 Mb/s.
+.It Cm outdoor
+Set the location to use in calculating regulatory constraints.
+The location is also advertised in beacon and probe response frames
+when 802.11d is enabled with
+.Cm dotd .
+See also
+.Cm anywhere ,
+.Cm country ,
+.Cm indoor ,
+and
+.Cm regdomain .
 .It Cm powersave
 Enable powersave operation.
 When operating as a client, the station will conserve power by
 periodically turning off the radio and listening for
 messages from the access point telling it there are packets waiting.
 The station must then retrieve the packets.
-When operating as an access point, the station must honor power
-save operation of associated clients.
-Not all devices support power save operation, either as a client
-or as an access point.
+Not all devices support power save operation as a client.
+The 802.11 specification requires that all access points support
+power save but some drivers do not.
 Use
 .Fl powersave
-to disable powersave operation.
-.It Cm powersavemode Ar mode
-Set powersave mode.
-The set of valid modes is
-.Cm off
-(same as
-.Fl powersave ) ,
-.Cm on
-(same as
-.Cm powersave ) ,
-and
-.Cm cam
-(same as
-.Cm powersave ) .
+to disable powersave operation when operating as a client.
 .It Cm powersavesleep Ar sleep
 Set the desired max powersave sleep time in TU's (1024 usecs).
 By default the max powersave sleep time is 100 TU's.
@@ -821,12 +1356,76 @@ and
 .Cm rtscts
 (RTS/CTS).
 Technique names are case insensitive.
+Not all devices support
+.Cm cts
+as a protection technique.
 .It Cm pureg
 When operating as an access point in 802.11g mode allow only
 11g-capable stations to associate (11b-only stations are not
 permitted to associate).
 To allow both 11g and 11b-only stations to associate, use
 .Fl pureg .
+.It Cm puren
+When operating as an access point in 802.11n mode allow only
+HT-capable stations to associate (legacy stations are not
+permitted to associate).
+To allow both HT and legacy stations to associate, use
+.Fl puren .
+.It Cm regdomain Ar sku
+Set the regulatory domain to use in calculating the regulatory constraints
+for operation.
+In particular the set of available channels, how the wireless device
+will operation on the channels, and the maximum transmit power that
+can be used on a channel are defined by this setting.
+Regdomain codes (SKU's) are taken from /etc/regdomain.xml and can also
+be viewed with the ``list countries'' request.
+Note that not all devices support changing the regdomain from a default
+setting; typically stored in EEPROM.
+See also
+.Cm country ,
+.Cm indoor ,
+.Cm outdoor ,
+and
+.Cm anywhere .
+.It Cm rifs
+Enable use of Reduced InterFrame Spacing (RIFS) when operating in 802.11n
+on an HT channel.
+Note that RIFS must be supported by both the station and access point
+for it to be used.
+To disable RIFS use
+.Fl rifs .
+.It Cm roam:rate Ar rate
+Set the threshold for controlling roaming when operating in a BSS.
+The
+.Ar rate
+parameter specifies the transmit rate in megabits
+at which roaming should be considered.
+If the current transmit rate drops below this setting and background scanning
+is enabled, then the system will check if a more desirable access point is
+available and switch over to it.
+The current scan cache contents are used if they are considered
+valid according to the
+.Cm scanvalid
+parameter; otherwise a background scan operation is triggered before
+any selection occurs.
+Each channel type has a separate rate threshold; the default values are:
+12 Mb/s (11a), 2 Mb/s (11b), 2 Mb/s (11g), MCS 1 (11na, 11ng).
+.It Cm roam:rssi Ar rssi
+Set the threshold for controlling roaming when operating in a BSS.
+The
+.Ar rssi
+parameter specifies the receive signal strength in dBm units
+at which roaming should be considered.
+If the current rssi drops below this setting and background scanning
+is enabled, then the system will check if a more desirable access point is
+available and switch over to it.
+The current scan cache contents are used if they are considered
+valid according to the
+.Cm scanvalid
+parameter; otherwise a background scan operation is triggered before
+any selection occurs.
+Each channel type has a separate rssi threshold; the default values are
+all 7 dBm.
 .It Cm roaming Ar mode
 When operating as a station, control how the system will
 behave when communication with the current access point
@@ -843,22 +1442,9 @@ argument may be one of
 By default, the device is left to handle this if it is
 capable; otherwise, the operating system will automatically
 attempt to reestablish communication.
-Manual mode is mostly useful when an application wants to
-control the selection of an access point.
-.It Cm ratectl Ar algorithm
-Set the TX rate control algorithm.
-The set of valid
-.Ar algorithm
-is
-.Cm onoe
-(Onoe TX rate control algorithm),
-.Cm sample
-(Sample TX rate control algorithm)
-and
-.Cm amrr
-(AMRR TX rate control algorithm).
-.Ar Algorithm
-names are case sensitive.
+Manual mode is used by applications such as
+.Xr wpa_supplicant 8
+that want to control the selection of an access point.
 .It Cm rtsthreshold Ar length
 Set the threshold for which
 transmitted frames are preceded by transmission of an
@@ -876,96 +1462,141 @@ to
 or
 .Cm -
 disables transmission of RTS frames.
-Not all adaptors support setting the RTS threshold.
-.It Cm ssid Ar ssid
-Set the desired Service Set Identifier (aka network name).
-The SSID is a string up to 32 characters
-in length and may be specified as either a normal string or in
-hexadecimal when preceded by
-.Ql 0x .
-Additionally, the SSID may be cleared by setting it to
-.Ql - .
+Not all adapters support setting the RTS threshold.
 .It Cm scan
 Initiate a scan of neighboring stations, wait for it to complete, and
 display all stations found.
 Only the super-user can initiate a scan.
-Depending on the capabilities of the APs, the following
-flags can be included in the output:
-.Bl -tag -width 3n
-.It Li A
-Channel Agility.
-Indicates that the station support channel hopping as described by the
-IEEE 802.11b specification.
-.It Li B
-Packet Binary Convolution Code (PBCC).
-A modulation alternative to the standard OFDM method.
-.It Li C
-Pollreq
-.It Li c
-Pollable
-.It Li D
-Direct Sequence Spread Spectrum - Orthogonal Frequency Division
-Multiplexing (DSSS-OFDM).
-Indicates the the station supports DSSS-OFDM modulation.
-.It Li E
-Extended Service Set (ESS).
-Indicates that the station is part of an infrastructure network
-(in contrast to an IBSS/ad-hoc network).
-.It Li I
-IBSS/ad-hoc network.
-Indicates that the station is part of an ad-hoc network
-(in contrast to an ESS network).
-.It Li P
-Privacy.
-Data confidentiality is required for all data frames
-exchanged within the BSS.
-This means that this BSS requires the station to
-use cryptographic means such as WEP, TKIP or AES-CCMP to
-encrypt/decrypt data frames being exchanged with others.
-.It Li R
-Robust Security Network (RSN).
-Indicates that the station supports the IEEE 802.11i authentication
-and key management protocol.
-.It Li S
-Short Preamble.
-Indicates that the network is using short preambles (defined
-in 802.11b High Rate/DSSS PHY, short preamble utilizes a
-56 bit sync field in contrast to a 128 bit field used in long
-preamble mode).
-.It Li s
-Short slot time.
-Indicates that the network is using a short slot time.
-.El
-.Pp
+See
+.Cm list scan
+for information on the display.
+By default a background scan is done; otherwise a foreground
+scan is done and the station may roam to a different access point.
 The
 .Cm list scan
 request can be used to show recent scan results without
 initiating a new scan.
-.Pp
+.It Cm scanvalid Ar threshold
+Set the maximum time the scan cache contents are considered valid;
+i.e. will be used without first triggering a scan operation to
+refresh the data.
 The
-.Fl v
-flag may be used to prevent the shortening of long SSIDs.
-.It Cm stationname Ar name
-Set the name of this station.
-It appears that the station name is not really part of the IEEE 802.11
-protocol though all interfaces seem to support it.
-As such it only
-seems to be meaningful to identical or virtually identical equipment.
-Setting the station name is identical in syntax to setting the SSID.
+.Ar threshold
+parameter is specified in seconds and defaults to 60 seconds.
+The minimum setting for
+.Ar threshold
+is 10 seconds.
+One should take care setting this threshold; if it is set too low
+then attempts to roam to another access point may trigger unnecessary
+background scan operations.
+.It Cm shortgi
+Enable use of Short Guard Interval when operating in 802.11n
+on an HT channel.
+NB: this currently enables Short GI on both HT40 and HT20 channels.
+To disable Short GI use
+.Fl shortgi .
+.It Cm smps
+Enable use of Static Spatial Multiplexing Power Save (SMPS)
+when operating in 802.11n.
+A station operating with Static SMPS maintains only a single
+receive chain active (this can significantly reduce power consumption).
+To disable SMPS use
+.Fl smps .
+.It Cm smpsdyn
+Enable use of Dynamic Spatial Multiplexing Power Save (SMPS)
+when operating in 802.11n.
+A station operating with Dynamic SMPS maintains only a single
+receive chain active but switches to multiple receive chains when it
+receives an RTS frame (this can significantly reduce power consumption).
+Note that stations cannot distinguish between RTS/CTS intended to
+enable multiple receive chains and those used for other purposes.
+To disable SMPS use
+.Fl smps .
+.It Cm ssid Ar ssid
+Set the desired Service Set Identifier (aka network name).
+The SSID is a string up to 32 characters
+in length and may be specified as either a normal string or in
+hexadecimal when preceded by
+.Ql 0x .
+Additionally, the SSID may be cleared by setting it to
+.Ql - .
+.It Cm tdmaslot Ar slot
+When operating with TDMA, use the specified
+.Ar slot
+configuration.
+The
+.Ar slot
+is a number between 0 and the maximum number of slots in the BSS.
+Note that a station configured as slot 0 is a master and
+will broadcast beacon frames advertising the BSS;
+stations configured to use other slots will always
+scan to locate a master before they ever transmit.
+By default
+.Cm tdmaslot
+is set to 1.
+.It Cm tdmaslotcnt Ar cnt
+When operating with TDMA, setup a BSS with
+.Ar cnt
+slots.
+The slot count may be at most 8.
+The current implementation is only tested with two stations
+(i.e. point to point applications).
+This setting is only meaningful when a station is configured as slot 0;
+other stations adopt this setting from the BSS they join.
+By default
+.Cm tdmaslotcnt
+is set to 2.
+.It Cm tdmaslotlen Ar len
+When operating with TDMA, setup a BSS such that each station has a slot
+.Ar len
+microseconds long.
+The slot length must be at least 150 microseconds (1/8 TU)
+and no more than 65 milliseconds.
+Note that setting too small a slot length may result in poor channel
+bandwidth utilization due to factors such as timer granularity and
+guard time.
+This setting is only meaningful when a station is configured as slot 0;
+other stations adopt this setting from the BSS they join.
+By default
+.Cm tdmaslotlen
+is set to 10 milliseconds.
+.It Cm tdmabintval Ar intval
+When operating with TDMA, setup a BSS such that beacons are transmitted every
+.Ar intval
+superframes to synchronize the TDMA slot timing.
+A superframe is defined as the number of slots times the slot length; e.g.
+a BSS with two slots of 10 milliseconds has a 20 millisecond superframe.
+The beacon interval may not be zero.
+A lower setting of
+.Cm tdmabintval
+causes the timers to be resynchronized more often; this can be help if
+significant timer drift is observed.
+By default
+.Cm tdmabintval
+is set to 5.
+.It Cm tsn
+When operating as an access point with WPA/802.11i allow legacy
+stations to associate using static key WEP and open authentication.
+To disallow legacy station use of WEP, use
+.Fl tsn .
 .It Cm txpower Ar power
 Set the power used to transmit frames.
 The
 .Ar power
-argument
-is a unitless value in the range 0 to 100 that is interpreted
-by drivers to derive a device-specific value.
+argument is specified in .5 dBm units.
 Out of range values are truncated.
 Typically only a few discreet power settings are available and
 the driver will use the setting closest to the specified value.
-Not all adaptors support changing the transmit power.
+Not all adapters support changing the transmit power.
+.It Cm ucastrate Ar rate
+Set a fixed rate for transmitting unicast frames.
+Rates are specified as megabits/second in decimal; e.g.\& 5.5 for 5.5 Mb/s.
+This rate should be valid for the current operating conditions;
+if an invalid rate is specified drivers are free to chose an
+appropriate rate.
 .It Cm wepmode Ar mode
 Set the desired WEP mode.
-Not all adaptors support all modes.
+Not all adapters support all modes.
 The set of valid modes is
 .Cm off , on ,
 and
@@ -974,10 +1605,10 @@ The
 .Cm mixed
 mode explicitly tells the adaptor to allow association with access
 points which allow both encrypted and unencrypted traffic.
-On these adaptors,
+On these adapters,
 .Cm on
 means that the access point must only allow encrypted connections.
-On other adaptors,
+On other adapters,
 .Cm on
 is generally another name for
 .Cm mixed .
@@ -1002,14 +1633,18 @@ the mapping of text keys to WEP encryption is usually driver-specific.
 In particular, the
 .Tn Windows
 drivers do this mapping differently to
-.Dx .
+.Fx .
 A key may be cleared by setting it to
 .Ql - .
 If WEP is supported then there are at least four keys.
-Some adaptors support more than four keys.
+Some adapters support more than four keys.
 If that is the case, then the first four keys
 (1-4) will be the standard temporary keys and any others will be adaptor
 specific keys such as permanent keys stored in NVRAM.
+.Pp
+Note that you must set a default transmit key with
+.Cm deftxkey
+for the system to know which key to use in encrypting outbound traffic.
 .It Cm wme
 Enable Wireless Multimedia Extensions (WME) support, if available,
 for the specified interface.
@@ -1017,6 +1652,8 @@ WME is a subset of the IEEE 802.11e standard to support the
 efficient communication of realtime and multimedia data.
 To disable WME support, use
 .Fl wme .
+Another name for this parameter is
+.Cm wmm .
 .Pp
 The following parameters are meaningful only when WME support is in use.
 Parameters are specified per-AC (Access Category) and
@@ -1103,10 +1740,15 @@ This parameter is meaningful only when operating in ap mode.
 Set the TxOpLimit channel access parameter to send to stations in a BSS.
 This parameter is meaningful only when operating in ap mode.
 .El
+.It Cm wps
+Enable Wireless Privacy Subscriber support.
+Note that WPS support requires a WPS-capable supplicant.
+To disable this function use
+.Fl wps .
 .El
 .Pp
 The following parameters support an optional access control list
-feature available with some adaptors when operating in ap mode; see
+feature available with some adapters when operating in ap mode; see
 .Xr wlan_acl 4 .
 This facility allows an access point to accept/deny association
 requests based on the MAC address of the station.
@@ -1133,6 +1775,93 @@ address database.
 Set the ACL policy to allow all stations to associate.
 .It Cm mac:flush
 Delete all entries in the database.
+.It Cm mac:radius
+Set the ACL policy to permit association only by
+stations approved by a RADIUS server.
+Note that this feature requires the
+.Xr hostapd 8
+program be configured to do the right thing
+as it handles the RADIUS processing
+(and marks stations as authorized).
+.El
+.Pp
+The following parameters are related to a wireless interface operating in mesh
+mode:
+.Bl -tag -width indent
+.It Cm meshid Ar meshid
+Set the desired Mesh Identifier.
+The Mesh ID is a string up to 32 characters in length.
+A mesh interface must have a Mesh Identifier specified
+to reach an operational state.
+.It Cm meshttl Ar ttl
+Set the desired ``time to live'' for mesh forwarded packets;
+this is the number of hops a packet may be forwarded before
+it is discarded.
+The default setting for
+.Cm meshttl
+is 31.
+.It Cm meshpeering
+Enable or disable peering with neighbor mesh stations.
+Stations must peer before any data packets can be exchanged.
+By default
+.Cm meshpeering
+is enabled.
+.It Cm meshforward
+Enable or disable forwarding packets by a mesh interface.
+By default
+.Cm meshforward
+is enabled.
+.It Cm meshmetric Ar protocol
+Set the specified
+.Ar protocol
+as the link metric protocol used on a mesh network.
+The default protocol is called
+.Ar AIRTIME .
+The mesh interface will restart after changing this setting.
+.It Cm meshpath Ar protocol
+Set the specified
+.Ar protocol
+as the path selection protocol used on a mesh network.
+The only available protocol at the moment is called
+.Ar HWMP
+(Hybrid Wireless Mesh Protocol).
+The mesh interface will restart after changing this setting.
+.It Cm hwmprootmode Ar mode
+Stations on a mesh network can operate as ``root nodes.''
+Root nodes try to find paths to all mesh nodes and advertise themselves
+regularly.
+When there is a root mesh node on a network, other mesh nodes can setup
+paths between themselves faster because they can use the root node
+to find the destination.
+This path may not be the best, but on-demand
+routing will eventually find the best path.
+The following modes are recognized:
+.Pp
+.Bl -tag -width ".Cm PROACTIVE" -compact
+.It Cm DISABLED
+Disable root mode.
+.It Cm NORMAL
+Send broadcast path requests every two seconds.
+Nodes on the mesh without a path to this root mesh station with try to
+discover a path to us.
+.It Cm PROACTIVE
+Send broadcast path requests every two seconds and every node must reply with
+with a path reply even if it already has a path to this root mesh station,
+.It Cm RANN
+Send broadcast root annoucement (RANN) frames.
+Nodes on the mesh without a path to this root mesh station with try to
+discover a path to us.
+.El
+By default
+.Cm hwmprootmode 
+is set to
+.Ar DISABLED .
+.It Cm hwmpmaxhops Ar cnt
+Set the maximum number of hops allowed in an HMWP path to
+.Ar cnt .
+The default setting for
+.Cm hwmpmaxhops
+is 31.
 .El
 .Pp
 The following parameters are for compatibility with other systems:
@@ -1144,11 +1873,16 @@ parameter.
 Included for
 .Nx
 compatibility.
-.It Cm station Ar name
-Another name for the
-.Cm stationname
-parameter.
-Included for
+.It Cm stationname Ar name
+Set the name of this station.
+The station name is not part of the IEEE 802.11
+protocol though some interfaces support it.
+As such it only
+seems to be meaningful to identical or virtually identical equipment.
+Setting the station name is identical in syntax to setting the SSID.
+One can also use
+.Cm station
+for
 .Bsx
 compatibility.
 .It Cm wep
index eb02915..8e0554e 100644 (file)
@@ -95,7 +95,7 @@ int   supmedia = 0;
 int    printkeys = 0;          /* Print keying material for interfaces. */
 int    printname = 0;          /* Print the name of the created interface. */
 
-static int ifconfig(int argc, char *const *argv, const struct afswtch *afp);
+static int ifconfig(int argc, char *const *argv, int, const struct afswtch *afp);
 static void status(const struct afswtch *afp, int addrcount,
                    struct sockaddr_dl *sdl, struct if_msghdr *ifm,
                    struct ifa_msghdr *ifam);
@@ -153,7 +153,9 @@ main(int argc, char *argv[])
        size_t needed;
        int mib[6];
        char options[1024];
+       const char *ifname;
        struct option *p;
+        size_t iflen;
 
        all = downonly = uponly = namesonly = verbose = 0;
 
@@ -215,6 +217,7 @@ main(int argc, char *argv[])
                if (argc > 1)
                        usage();
 
+               ifname = NULL;
                ifindex = 0;
                if (argc == 1) {
                        afp = af_getbyname(*argv);
@@ -229,27 +232,29 @@ main(int argc, char *argv[])
                if (argc < 1)
                        usage();
 
-               strncpy(name, *argv, sizeof(name));
+               ifname = *argv;
                argc--, argv++;
 
                /* check and maybe load support for this interface */
                ifmaybeload(name);
-
-               /*
-                * NOTE:  We must special-case the `create' command right
-                * here as we would otherwise fail when trying to find
-                * the interface.
-                */
-               if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
-                   strcmp(argv[0], "plumb") == 0)) {
-                       clone_create();
-                       argc--, argv++;
-                       if (argc == 0)
-                               goto end;
-               }
-               ifindex = if_nametoindex(name);
-               if (ifindex == 0)
+               ifindex = if_nametoindex(ifname);
+               if (ifindex == 0) {
+                       /*
+                        * NOTE:  We must special-case the `create' command
+                        * right here as we would otherwise fail when trying
+                        * to find the interface.
+                        */
+                       if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
+                           strcmp(argv[0], "plumb") == 0)) {
+                               iflen = strlcpy(name, ifname, sizeof(name));
+                               if (iflen >= sizeof(name))
+                                       errx(1, "%s: cloning name too long",
+                                           ifname);
+                               ifconfig(argc, argv, 1, NULL);
+                               exit(0);
+                       }
                        errx(1, "interface %s does not exist", name);
+               }
        }
 
        /* Check for address family */
@@ -357,7 +362,7 @@ retry:
                }
 
                if (argc > 0)
-                       ifconfig(argc, argv, afp);
+                       ifconfig(argc, argv, 0, afp);
                else
                        status(afp, addrcount, sdl, ifm, ifam);
        }
@@ -447,13 +452,20 @@ cmd_register(struct cmd *p)
 }
 
 static const struct cmd *
-cmd_lookup(const char *name)
+cmd_lookup(const char *name, int iscreate)
 {
 #define        N(a)    (sizeof(a)/sizeof(a[0]))
        const struct cmd *p;
 
        for (p = cmds; p != NULL; p = p->c_next)
                if (strcmp(name, p->c_name) == 0)
+                       if (iscreate) {
+                               if (p->c_iscloneop)
+                                       return p;
+                       } else {
+                               if (!p->c_iscloneop)
+                                       return p;
+                       }
                        return p;
        return NULL;
 #undef N
@@ -489,17 +501,18 @@ static const struct cmd setifdstaddr_cmd =
        DEF_CMD("ifdstaddr", 0, setifdstaddr);
 
 static int
-ifconfig(int argc, char *const *argv, const struct afswtch *afp)
+ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *uafp)
 {
+       const struct afswtch *afp, *nafp;
        struct callback *cb;
        int s;
 
-       if (afp == NULL)
-               afp = af_getbyname("inet");
+       strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
+       afp = uafp != NULL ? uafp : af_getbyname("inet");
+top:
        ifr.ifr_addr.sa_family =
                afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ?
                AF_INET : afp->af_af;
-       strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
 
        if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0)
                err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family);
@@ -507,7 +520,39 @@ ifconfig(int argc, char *const *argv, const struct afswtch *afp)
        while (argc > 0) {
                const struct cmd *p;
 
-               p = cmd_lookup(*argv);
+               p = cmd_lookup(*argv, iscreate);
+
+                if (iscreate && p == NULL) {
+                        /*
+                         * Push the clone create callback so the new
+                         * device is created and can be used for any
+                         * remaining arguments.
+                         */
+                        cb = callbacks;
+                        if (cb == NULL)
+                                errx(1, "internal error, no callback");
+                        callbacks = cb->cb_next;
+                        cb->cb_func(s, cb->cb_arg);
+                        iscreate = 0;
+                        /*
+                         * Handle any address family spec that
+                         * immediately follows and potentially
+                         * recreate the socket.
+                         */
+                        nafp = af_getbyname(*argv);
+                        if (nafp != NULL) {
+                                argc--, argv++;
+                                if (nafp != afp) {
+                                        close(s);
+                                        afp = nafp;
+                                        goto top;
+                                }
+                        }
+                        /*
+                         * Look for a normal parameter.
+                         */
+                        continue;
+               }
                if (p == NULL) {
                        /*
                         * Not a recognized command, choose between setting
index f82f9d8..cf7025a 100644 (file)
@@ -53,6 +53,7 @@ struct cmd {
                c_func  *c_func;
                c_func2 *c_func2;
        } c_u;
+       int     c_iscloneop;
        struct cmd *c_next;
 };
 void   cmd_register(struct cmd *);
@@ -68,11 +69,20 @@ void        callback_register(callback_func *, void *);
 #define        DECL_CMD_FUNC2(name, arg1, arg2)        \
        void name(const char *arg1, const char *arg2, int s, const struct afswtch *afp)
 
-#define        DEF_CMD(name, param, func)      { name, param, { .c_func = func } }
+#define        DEF_CMD(name, param, func)      \
+       { name, param, { .c_func = func }, 0, NULL }
 #define        DEF_CMD_ARG(name, func)         \
-       { .c_name = name, .c_parameter = NEXTARG, .c_u = { .c_func = func } }
-#define        DEF_CMD_OPTARG(name, func)      { name, OPTARG, { .c_func = func } }
-#define        DEF_CMD_ARG2(name, func)        { name, NEXTARG2, { .c_func2 = func } }
+       { .c_name = name, .c_parameter = NEXTARG, \
+               .c_u = { .c_func = func }, 0, NULL }
+#define        DEF_CMD_OPTARG(name, func)      \
+       { name, OPTARG, { .c_func = func }, 0, NULL }
+#define        DEF_CMD_ARG2(name, func)        \
+       { name, NEXTARG2, { .c_func2 = func }, 0, NULL }
+#define        DEF_CLONE_CMD(name, param, func) \
+       { name, param, { .c_func = func }, 1, NULL }
+#define        DEF_CLONE_CMD_ARG(name, func)   \
+       { name, NEXTARG, { .c_func = func }, 1, NULL }
+
 
 struct rt_addrinfo;
 struct addrinfo;
@@ -142,4 +152,11 @@ void       printb(const char *s, unsigned value, const char *bits);
 
 void   ifmaybeload(char *);
 
-void   clone_create(void);
+typedef void clone_callback_func(int, struct ifreq *);
+void    clone_setdefcallback(const char *, clone_callback_func *);
+
+/*
+ * XXX expose this so modules that neeed to know of any pending
+ * operations on ifmedia can avoid cmd line ordering confusion.
+ */
+struct ifmediareq *ifmedia_getstate(int s);
index 3cc768f..0027b59 100644 (file)
@@ -24,8 +24,8 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sbin/ifconfig/ifieee80211.c,v 1.18.2.10 2006/08/10 06:09:23 sam Exp $
- * $DragonFly: src/sbin/ifconfig/ifieee80211.c,v 1.20 2008/01/19 07:34:13 sephe Exp $
+ * $FreeBSD: head/sbin/ifconfig/ifieee80211.c 203970 2010-02-16 21:39:20Z imp $
+ * $DragonFly$
  */
 
 /*-
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the NetBSD
- *     Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- *    contributors may be used to endorse or promote products derived
- *    from this software without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 #include <net/if_media.h>
 #include <net/route.h>
 
-#include <netproto/802_11/ieee80211.h>
-#include <netproto/802_11/ieee80211_crypto.h>
 #include <netproto/802_11/ieee80211_ioctl.h>
-#include <netproto/802_11/ieee80211_ratectl.h>
+#include <netproto/802_11/ieee80211_dragonfly.h>
+#include <netproto/802_11/ieee80211_superg.h>
+#include <netproto/802_11/ieee80211_tdma.h>
+#include <netproto/802_11/ieee80211_mesh.h>
 
+#include <assert.h>
 #include <ctype.h>
 #include <err.h>
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdarg.h>
+#include <stddef.h>            /* NB: for offsetof */
 
 #include "ifconfig.h"
+#include "regdomain.h"
+
+#ifndef IEEE80211_FIXED_RATE_NONE
+#define        IEEE80211_FIXED_RATE_NONE       0xff
+#endif
+
+/* XXX need these publicly defined or similar */
+#ifndef IEEE80211_NODE_AUTH
+#define        IEEE80211_NODE_AUTH     0x000001        /* authorized for data */
+#define        IEEE80211_NODE_QOS      0x000002        /* QoS enabled */
+#define        IEEE80211_NODE_ERP      0x000004        /* ERP enabled */
+#define        IEEE80211_NODE_PWR_MGT  0x000010        /* power save mode enabled */
+#define        IEEE80211_NODE_AREF     0x000020        /* authentication ref held */
+#define        IEEE80211_NODE_HT       0x000040        /* HT enabled */
+#define        IEEE80211_NODE_HTCOMPAT 0x000080        /* HT setup w/ vendor OUI's */
+#define        IEEE80211_NODE_WPS      0x000100        /* WPS association */
+#define        IEEE80211_NODE_TSN      0x000200        /* TSN association */
+#define        IEEE80211_NODE_AMPDU_RX 0x000400        /* AMPDU rx enabled */
+#define        IEEE80211_NODE_AMPDU_TX 0x000800        /* AMPDU tx enabled */
+#define        IEEE80211_NODE_MIMO_PS  0x001000        /* MIMO power save enabled */
+#define        IEEE80211_NODE_MIMO_RTS 0x002000        /* send RTS in MIMO PS */
+#define        IEEE80211_NODE_RIFS     0x004000        /* RIFS enabled */
+#define        IEEE80211_NODE_SGI20    0x008000        /* Short GI in HT20 enabled */
+#define        IEEE80211_NODE_SGI40    0x010000        /* Short GI in HT40 enabled */
+#define        IEEE80211_NODE_ASSOCID  0x020000        /* xmit requires associd */
+#define        IEEE80211_NODE_AMSDU_RX 0x040000        /* AMSDU rx enabled */
+#define        IEEE80211_NODE_AMSDU_TX 0x080000        /* AMSDU tx enabled */
+#endif
+
+#define        MAXCHAN 1536            /* max 1.5K channels */
+
+#define        MAXCOL  78
+static int col;
+static char spacer;
+
+static void LINE_INIT(char c);
+static void LINE_BREAK(void);
+static void LINE_CHECK(const char *fmt, ...);
+
+static const char *modename[IEEE80211_MODE_MAX] = {
+       [IEEE80211_MODE_AUTO]     = "auto",
+       [IEEE80211_MODE_11A]      = "11a",
+       [IEEE80211_MODE_11B]      = "11b",
+       [IEEE80211_MODE_11G]      = "11g",
+       [IEEE80211_MODE_FH]       = "fh",
+       [IEEE80211_MODE_TURBO_A]  = "turboA",
+       [IEEE80211_MODE_TURBO_G]  = "turboG",
+       [IEEE80211_MODE_STURBO_A] = "sturbo",
+       [IEEE80211_MODE_11NA]     = "11na",
+       [IEEE80211_MODE_11NG]     = "11ng",
+       [IEEE80211_MODE_HALF]     = "half",
+       [IEEE80211_MODE_QUARTER]  = "quarter"
+};
 
-static void set80211(int s, int type, int val, int len, u_int8_t *data);
+static void set80211(int s, int type, int val, int len, void *data);
+static int get80211(int s, int type, void *data, int len);
+static int get80211len(int s, int type, void *data, int len, int *plen);
+static int get80211val(int s, int type, int *val);
 static const char *get_string(const char *val, const char *sep,
     u_int8_t *buf, int *lenp);
 static void print_string(const u_int8_t *buf, int len);
+static void print_regdomain(const struct ieee80211_regdomain *, int);
+static void print_channels(int, const struct ieee80211req_chaninfo *,
+    int allchans, int verbose);
+static void regdomain_makechannels(struct ieee80211_regdomain_req *,
+    const struct ieee80211_devcaps_req *);
+static const char *mesh_linkstate_string(uint8_t state);
+
+static struct ieee80211req_chaninfo *chaninfo;
+static struct ieee80211_regdomain regdomain;
+static int gotregdomain = 0;
+static struct ieee80211_roamparams_req roamparams;
+static int gotroam = 0;
+static struct ieee80211_txparams_req txparams;
+static int gottxparams = 0;
+static struct ieee80211_channel curchan;
+static int gotcurchan = 0;
+static struct ifmediareq *ifmr;
+static int htconf = 0;
+static int gothtconf = 0;
+
+static void
+gethtconf(int s)
+{
+       if (gothtconf)
+               return;
+       if (get80211val(s, IEEE80211_IOC_HTCONF, &htconf) < 0)
+               warn("unable to get HT configuration information");
+       gothtconf = 1;
+}
+
+/*
+ * Collect channel info from the kernel.  We use this (mostly)
+ * to handle mapping between frequency and IEEE channel number.
+ */
+static void
+getchaninfo(int s)
+{
+       if (chaninfo != NULL)
+               return;
+       chaninfo = malloc(IEEE80211_CHANINFO_SIZE(MAXCHAN));
+       if (chaninfo == NULL)
+               errx(1, "no space for channel list");
+       if (get80211(s, IEEE80211_IOC_CHANINFO, chaninfo,
+           IEEE80211_CHANINFO_SIZE(MAXCHAN)) < 0)
+               err(1, "unable to get channel information");
+       ifmr = ifmedia_getstate(s);
+       gethtconf(s);
+}
+
+static struct regdata *
+getregdata(void)
+{
+       static struct regdata *rdp = NULL;
+       if (rdp == NULL) {
+               rdp = lib80211_alloc_regdata();
+               if (rdp == NULL)
+                       errx(-1, "missing or corrupted regdomain database");
+       }
+       return rdp;
+}
+
+/*
+ * Given the channel at index i with attributes from,
+ * check if there is a channel with attributes to in
+ * the channel table.  With suitable attributes this
+ * allows the caller to look for promotion; e.g. from
+ * 11b > 11g.
+ */
+static int
+canpromote(int i, int from, int to)
+{
+       const struct ieee80211_channel *fc = &chaninfo->ic_chans[i];
+       int j;
+
+       if ((fc->ic_flags & from) != from)
+               return i;
+       /* NB: quick check exploiting ordering of chans w/ same frequency */
+       if (i+1 < chaninfo->ic_nchans &&
+           chaninfo->ic_chans[i+1].ic_freq == fc->ic_freq &&
+           (chaninfo->ic_chans[i+1].ic_flags & to) == to)
+               return i+1;
+       /* brute force search in case channel list is not ordered */
+       for (j = 0; j < chaninfo->ic_nchans; j++) {
+               const struct ieee80211_channel *tc = &chaninfo->ic_chans[j];
+               if (j != i &&
+                   tc->ic_freq == fc->ic_freq && (tc->ic_flags & to) == to)
+               return j;
+       }
+       return i;
+}
+
+/*
+ * Handle channel promotion.  When a channel is specified with
+ * only a frequency we want to promote it to the ``best'' channel
+ * available.  The channel list has separate entries for 11b, 11g,
+ * 11a, and 11n[ga] channels so specifying a frequency w/o any
+ * attributes requires we upgrade, e.g. from 11b -> 11g.  This
+ * gets complicated when the channel is specified on the same
+ * command line with a media request that constrains the available
+ * channe list (e.g. mode 11a); we want to honor that to avoid
+ * confusing behaviour.
+ */
+static int
+promote(int i)
+{
+       /*
+        * Query the current mode of the interface in case it's
+        * constrained (e.g. to 11a).  We must do this carefully
+        * as there may be a pending ifmedia request in which case
+        * asking the kernel will give us the wrong answer.  This
+        * is an unfortunate side-effect of the way ifconfig is
+        * structure for modularity (yech).
+        *
+        * NB: ifmr is actually setup in getchaninfo (above); we
+        *     assume it's called coincident with to this call so
+        *     we have a ``current setting''; otherwise we must pass
+        *     the socket descriptor down to here so we can make
+        *     the ifmedia_getstate call ourselves.
+        */
+       int chanmode = ifmr != NULL ? IFM_MODE(ifmr->ifm_current) : IFM_AUTO;
+
+       /* when ambiguous promote to ``best'' */
+       /* NB: we abitrarily pick HT40+ over HT40- */
+       if (chanmode != IFM_IEEE80211_11B)
+               i = canpromote(i, IEEE80211_CHAN_B, IEEE80211_CHAN_G);
+       if (chanmode != IFM_IEEE80211_11G && (htconf & 1)) {
+               i = canpromote(i, IEEE80211_CHAN_G,
+                       IEEE80211_CHAN_G | IEEE80211_CHAN_HT20);
+               if (htconf & 2) {
+                       i = canpromote(i, IEEE80211_CHAN_G,
+                               IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D);
+                       i = canpromote(i, IEEE80211_CHAN_G,
+                               IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U);
+               }
+       }
+       if (chanmode != IFM_IEEE80211_11A && (htconf & 1)) {
+               i = canpromote(i, IEEE80211_CHAN_A,
+                       IEEE80211_CHAN_A | IEEE80211_CHAN_HT20);
+               if (htconf & 2) {
+                       i = canpromote(i, IEEE80211_CHAN_A,
+                               IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D);
+                       i = canpromote(i, IEEE80211_CHAN_A,
+                               IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U);
+               }
+       }
+       return i;
+}
+
+static void
+mapfreq(struct ieee80211_channel *chan, int freq, int flags)
+{
+       int i;
+
+       for (i = 0; i < chaninfo->ic_nchans; i++) {
+               const struct ieee80211_channel *c = &chaninfo->ic_chans[i];
+
+               if (c->ic_freq == freq && (c->ic_flags & flags) == flags) {
+                       if (flags == 0) {
+                               /* when ambiguous promote to ``best'' */
+                               c = &chaninfo->ic_chans[promote(i)];
+                       }
+                       *chan = *c;
+                       return;
+               }
+       }
+       errx(1, "unknown/undefined frequency %u/0x%x", freq, flags);
+}
+
+static void
+mapchan(struct ieee80211_channel *chan, int ieee, int flags)
+{
+       int i;
+
+       for (i = 0; i < chaninfo->ic_nchans; i++) {
+               const struct ieee80211_channel *c = &chaninfo->ic_chans[i];
+
+               if (c->ic_ieee == ieee && (c->ic_flags & flags) == flags) {
+                       if (flags == 0) {
+                               /* when ambiguous promote to ``best'' */
+                               c = &chaninfo->ic_chans[promote(i)];
+                       }
+                       *chan = *c;
+                       return;
+               }
+       }
+       errx(1, "unknown/undefined channel number %d flags 0x%x", ieee, flags);
+}
+
+static const struct ieee80211_channel *
+getcurchan(int s)
+{
+       if (gotcurchan)
+               return &curchan;
+       if (get80211(s, IEEE80211_IOC_CURCHAN, &curchan, sizeof(curchan)) < 0) {
+               int val;
+               /* fall back to legacy ioctl */
+               if (get80211val(s, IEEE80211_IOC_CHANNEL, &val) < 0)
+                       err(-1, "cannot figure out current channel");
+               getchaninfo(s);
+               mapchan(&curchan, val, 0);
+       }
+       gotcurchan = 1;
+       return &curchan;
+}
+
+static enum ieee80211_phymode
+chan2mode(const struct ieee80211_channel *c)
+{
+       if (IEEE80211_IS_CHAN_HTA(c))
+               return IEEE80211_MODE_11NA;
+       if (IEEE80211_IS_CHAN_HTG(c))
+               return IEEE80211_MODE_11NG;
+       if (IEEE80211_IS_CHAN_108A(c))
+               return IEEE80211_MODE_TURBO_A;
+       if (IEEE80211_IS_CHAN_108G(c))
+               return IEEE80211_MODE_TURBO_G;
+       if (IEEE80211_IS_CHAN_ST(c))
+               return IEEE80211_MODE_STURBO_A;
+       if (IEEE80211_IS_CHAN_FHSS(c))
+               return IEEE80211_MODE_FH;
+       if (IEEE80211_IS_CHAN_HALF(c))
+               return IEEE80211_MODE_HALF;
+       if (IEEE80211_IS_CHAN_QUARTER(c))
+               return IEEE80211_MODE_QUARTER;
+       if (IEEE80211_IS_CHAN_A(c))
+               return IEEE80211_MODE_11A;
+       if (IEEE80211_IS_CHAN_ANYG(c))
+               return IEEE80211_MODE_11G;
+       if (IEEE80211_IS_CHAN_B(c))
+               return IEEE80211_MODE_11B;
+       return IEEE80211_MODE_AUTO;
+}
+
+static void
+getroam(int s)
+{
+       if (gotroam)
+               return;
+       if (get80211(s, IEEE80211_IOC_ROAM,
+           &roamparams, sizeof(roamparams)) < 0)
+               err(1, "unable to get roaming parameters");
+       gotroam = 1;
+}
+
+static void
+setroam_cb(int s, void *arg)
+{
+       struct ieee80211_roamparams_req *roam = arg;
+       set80211(s, IEEE80211_IOC_ROAM, 0, sizeof(*roam), roam);
+}
+
+static void
+gettxparams(int s)
+{
+       if (gottxparams)
+               return;
+       if (get80211(s, IEEE80211_IOC_TXPARAMS,
+           &txparams, sizeof(txparams)) < 0)
+               err(1, "unable to get transmit parameters");
+       gottxparams = 1;
+}
+
+static void
+settxparams_cb(int s, void *arg)
+{
+       struct ieee80211_txparams_req *txp = arg;
+       set80211(s, IEEE80211_IOC_TXPARAMS, 0, sizeof(*txp), txp);
+}
+
+static void
+getregdomain(int s)
+{
+       if (gotregdomain)
+               return;
+       if (get80211(s, IEEE80211_IOC_REGDOMAIN,
+           &regdomain, sizeof(regdomain)) < 0)
+               err(1, "unable to get regulatory domain info");
+       gotregdomain = 1;
+}
+
+static void
+getdevcaps(int s, struct ieee80211_devcaps_req *dc)
+{
+       if (get80211(s, IEEE80211_IOC_DEVCAPS, dc,
+           IEEE80211_DEVCAPS_SPACE(dc)) < 0)
+               err(1, "unable to get device capabilities");
+}
+
+static void
+setregdomain_cb(int s, void *arg)
+{
+       struct ieee80211_regdomain_req *req;
+       struct ieee80211_regdomain *rd = arg;
+       struct ieee80211_devcaps_req *dc;
+       struct regdata *rdp = getregdata();
+
+       if (rd->country != NO_COUNTRY) {
+               const struct country *cc;
+               /*
+                * Check current country seting to make sure it's
+                * compatible with the new regdomain.  If not, then
+                * override it with any default country for this
+                * SKU.  If we cannot arrange a match, then abort.
+                */
+               cc = lib80211_country_findbycc(rdp, rd->country);
+               if (cc == NULL)
+                       errx(1, "unknown ISO country code %d", rd->country);
+               if (cc->rd->sku != rd->regdomain) {
+                       const struct regdomain *rp;
+                       /*
+                        * Check if country is incompatible with regdomain.
+                        * To enable multiple regdomains for a country code
+                        * we permit a mismatch between the regdomain and
+                        * the country's associated regdomain when the
+                        * regdomain is setup w/o a default country.  For
+                        * example, US is bound to the FCC regdomain but
+                        * we allow US to be combined with FCC3 because FCC3
+                        * has not default country.  This allows bogus
+                        * combinations like FCC3+DK which are resolved when
+                        * constructing the channel list by deferring to the
+                        * regdomain to construct the channel list.
+                        */
+                       rp = lib80211_regdomain_findbysku(rdp, rd->regdomain);
+                       if (rp == NULL)
+                               errx(1, "country %s (%s) is not usable with "
+                                   "regdomain %d", cc->isoname, cc->name,
+                                   rd->regdomain);
+                       else if (rp->cc != NULL && rp->cc != cc)
+                               errx(1, "country %s (%s) is not usable with "
+                                  "regdomain %s", cc->isoname, cc->name,
+                                  rp->name);
+               }
+       }
+       /*
+        * Fetch the device capabilities and calculate the
+        * full set of netbands for which we request a new
+        * channel list be constructed.  Once that's done we
+        * push the regdomain info + channel list to the kernel.
+        */
+       dc = malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN));
+       if (dc == NULL)
+               errx(1, "no space for device capabilities");
+       dc->dc_chaninfo.ic_nchans = MAXCHAN;
+       getdevcaps(s, dc);
+#if 0
+       if (verbose) {
+               printf("drivercaps: 0x%x\n", dc->dc_drivercaps);
+               printf("cryptocaps: 0x%x\n", dc->dc_cryptocaps);
+               printf("htcaps    : 0x%x\n", dc->dc_htcaps);
+               memcpy(chaninfo, &dc->dc_chaninfo,
+                   IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo));
+               print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, 1/*verbose*/);
+       }
+#endif
+       req = malloc(IEEE80211_REGDOMAIN_SIZE(dc->dc_chaninfo.ic_nchans));
+       if (req == NULL)
+               errx(1, "no space for regdomain request");
+       req->rd = *rd;
+       regdomain_makechannels(req, dc);
+       if (verbose) {
+               LINE_INIT(':');
+               print_regdomain(rd, 1/*verbose*/);
+               LINE_BREAK();
+               /* blech, reallocate channel list for new data */
+               if (chaninfo != NULL)
+                       free(chaninfo);
+               chaninfo = malloc(IEEE80211_CHANINFO_SPACE(&req->chaninfo));
+               if (chaninfo == NULL)
+                       errx(1, "no space for channel list");
+               memcpy(chaninfo, &req->chaninfo,
+                   IEEE80211_CHANINFO_SPACE(&req->chaninfo));
+               print_channels(s, &req->chaninfo, 1/*allchans*/, 1/*verbose*/);
+       }
+       if (req->chaninfo.ic_nchans == 0)
+               errx(1, "no channels calculated");
+       set80211(s, IEEE80211_IOC_REGDOMAIN, 0,
+           IEEE80211_REGDOMAIN_SPACE(req), req);
+       free(req);
+       free(dc);
+}
+
+static int
+ieee80211_mhz2ieee(int freq, int flags)
+{
+       struct ieee80211_channel chan;
+       mapfreq(&chan, freq, flags);
+       return chan.ic_ieee;
+}
 
 static int
 isanyarg(const char *arg)
 {
-       return (strcmp(arg, "-") == 0 ||
-           strcasecmp(arg, "any") == 0 || strcasecmp(arg, "off") == 0);
+       return (strncmp(arg, "-", 1) == 0 ||
+           strncasecmp(arg, "any", 3) == 0 || strncasecmp(arg, "off", 3) == 0);
 }
 
 static void
@@ -117,7 +557,7 @@ set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
 
        ssid = 0;
        len = strlen(val);
-       if (len > 2 && isdigit(val[0]) && val[1] == ':') {
+       if (len > 2 && isdigit((int)val[0]) && val[1] == ':') {
                ssid = atoi(val)-1;
                val += 2;
        }
@@ -130,6 +570,20 @@ set80211ssid(const char *val, int d, int s, const struct afswtch *rafp)
        set80211(s, IEEE80211_IOC_SSID, ssid, len, data);
 }
 
+static void
+set80211meshid(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       int             len;
+       u_int8_t        data[IEEE80211_NWID_LEN];
+
+       memset(data, 0, sizeof(data));
+       len = sizeof(data);
+       if (get_string(val, NULL, data, &len) == NULL)
+               exit(1);
+
+       set80211(s, IEEE80211_IOC_MESH_ID, 0, len, data);
+}      
+
 static void
 set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
 {
@@ -144,45 +598,171 @@ set80211stationname(const char *val, int d, int s, const struct afswtch *rafp)
 }
 
 /*
- * Convert IEEE channel number to MHz frequency.
- */
-static u_int
-ieee80211_ieee2mhz(u_int chan)
+ * Parse a channel specification for attributes/flags.
+ * The syntax is:
+ *     freq/xx         channel width (5,10,20,40,40+,40-)
+ *     freq:mode       channel mode (a,b,g,h,n,t,s,d)
+ *
+ * These can be combined in either order; e.g. 2437:ng/40.
+ * Modes are case insensitive.
+ *
+ * The result is not validated here; it's assumed to be
+ * checked against the channel table fetched from the kernel.
+ */ 
+static int
+getchannelflags(const char *val, int freq)
 {
-       if (chan == 14)
-               return 2484;
-       if (chan < 14)                  /* 0-13 */
-               return 2407 + chan*5;
-       if (chan < 27)                  /* 15-26 */
-               return 2512 + ((chan-15)*20);
-       return 5000 + (chan*5);
+#define        _CHAN_HT        0x80000000
+       const char *cp;
+       int flags;
+
+       flags = 0;
+
+       cp = strchr(val, ':');
+       if (cp != NULL) {
+               for (cp++; isalpha((int) *cp); cp++) {
+                       /* accept mixed case */
+                       int c = *cp;
+                       if (isupper(c))
+                               c = tolower(c);
+                       switch (c) {
+                       case 'a':               /* 802.11a */
+                               flags |= IEEE80211_CHAN_A;
+                               break;
+                       case 'b':               /* 802.11b */
+                               flags |= IEEE80211_CHAN_B;
+                               break;
+                       case 'g':               /* 802.11g */
+                               flags |= IEEE80211_CHAN_G;
+                               break;
+                       case 'h':               /* ht = 802.11n */
+                       case 'n':               /* 802.11n */
+                               flags |= _CHAN_HT;      /* NB: private */
+                               break;
+                       case 'd':               /* dt = Atheros Dynamic Turbo */
+                               flags |= IEEE80211_CHAN_TURBO;
+                               break;
+                       case 't':               /* ht, dt, st, t */
+                               /* dt and unadorned t specify Dynamic Turbo */
+                               if ((flags & (IEEE80211_CHAN_STURBO|_CHAN_HT)) == 0)
+                                       flags |= IEEE80211_CHAN_TURBO;
+                               break;
+                       case 's':               /* st = Atheros Static Turbo */
+                               flags |= IEEE80211_CHAN_STURBO;
+                               break;
+                       default:
+                               errx(-1, "%s: Invalid channel attribute %c\n",
+                                   val, *cp);
+                       }
+               }
+       }
+       cp = strchr(val, '/');
+       if (cp != NULL) {
+               char *ep;
+               u_long cw = strtoul(cp+1, &ep, 10);
+
+               switch (cw) {
+               case 5:
+                       flags |= IEEE80211_CHAN_QUARTER;
+                       break;
+               case 10:
+                       flags |= IEEE80211_CHAN_HALF;
+                       break;
+               case 20:
+                       /* NB: this may be removed below */
+                       flags |= IEEE80211_CHAN_HT20;
+                       break;
+               case 40:
+                       if (ep != NULL && *ep == '+')
+                               flags |= IEEE80211_CHAN_HT40U;
+                       else if (ep != NULL && *ep == '-')
+                               flags |= IEEE80211_CHAN_HT40D;
+                       break;
+               default:
+                       errx(-1, "%s: Invalid channel width\n", val);
+               }
+       }
+       /*
+        * Cleanup specifications.
+        */ 
+       if ((flags & _CHAN_HT) == 0) {
+               /*
+                * If user specified freq/20 or freq/40 quietly remove
+                * HT cw attributes depending on channel use.  To give
+                * an explicit 20/40 width for an HT channel you must
+                * indicate it is an HT channel since all HT channels
+                * are also usable for legacy operation; e.g. freq:n/40.
+                */
+               flags &= ~IEEE80211_CHAN_HT;
+       } else {
+               /*
+                * Remove private indicator that this is an HT channel
+                * and if no explicit channel width has been given
+                * provide the default settings.
+                */
+               flags &= ~_CHAN_HT;
+               if ((flags & IEEE80211_CHAN_HT) == 0) {
+                       struct ieee80211_channel chan;
+                       /*
+                        * Consult the channel list to see if we can use
+                        * HT40+ or HT40- (if both the map routines choose).
+                        */
+                       if (freq > 255)
+                               mapfreq(&chan, freq, 0);
+                       else
+                               mapchan(&chan, freq, 0);
+                       flags |= (chan.ic_flags & IEEE80211_CHAN_HT);
+               }
+       }
+       return flags;
+#undef _CHAN_HT
 }
 
-/*
- * Convert MHz frequency to IEEE channel number.
- */
-static u_int
-ieee80211_mhz2ieee(u_int freq)
+static void
+getchannel(int s, struct ieee80211_channel *chan, const char *val)
 {
-       if (freq == 2484)
-               return 14;
-       if (freq < 2484)
-               return (freq - 2407) / 5;
-       if (freq < 5000)
-               return 15 + ((freq - 2512) / 20);
-       return (freq - 5000) / 5;
+       int v, flags;
+       char *eptr;
+
+       memset(chan, 0, sizeof(*chan));
+       if (isanyarg(val)) {
+               chan->ic_freq = IEEE80211_CHAN_ANY;
+               return;
+       }
+       getchaninfo(s);
+       errno = 0;
+       v = strtol(val, &eptr, 10);
+       if (val[0] == '\0' || val == eptr || errno == ERANGE ||
+           /* channel may be suffixed with nothing, :flag, or /width */
+           (eptr[0] != '\0' && eptr[0] != ':' && eptr[0] != '/'))
+               errx(1, "invalid channel specification%s",
+                   errno == ERANGE ? " (out of range)" : "");
+       flags = getchannelflags(val, v);
+       if (v > 255) {          /* treat as frequency */
+               mapfreq(chan, v, flags);
+       } else {
+               mapchan(chan, v, flags);
+       }
 }
 
 static void
 set80211channel(const char *val, int d, int s, const struct afswtch *rafp)
 {
-       if (!isanyarg(val)) {
-               int v = atoi(val);
-               if (v > 255)            /* treat as frequency */
-                       v = ieee80211_mhz2ieee(v);
-               set80211(s, IEEE80211_IOC_CHANNEL, v, 0, NULL);
-       } else
-               set80211(s, IEEE80211_IOC_CHANNEL, IEEE80211_CHAN_ANY, 0, NULL);
+       struct ieee80211_channel chan;
+
+       getchannel(s, &chan, val);
+       set80211(s, IEEE80211_IOC_CURCHAN, 0, sizeof(chan), &chan);
+}
+
+static void
+set80211chanswitch(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       struct ieee80211_chanswitch_req csr;
+
+       getchannel(s, &csr.csa_chan, val);
+       csr.csa_mode = 1;
+       csr.csa_count = 5;
+       set80211(s, IEEE80211_IOC_CHANSWITCH, 0, sizeof(csr), &csr);
 }
 
 static void
@@ -292,7 +872,7 @@ set80211wepkey(const char *val, int d, int s, const struct afswtch *rafp)
        int             len;
        u_int8_t        data[IEEE80211_KEYBUF_SIZE];
 
-       if (isdigit(val[0]) && val[1] == ':') {
+       if (isdigit((int)val[0]) && val[1] == ':') {
                key = atoi(val)-1;
                val += 2;
        }
@@ -318,7 +898,7 @@ set80211nwkey(const char *val, int d, int s, const struct afswtch *rafp)
 
        set80211(s, IEEE80211_IOC_WEP, IEEE80211_WEP_ON, 0, NULL);
 
-       if (isdigit(val[0]) && val[1] == ':') {
+       if (isdigit((int)val[0]) && val[1] == ':') {
                txkey = val[0]-'0'-1;
                val += 2;
 
@@ -363,7 +943,7 @@ set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
                mode = IEEE80211_PROTMODE_OFF;
        } else if (strcasecmp(val, "cts") == 0) {
                mode = IEEE80211_PROTMODE_CTS;
-       } else if (strcasecmp(val, "rtscts") == 0) {
+       } else if (strncasecmp(val, "rtscts", 3) == 0) {
                mode = IEEE80211_PROTMODE_RTSCTS;
        } else {
                errx(1, "unknown protection mode");
@@ -372,10 +952,32 @@ set80211protmode(const char *val, int d, int s, const struct afswtch *rafp)
        set80211(s, IEEE80211_IOC_PROTMODE, mode, 0, NULL);
 }
 
+static void
+set80211htprotmode(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       int     mode;
+
+       if (strcasecmp(val, "off") == 0) {
+               mode = IEEE80211_PROTMODE_OFF;
+       } else if (strncasecmp(val, "rts", 3) == 0) {
+               mode = IEEE80211_PROTMODE_RTSCTS;
+       } else {
+               errx(1, "unknown protection mode");
+       }
+
+       set80211(s, IEEE80211_IOC_HTPROTMODE, mode, 0, NULL);
+}
+
 static void
 set80211txpower(const char *val, int d, int s, const struct afswtch *rafp)
 {
-       set80211(s, IEEE80211_IOC_TXPOWER, atoi(val), 0, NULL);
+       double v = atof(val);
+       int txpow;
+
+       txpow = (int) (2*v);
+       if (txpow != 2*v)
+               errx(-1, "invalid tx power (must be .5 dBm units)");
+       set80211(s, IEEE80211_IOC_TXPOWER, txpow, 0, NULL);
 }
 
 #define        IEEE80211_ROAMING_DEVICE        0
@@ -417,11 +1019,22 @@ set80211apbridge(const char *val, int d, int s, const struct afswtch *rafp)
        set80211(s, IEEE80211_IOC_APBRIDGE, d, 0, NULL);
 }
 
+static void
+set80211fastframes(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_FF, d, 0, NULL);
+}
+
+static void
+set80211dturbo(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_TURBOP, d, 0, NULL);
+}
+
 static void
 set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
 {
        struct ieee80211req_chanlist chanlist;
-#define        MAXCHAN (sizeof(chanlist.ic_channels)*NBBY)
        char *temp, *cp, *tp;
 
        temp = malloc(strlen(val) + 1);
@@ -431,25 +1044,25 @@ set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
        memset(&chanlist, 0, sizeof(chanlist));
        cp = temp;
        for (;;) {
-               int first, last, f;
+               int first, last, f, c;
 
                tp = strchr(cp, ',');
                if (tp != NULL)
                        *tp++ = '\0';
                switch (sscanf(cp, "%u-%u", &first, &last)) {
                case 1:
-                       if (first > MAXCHAN)
-                               errx(-1, "channel %u out of range, max %zu",
-                                       first, MAXCHAN);
+                       if (first > IEEE80211_CHAN_MAX)
+                               errx(-1, "channel %u out of range, max %u",
+                                       first, IEEE80211_CHAN_MAX);
                        setbit(chanlist.ic_channels, first);
                        break;
                case 2:
-                       if (first > MAXCHAN)
-                               errx(-1, "channel %u out of range, max %zu",
-                                       first, MAXCHAN);
-                       if (last > MAXCHAN)
-                               errx(-1, "channel %u out of range, max %zu",
-                                       last, MAXCHAN);
+                       if (first > IEEE80211_CHAN_MAX)
+                               errx(-1, "channel %u out of range, max %u",
+                                       first, IEEE80211_CHAN_MAX);
+                       if (last > IEEE80211_CHAN_MAX)
+                               errx(-1, "channel %u out of range, max %u",
+                                       last, IEEE80211_CHAN_MAX);
                        if (first > last)
                                errx(-1, "void channel range, %u > %u",
                                        first, last);
@@ -459,15 +1072,14 @@ set80211chanlist(const char *val, int d, int s, const struct afswtch *rafp)
                }
                if (tp == NULL)
                        break;
-               while (isspace(*tp))
+               c = *tp;
+               while (isspace(c))
                        tp++;
-               if (!isdigit(*tp))
+               if (!isdigit(c))
                        break;
                cp = tp;
        }
-       set80211(s, IEEE80211_IOC_CHANLIST, 0,
-               sizeof(chanlist), (uint8_t *) &chanlist);
-#undef MAXCHAN
+       set80211(s, IEEE80211_IOC_CHANLIST, 0, sizeof(chanlist), &chanlist);
 }
 
 static void
@@ -650,7 +1262,7 @@ DECL_CMD_FUNC(set80211kickmac, val, d)
        mlme.im_op = IEEE80211_MLME_DEAUTH;
        mlme.im_reason = IEEE80211_REASON_AUTH_EXPIRE;
        memcpy(mlme.im_macaddr, LLADDR(&sdl), IEEE80211_ADDR_LEN);
-       set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), (u_int8_t *) &mlme);
+       set80211(s, IEEE80211_IOC_MLME, 0, sizeof(mlme), &mlme);
 }
 
 static
@@ -660,72 +1272,1087 @@ DECL_CMD_FUNC(set80211maccmd, val, d)
 }
 
 static void
-set80211pureg(const char *val, int d, int s, const struct afswtch *rafp)
+set80211meshrtmac(int s, int req, const char *val)
 {
-       set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL);
+       char *temp;
+       struct sockaddr_dl sdl;
+
+       temp = malloc(strlen(val) + 2); /* ':' and '\0' */
+       if (temp == NULL)
+               errx(1, "malloc failed");
+       temp[0] = ':';
+       strcpy(temp + 1, val);
+       sdl.sdl_len = sizeof(sdl);
+       link_addr(temp, &sdl);
+       free(temp);
+       if (sdl.sdl_alen != IEEE80211_ADDR_LEN)
+               errx(1, "malformed link-level address");
+       set80211(s, IEEE80211_IOC_MESH_RTCMD, req,
+           IEEE80211_ADDR_LEN, LLADDR(&sdl));
 }
 
-static void
-set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
+static
+DECL_CMD_FUNC(set80211addmeshrt, val, d)
 {
-       set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
+       set80211meshrtmac(s, IEEE80211_MESH_RTCMD_ADD, val);
 }
 
-static void
-set80211ratectl(const char *val, int d, int s, const struct afswtch *rafp)
+static
+DECL_CMD_FUNC(set80211delmeshrt, val, d)
 {
-       int ratectl = 0;
-
-       if (strcmp("onoe", val) == 0)
-               ratectl = IEEE80211_RATECTL_ONOE;
-       else if (strcmp("amrr", val) == 0)
-               ratectl = IEEE80211_RATECTL_AMRR;
-       else if (strcmp("sample", val) == 0)
-               ratectl = IEEE80211_RATECTL_SAMPLE;
-       else
-               errx(1, "unknown ratectl");
-
-       set80211(s, IEEE80211_IOC_RATECTL, ratectl, 0, NULL);
+       set80211meshrtmac(s, IEEE80211_MESH_RTCMD_DELETE, val);
 }
 
 static
-DECL_CMD_FUNC(set80211mcastrate, val, d)
+DECL_CMD_FUNC(set80211meshrtcmd, val, d)
 {
-       set80211(s, IEEE80211_IOC_MCAST_RATE, (int) 2*atof(val), 0, NULL);
+       set80211(s, IEEE80211_IOC_MESH_RTCMD, d, 0, NULL);
 }
 
 static
-DECL_CMD_FUNC(set80211fragthreshold, val, d)
+DECL_CMD_FUNC(set80211hwmprootmode, val, d)
 {
-       set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
-               isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
+       int mode;
+
+       if (strcasecmp(val, "normal") == 0)
+               mode = IEEE80211_HWMP_ROOTMODE_NORMAL;
+       else if (strcasecmp(val, "proactive") == 0)
+               mode = IEEE80211_HWMP_ROOTMODE_PROACTIVE;
+       else if (strcasecmp(val, "rann") == 0)
+               mode = IEEE80211_HWMP_ROOTMODE_RANN;
+       else
+               mode = IEEE80211_HWMP_ROOTMODE_DISABLED;
+       set80211(s, IEEE80211_IOC_HWMP_ROOTMODE, mode, 0, NULL);
 }
 
 static
-DECL_CMD_FUNC(set80211bmissthreshold, val, d)
+DECL_CMD_FUNC(set80211hwmpmaxhops, val, d)
 {
-       set80211(s, IEEE80211_IOC_BMISSTHRESHOLD,
-               isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL);
+       set80211(s, IEEE80211_IOC_HWMP_MAXHOPS, atoi(val), 0, NULL);
 }
 
-static int
-getmaxrate(uint8_t rates[15], uint8_t nrates)
+static void
+set80211pureg(const char *val, int d, int s, const struct afswtch *rafp)
 {
-       int i, maxrate = -1;
+       set80211(s, IEEE80211_IOC_PUREG, d, 0, NULL);
+}
 
-       for (i = 0; i < nrates; i++) {
-               int rate = rates[i] & IEEE80211_RATE_VAL;
-               if (rate > maxrate)
-                       maxrate = rate;
-       }
-       return maxrate / 2;
+static void
+set80211bgscan(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_BGSCAN, d, 0, NULL);
 }
 
-static const char *
-getcaps(int capinfo)
+static
+DECL_CMD_FUNC(set80211bgscanidle, val, d)
 {
-       static char capstring[32];
-       char *cp = capstring;
+       set80211(s, IEEE80211_IOC_BGSCAN_IDLE, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211bgscanintvl, val, d)
+{
+       set80211(s, IEEE80211_IOC_BGSCAN_INTERVAL, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211scanvalid, val, d)
+{
+       set80211(s, IEEE80211_IOC_SCANVALID, atoi(val), 0, NULL);
+}
+
+/*
+ * Parse an optional trailing specification of which netbands
+ * to apply a parameter to.  This is basically the same syntax
+ * as used for channels but you can concatenate to specify
+ * multiple.  For example:
+ *     14:abg          apply to 11a, 11b, and 11g
+ *     6:ht            apply to 11na and 11ng
+ * We don't make a big effort to catch silly things; this is
+ * really a convenience mechanism.
+ */
+static int
+getmodeflags(const char *val)
+{
+       const char *cp;
+       int flags;
+
+       flags = 0;
+
+       cp = strchr(val, ':');
+       if (cp != NULL) {
+               for (cp++; isalpha((int) *cp); cp++) {
+                       /* accept mixed case */
+                       int c = *cp;
+                       if (isupper(c))
+                               c = tolower(c);
+                       switch (c) {
+                       case 'a':               /* 802.11a */
+                               flags |= IEEE80211_CHAN_A;
+                               break;
+                       case 'b':               /* 802.11b */
+                               flags |= IEEE80211_CHAN_B;
+                               break;
+                       case 'g':               /* 802.11g */
+                               flags |= IEEE80211_CHAN_G;
+                               break;
+                       case 'n':               /* 802.11n */
+                               flags |= IEEE80211_CHAN_HT;
+                               break;
+                       case 'd':               /* dt = Atheros Dynamic Turbo */
+                               flags |= IEEE80211_CHAN_TURBO;
+                               break;
+                       case 't':               /* ht, dt, st, t */
+                               /* dt and unadorned t specify Dynamic Turbo */
+                               if ((flags & (IEEE80211_CHAN_STURBO|IEEE80211_CHAN_HT)) == 0)
+                                       flags |= IEEE80211_CHAN_TURBO;
+                               break;
+                       case 's':               /* st = Atheros Static Turbo */
+                               flags |= IEEE80211_CHAN_STURBO;
+                               break;
+                       case 'h':               /* 1/2-width channels */
+                               flags |= IEEE80211_CHAN_HALF;
+                               break;
+                       case 'q':               /* 1/4-width channels */
+                               flags |= IEEE80211_CHAN_QUARTER;
+                               break;
+                       default:
+                               errx(-1, "%s: Invalid mode attribute %c\n",
+                                   val, *cp);
+                       }
+               }
+       }
+       return flags;
+}
+
+#define        IEEE80211_CHAN_HTA      (IEEE80211_CHAN_HT|IEEE80211_CHAN_5GHZ)
+#define        IEEE80211_CHAN_HTG      (IEEE80211_CHAN_HT|IEEE80211_CHAN_2GHZ)
+
+#define        _APPLY(_flags, _base, _param, _v) do {                          \
+    if (_flags & IEEE80211_CHAN_HT) {                                  \
+           if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\
+                   _base.params[IEEE80211_MODE_11NA]._param = _v;      \
+                   _base.params[IEEE80211_MODE_11NG]._param = _v;      \
+           } else if (_flags & IEEE80211_CHAN_5GHZ)                    \
+                   _base.params[IEEE80211_MODE_11NA]._param = _v;      \
+           else                                                        \
+                   _base.params[IEEE80211_MODE_11NG]._param = _v;      \
+    }                                                                  \
+    if (_flags & IEEE80211_CHAN_TURBO) {                               \
+           if ((_flags & (IEEE80211_CHAN_5GHZ|IEEE80211_CHAN_2GHZ)) == 0) {\
+                   _base.params[IEEE80211_MODE_TURBO_A]._param = _v;   \
+                   _base.params[IEEE80211_MODE_TURBO_G]._param = _v;   \
+           } else if (_flags & IEEE80211_CHAN_5GHZ)                    \
+                   _base.params[IEEE80211_MODE_TURBO_A]._param = _v;   \
+           else                                                        \
+                   _base.params[IEEE80211_MODE_TURBO_G]._param = _v;   \
+    }                                                                  \
+    if (_flags & IEEE80211_CHAN_STURBO)                                        \
+           _base.params[IEEE80211_MODE_STURBO_A]._param = _v;          \
+    if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)               \
+           _base.params[IEEE80211_MODE_11A]._param = _v;               \
+    if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)               \
+           _base.params[IEEE80211_MODE_11G]._param = _v;               \
+    if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)               \
+           _base.params[IEEE80211_MODE_11B]._param = _v;               \
+    if (_flags & IEEE80211_CHAN_HALF)                                  \
+           _base.params[IEEE80211_MODE_HALF]._param = _v;              \
+    if (_flags & IEEE80211_CHAN_QUARTER)                               \
+           _base.params[IEEE80211_MODE_QUARTER]._param = _v;           \
+} while (0)
+#define        _APPLY1(_flags, _base, _param, _v) do {                         \
+    if (_flags & IEEE80211_CHAN_HT) {                                  \
+           if (_flags & IEEE80211_CHAN_5GHZ)                           \
+                   _base.params[IEEE80211_MODE_11NA]._param = _v;      \
+           else                                                        \
+                   _base.params[IEEE80211_MODE_11NG]._param = _v;      \
+    } else if ((_flags & IEEE80211_CHAN_108A) == IEEE80211_CHAN_108A)  \
+           _base.params[IEEE80211_MODE_TURBO_A]._param = _v;           \
+    else if ((_flags & IEEE80211_CHAN_108G) == IEEE80211_CHAN_108G)    \
+           _base.params[IEEE80211_MODE_TURBO_G]._param = _v;           \
+    else if ((_flags & IEEE80211_CHAN_ST) == IEEE80211_CHAN_ST)                \
+           _base.params[IEEE80211_MODE_STURBO_A]._param = _v;          \
+    else if (_flags & IEEE80211_CHAN_HALF)                             \
+           _base.params[IEEE80211_MODE_HALF]._param = _v;              \
+    else if (_flags & IEEE80211_CHAN_QUARTER)                          \
+           _base.params[IEEE80211_MODE_QUARTER]._param = _v;           \
+    else if ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)          \
+           _base.params[IEEE80211_MODE_11A]._param = _v;               \
+    else if ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)          \
+           _base.params[IEEE80211_MODE_11G]._param = _v;               \
+    else if ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)          \
+           _base.params[IEEE80211_MODE_11B]._param = _v;               \
+} while (0)
+#define        _APPLY_RATE(_flags, _base, _param, _v) do {                     \
+    if (_flags & IEEE80211_CHAN_HT) {                                  \
+       (_v) = (_v / 2) | IEEE80211_RATE_MCS;                           \
+    }                                                                  \
+    _APPLY(_flags, _base, _param, _v);                                 \
+} while (0)
+#define        _APPLY_RATE1(_flags, _base, _param, _v) do {                    \
+    if (_flags & IEEE80211_CHAN_HT) {                                  \
+       (_v) = (_v / 2) | IEEE80211_RATE_MCS;                           \
+    }                                                                  \
+    _APPLY1(_flags, _base, _param, _v);                                        \
+} while (0)
+
+static
+DECL_CMD_FUNC(set80211roamrssi, val, d)
+{
+       double v = atof(val);
+       int rssi, flags;
+
+       rssi = (int) (2*v);
+       if (rssi != 2*v)
+               errx(-1, "invalid rssi (must be .5 dBm units)");
+       flags = getmodeflags(val);
+       getroam(s);
+       if (flags == 0) {               /* NB: no flags => current channel */
+               flags = getcurchan(s)->ic_flags;
+               _APPLY1(flags, roamparams, rssi, rssi);
+       } else
+               _APPLY(flags, roamparams, rssi, rssi);
+       callback_register(setroam_cb, &roamparams);
+}
+
+static int
+getrate(const char *val, const char *tag)
+{
+       double v = atof(val);
+       int rate;
+
+       rate = (int) (2*v);
+       if (rate != 2*v)
+               errx(-1, "invalid %s rate (must be .5 Mb/s units)", tag);
+       return rate;            /* NB: returns 2x the specified value */
+}
+
+static
+DECL_CMD_FUNC(set80211roamrate, val, d)
+{
+       int rate, flags;
+
+       rate = getrate(val, "roam");
+       flags = getmodeflags(val);
+       getroam(s);
+       if (flags == 0) {               /* NB: no flags => current channel */
+               flags = getcurchan(s)->ic_flags;
+               _APPLY_RATE1(flags, roamparams, rate, rate);
+       } else
+               _APPLY_RATE(flags, roamparams, rate, rate);
+       callback_register(setroam_cb, &roamparams);
+}
+
+static
+DECL_CMD_FUNC(set80211mcastrate, val, d)
+{
+       int rate, flags;
+
+       rate = getrate(val, "mcast");
+       flags = getmodeflags(val);
+       gettxparams(s);
+       if (flags == 0) {               /* NB: no flags => current channel */
+               flags = getcurchan(s)->ic_flags;
+               _APPLY_RATE1(flags, txparams, mcastrate, rate);
+       } else
+               _APPLY_RATE(flags, txparams, mcastrate, rate);
+       callback_register(settxparams_cb, &txparams);
+}
+
+static
+DECL_CMD_FUNC(set80211mgtrate, val, d)
+{
+       int rate, flags;
+
+       rate = getrate(val, "mgmt");
+       flags = getmodeflags(val);
+       gettxparams(s);
+       if (flags == 0) {               /* NB: no flags => current channel */
+               flags = getcurchan(s)->ic_flags;
+               _APPLY_RATE1(flags, txparams, mgmtrate, rate);
+       } else
+               _APPLY_RATE(flags, txparams, mgmtrate, rate);
+       callback_register(settxparams_cb, &txparams);
+}
+
+static
+DECL_CMD_FUNC(set80211ucastrate, val, d)
+{
+       int flags;
+
+       gettxparams(s);
+       flags = getmodeflags(val);
+       if (isanyarg(val)) {
+               if (flags == 0) {       /* NB: no flags => current channel */
+                       flags = getcurchan(s)->ic_flags;
+                       _APPLY1(flags, txparams, ucastrate,
+                           IEEE80211_FIXED_RATE_NONE);
+               } else
+                       _APPLY(flags, txparams, ucastrate,
+                           IEEE80211_FIXED_RATE_NONE);
+       } else {
+               int rate = getrate(val, "ucast");
+               if (flags == 0) {       /* NB: no flags => current channel */
+                       flags = getcurchan(s)->ic_flags;
+                       _APPLY_RATE1(flags, txparams, ucastrate, rate);
+               } else
+                       _APPLY_RATE(flags, txparams, ucastrate, rate);
+       }
+       callback_register(settxparams_cb, &txparams);
+}
+
+static
+DECL_CMD_FUNC(set80211maxretry, val, d)
+{
+       int v = atoi(val), flags;
+
+       flags = getmodeflags(val);
+       gettxparams(s);
+       if (flags == 0) {               /* NB: no flags => current channel */
+               flags = getcurchan(s)->ic_flags;
+               _APPLY1(flags, txparams, maxretry, v);
+       } else
+               _APPLY(flags, txparams, maxretry, v);
+       callback_register(settxparams_cb, &txparams);
+}
+#undef _APPLY_RATE
+#undef _APPLY
+#undef IEEE80211_CHAN_HTA
+#undef IEEE80211_CHAN_HTG
+
+static
+DECL_CMD_FUNC(set80211fragthreshold, val, d)
+{
+       set80211(s, IEEE80211_IOC_FRAGTHRESHOLD,
+               isundefarg(val) ? IEEE80211_FRAG_MAX : atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211bmissthreshold, val, d)
+{
+       set80211(s, IEEE80211_IOC_BMISSTHRESHOLD,
+               isundefarg(val) ? IEEE80211_HWBMISS_MAX : atoi(val), 0, NULL);
+}
+
+static void
+set80211burst(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_BURST, d, 0, NULL);
+}
+
+static void
+set80211doth(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_DOTH, d, 0, NULL);
+}
+
+static void
+set80211dfs(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_DFS, d, 0, NULL);
+}
+
+static void
+set80211shortgi(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_SHORTGI,
+               d ? (IEEE80211_HTCAP_SHORTGI20 | IEEE80211_HTCAP_SHORTGI40) : 0,
+               0, NULL);
+}
+
+static void
+set80211ampdu(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       int ampdu;
+
+       if (get80211val(s, IEEE80211_IOC_AMPDU, &ampdu) < 0)
+               errx(-1, "cannot get AMPDU setting");
+       if (d < 0) {
+               d = -d;
+               ampdu &= ~d;
+       } else
+               ampdu |= d;
+       set80211(s, IEEE80211_IOC_AMPDU, ampdu, 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211ampdulimit, val, d)
+{
+       int v;
+
+       switch (atoi(val)) {
+       case 8:
+       case 8*1024:
+               v = IEEE80211_HTCAP_MAXRXAMPDU_8K;
+               break;
+       case 16:
+       case 16*1024:
+               v = IEEE80211_HTCAP_MAXRXAMPDU_16K;
+               break;
+       case 32:
+       case 32*1024:
+               v = IEEE80211_HTCAP_MAXRXAMPDU_32K;
+               break;
+       case 64:
+       case 64*1024:
+               v = IEEE80211_HTCAP_MAXRXAMPDU_64K;
+               break;
+       default:
+               errx(-1, "invalid A-MPDU limit %s", val);
+       }
+       set80211(s, IEEE80211_IOC_AMPDU_LIMIT, v, 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211ampdudensity, val, d)
+{
+       int v;
+
+       if (isanyarg(val) || strcasecmp(val, "na") == 0)
+               v = IEEE80211_HTCAP_MPDUDENSITY_NA;
+       else switch ((int)(atof(val)*4)) {
+       case 0:
+               v = IEEE80211_HTCAP_MPDUDENSITY_NA;
+               break;
+       case 1:
+               v = IEEE80211_HTCAP_MPDUDENSITY_025;
+               break;
+       case 2:
+               v = IEEE80211_HTCAP_MPDUDENSITY_05;
+               break;
+       case 4:
+               v = IEEE80211_HTCAP_MPDUDENSITY_1;
+               break;
+       case 8:
+               v = IEEE80211_HTCAP_MPDUDENSITY_2;
+               break;
+       case 16:
+               v = IEEE80211_HTCAP_MPDUDENSITY_4;
+               break;
+       case 32:
+               v = IEEE80211_HTCAP_MPDUDENSITY_8;
+               break;
+       case 64:
+               v = IEEE80211_HTCAP_MPDUDENSITY_16;
+               break;
+       default:
+               errx(-1, "invalid A-MPDU density %s", val);
+       }
+       set80211(s, IEEE80211_IOC_AMPDU_DENSITY, v, 0, NULL);
+}
+
+static void
+set80211amsdu(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       int amsdu;
+
+       if (get80211val(s, IEEE80211_IOC_AMSDU, &amsdu) < 0)
+               err(-1, "cannot get AMSDU setting");
+       if (d < 0) {
+               d = -d;
+               amsdu &= ~d;
+       } else
+               amsdu |= d;
+       set80211(s, IEEE80211_IOC_AMSDU, amsdu, 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211amsdulimit, val, d)
+{
+       set80211(s, IEEE80211_IOC_AMSDU_LIMIT, atoi(val), 0, NULL);
+}
+
+static void
+set80211puren(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_PUREN, d, 0, NULL);
+}
+
+static void
+set80211htcompat(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_HTCOMPAT, d, 0, NULL);
+}
+
+static void
+set80211htconf(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_HTCONF, d, 0, NULL);
+       htconf = d;
+}
+
+static void
+set80211dwds(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_DWDS, d, 0, NULL);
+}
+
+static void
+set80211inact(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_INACTIVITY, d, 0, NULL);
+}
+
+static void
+set80211tsn(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_TSN, d, 0, NULL);
+}
+
+static void
+set80211dotd(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_DOTD, d, 0, NULL);
+}
+
+static void
+set80211smps(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_SMPS, d, 0, NULL);
+}
+
+static void
+set80211rifs(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       set80211(s, IEEE80211_IOC_RIFS, d, 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211tdmaslot, val, d)
+{
+       set80211(s, IEEE80211_IOC_TDMA_SLOT, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211tdmaslotcnt, val, d)
+{
+       set80211(s, IEEE80211_IOC_TDMA_SLOTCNT, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211tdmaslotlen, val, d)
+{
+       set80211(s, IEEE80211_IOC_TDMA_SLOTLEN, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211tdmabintval, val, d)
+{
+       set80211(s, IEEE80211_IOC_TDMA_BINTERVAL, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211meshttl, val, d)
+{
+       set80211(s, IEEE80211_IOC_MESH_TTL, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211meshforward, val, d)
+{
+       set80211(s, IEEE80211_IOC_MESH_FWRD, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211meshpeering, val, d)
+{
+       set80211(s, IEEE80211_IOC_MESH_AP, atoi(val), 0, NULL);
+}
+
+static
+DECL_CMD_FUNC(set80211meshmetric, val, d)
+{
+       char v[12];
+       
+       memcpy(v, val, sizeof(v));
+       set80211(s, IEEE80211_IOC_MESH_PR_METRIC, 0, 0, v);
+}
+
+static
+DECL_CMD_FUNC(set80211meshpath, val, d)
+{
+       char v[12];
+       
+       memcpy(v, val, sizeof(v));
+       set80211(s, IEEE80211_IOC_MESH_PR_PATH, 0, 0, v);
+}
+
+static int
+regdomain_sort(const void *a, const void *b)
+{
+#define        CHAN_ALL \
+       (IEEE80211_CHAN_ALLTURBO|IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)
+       const struct ieee80211_channel *ca = a;
+       const struct ieee80211_channel *cb = b;
+
+       return ca->ic_freq == cb->ic_freq ?
+           (ca->ic_flags & CHAN_ALL) - (cb->ic_flags & CHAN_ALL) :
+           ca->ic_freq - cb->ic_freq;
+#undef CHAN_ALL
+}
+
+static const struct ieee80211_channel *
+chanlookup(const struct ieee80211_channel chans[], int nchans,
+       int freq, int flags)
+{
+       int i;
+
+       flags &= IEEE80211_CHAN_ALLTURBO;
+       for (i = 0; i < nchans; i++) {
+               const struct ieee80211_channel *c = &chans[i];
+               if (c->ic_freq == freq &&
+                   (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
+                       return c;
+       }
+       return NULL;
+}
+
+static int
+chanfind(const struct ieee80211_channel chans[], int nchans, int flags)
+{
+       int i;
+
+       for (i = 0; i < nchans; i++) {
+               const struct ieee80211_channel *c = &chans[i];
+               if ((c->ic_flags & flags) == flags)
+                       return 1;
+       }
+       return 0;
+}
+
+/*
+ * Check channel compatibility.
+ */
+static int
+checkchan(const struct ieee80211req_chaninfo *avail, int freq, int flags)
+{
+       flags &= ~REQ_FLAGS;
+       /*
+        * Check if exact channel is in the calibration table;
+        * everything below is to deal with channels that we
+        * want to include but that are not explicitly listed.
+        */
+       if (flags & IEEE80211_CHAN_HT40) {
+               /* NB: we use an HT40 channel center that matches HT20 */
+               flags = (flags &~ IEEE80211_CHAN_HT40) | IEEE80211_CHAN_HT20;
+       }
+       if (chanlookup(avail->ic_chans, avail->ic_nchans, freq, flags) != NULL)
+               return 1;
+       if (flags & IEEE80211_CHAN_GSM) {
+               /*
+                * XXX GSM frequency mapping is handled in the kernel
+                * so we cannot find them in the calibration table;
+                * just accept the channel and the kernel will reject
+                * the channel list if it's wrong.
+                */
+               return 1;
+       }
+       /*
+        * If this is a 1/2 or 1/4 width channel allow it if a full
+        * width channel is present for this frequency, and the device
+        * supports fractional channels on this band.  This is a hack
+        * that avoids bloating the calibration table; it may be better
+        * by per-band attributes though (we are effectively calculating
+        * this attribute by scanning the channel list ourself).
+        */
+       if ((flags & (IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)) == 0)
+               return 0;
+       if (chanlookup(avail->ic_chans, avail->ic_nchans, freq,
+           flags &~ (IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER)) == NULL)
+               return 0;
+       if (flags & IEEE80211_CHAN_HALF) {
+               return chanfind(avail->ic_chans, avail->ic_nchans,
+                   IEEE80211_CHAN_HALF |
+                      (flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ)));
+       } else {
+               return chanfind(avail->ic_chans, avail->ic_nchans,
+                   IEEE80211_CHAN_QUARTER |
+                       (flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ)));
+       }
+}
+
+static void
+regdomain_addchans(struct ieee80211req_chaninfo *ci,
+       const netband_head *bands,
+       const struct ieee80211_regdomain *reg,
+       uint32_t chanFlags,
+       const struct ieee80211req_chaninfo *avail)
+{
+       const struct netband *nb;
+       const struct freqband *b;
+       struct ieee80211_channel *c, *prev;
+       int freq, hi_adj, lo_adj, channelSep;
+       uint32_t flags;
+
+       hi_adj = (chanFlags & IEEE80211_CHAN_HT40U) ? -20 : 0;
+       lo_adj = (chanFlags & IEEE80211_CHAN_HT40D) ? 20 : 0;
+       channelSep = (chanFlags & IEEE80211_CHAN_2GHZ) ? 0 : 40;
+       LIST_FOREACH(nb, bands, next) {
+               b = nb->band;
+               if (verbose) {
+                       printf("%s:", __func__);
+                       printb(" chanFlags", chanFlags, IEEE80211_CHAN_BITS);
+                       printb(" bandFlags", nb->flags | b->flags,
+                           IEEE80211_CHAN_BITS);
+                       putchar('\n');
+               }
+               prev = NULL;
+               for (freq = b->freqStart + lo_adj;
+                    freq <= b->freqEnd + hi_adj; freq += b->chanSep) {
+                       /*
+                        * Construct flags for the new channel.  We take
+                        * the attributes from the band descriptions except
+                        * for HT40 which is enabled generically (i.e. +/-
+                        * extension channel) in the band description and
+                        * then constrained according by channel separation.
+                        */
+                       flags = nb->flags | b->flags;
+                       if (flags & IEEE80211_CHAN_HT) {
+                               /*
+                                * HT channels are generated specially; we're
+                                * called to add HT20, HT40+, and HT40- chan's
+                                * so we need to expand only band specs for
+                                * the HT channel type being added.
+                                */
+                               if ((chanFlags & IEEE80211_CHAN_HT20) &&
+                                   (flags & IEEE80211_CHAN_HT20) == 0) {
+                                       if (verbose)
+                                               printf("%u: skip, not an "
+                                                   "HT20 channel\n", freq);
+                                       continue;
+                               }
+                               if ((chanFlags & IEEE80211_CHAN_HT40) &&
+                                   (flags & IEEE80211_CHAN_HT40) == 0) {
+                                       if (verbose)
+                                               printf("%u: skip, not an "
+                                                   "HT40 channel\n", freq);
+                                       continue;
+                               }
+                               /*
+                                * DFS and HT40 don't mix.  This should be
+                                * expressed in the regdomain database but
+                                * just in case enforce it here.
+                                */
+                               if ((chanFlags & IEEE80211_CHAN_HT40) &&
+                                   (flags & IEEE80211_CHAN_DFS)) {
+                                       if (verbose)
+                                               printf("%u: skip, HT40+DFS "
+                                                   "not permitted\n", freq);
+                                       continue;
+                               }
+                               /* NB: HT attribute comes from caller */
+                               flags &= ~IEEE80211_CHAN_HT;
+                               flags |= chanFlags & IEEE80211_CHAN_HT;
+                       }
+                       /*
+                        * Check if device can operate on this frequency.
+                        */
+                       if (!checkchan(avail, freq, flags)) {
+                               if (verbose) {
+                                       printf("%u: skip, ", freq);
+                                       printb("flags", flags,
+                                           IEEE80211_CHAN_BITS);
+                                       printf(" not available\n");
+                               }
+                               continue;
+                       }
+                       if ((flags & REQ_ECM) && !reg->ecm) {
+                               if (verbose)
+                                       printf("%u: skip, ECM channel\n", freq);
+                               continue;
+                       }
+                       if ((flags & REQ_INDOOR) && reg->location == 'O') {
+                               if (verbose)
+                                       printf("%u: skip, indoor channel\n",
+                                           freq);
+                               continue;
+                       }
+                       if ((flags & REQ_OUTDOOR) && reg->location == 'I') {
+                               if (verbose)
+                                       printf("%u: skip, outdoor channel\n",
+                                           freq);
+                               continue;
+                       }
+                       if ((flags & IEEE80211_CHAN_HT40) &&
+                           prev != NULL && (freq - prev->ic_freq) < channelSep) {
+                               if (verbose)
+                                       printf("%u: skip, only %u channel "
+                                           "separation, need %d\n", freq, 
+                                           freq - prev->ic_freq, channelSep);
+                               continue;
+                       }
+                       if (ci->ic_nchans == IEEE80211_CHAN_MAX) {
+                               if (verbose)
+                                       printf("%u: skip, channel table full\n",
+                                           freq);
+                               break;
+                       }
+                       c = &ci->ic_chans[ci->ic_nchans++];
+                       memset(c, 0, sizeof(*c));
+                       c->ic_freq = freq;
+                       c->ic_flags = flags;
+                       if (c->ic_flags & IEEE80211_CHAN_DFS)
+                               c->ic_maxregpower = nb->maxPowerDFS;
+                       else
+                               c->ic_maxregpower = nb->maxPower;
+                       if (verbose) {
+                               printf("[%3d] add freq %u ",
+                                   ci->ic_nchans-1, c->ic_freq);
+                               printb("flags", c->ic_flags, IEEE80211_CHAN_BITS);
+                               printf(" power %u\n", c->ic_maxregpower);
+                       }
+                       /* NB: kernel fills in other fields */
+                       prev = c;
+               }
+       }
+}
+
+static void
+regdomain_makechannels(
+       struct ieee80211_regdomain_req *req,
+       const struct ieee80211_devcaps_req *dc)
+{
+       struct regdata *rdp = getregdata();
+       const struct country *cc;
+       const struct ieee80211_regdomain *reg = &req->rd;
+       struct ieee80211req_chaninfo *ci = &req->chaninfo;
+       const struct regdomain *rd;
+
+       /*
+        * Locate construction table for new channel list.  We treat
+        * the regdomain/SKU as definitive so a country can be in
+        * multiple with different properties (e.g. US in FCC+FCC3).
+        * If no regdomain is specified then we fallback on the country
+        * code to find the associated regdomain since countries always
+        * belong to at least one regdomain.
+        */
+       if (reg->regdomain == 0) {
+               cc = lib80211_country_findbycc(rdp, reg->country);
+               if (cc == NULL)
+                       errx(1, "internal error, country %d not found",
+                           reg->country);
+               rd = cc->rd;
+       } else
+               rd = lib80211_regdomain_findbysku(rdp, reg->regdomain);
+       if (rd == NULL)
+               errx(1, "internal error, regdomain %d not found",
+                           reg->regdomain);
+       if (rd->sku != SKU_DEBUG) {
+               /*
+                * regdomain_addchans incrememnts the channel count for
+                * each channel it adds so initialize ic_nchans to zero.
+                * Note that we know we have enough space to hold all possible
+                * channels because the devcaps list size was used to
+                * allocate our request.
+                */
+               ci->ic_nchans = 0;
+               if (!LIST_EMPTY(&rd->bands_11b))
+                       regdomain_addchans(ci, &rd->bands_11b, reg,
+                           IEEE80211_CHAN_B, &dc->dc_chaninfo);
+               if (!LIST_EMPTY(&rd->bands_11g))
+                       regdomain_addchans(ci, &rd->bands_11g, reg,
+                           IEEE80211_CHAN_G, &dc->dc_chaninfo);
+               if (!LIST_EMPTY(&rd->bands_11a))
+                       regdomain_addchans(ci, &rd->bands_11a, reg,
+                           IEEE80211_CHAN_A, &dc->dc_chaninfo);
+               if (!LIST_EMPTY(&rd->bands_11na) && dc->dc_htcaps != 0) {
+                       regdomain_addchans(ci, &rd->bands_11na, reg,
+                           IEEE80211_CHAN_A | IEEE80211_CHAN_HT20,
+                           &dc->dc_chaninfo);
+                       if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
+                               regdomain_addchans(ci, &rd->bands_11na, reg,
+                                   IEEE80211_CHAN_A | IEEE80211_CHAN_HT40U,
+                                   &dc->dc_chaninfo);
+                               regdomain_addchans(ci, &rd->bands_11na, reg,
+                                   IEEE80211_CHAN_A | IEEE80211_CHAN_HT40D,
+                                   &dc->dc_chaninfo);
+                       }
+               }
+               if (!LIST_EMPTY(&rd->bands_11ng) && dc->dc_htcaps != 0) {
+                       regdomain_addchans(ci, &rd->bands_11ng, reg,
+                           IEEE80211_CHAN_G | IEEE80211_CHAN_HT20,
+                           &dc->dc_chaninfo);
+                       if (dc->dc_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
+                               regdomain_addchans(ci, &rd->bands_11ng, reg,
+                                   IEEE80211_CHAN_G | IEEE80211_CHAN_HT40U,
+                                   &dc->dc_chaninfo);
+                               regdomain_addchans(ci, &rd->bands_11ng, reg,
+                                   IEEE80211_CHAN_G | IEEE80211_CHAN_HT40D,
+                                   &dc->dc_chaninfo);
+                       }
+               }
+               qsort(ci->ic_chans, ci->ic_nchans, sizeof(ci->ic_chans[0]),
+                   regdomain_sort);
+       } else
+               memcpy(ci, &dc->dc_chaninfo,
+                   IEEE80211_CHANINFO_SPACE(&dc->dc_chaninfo));
+}
+
+static void
+list_countries(void)
+{
+       struct regdata *rdp = getregdata();
+       const struct country *cp;
+       const struct regdomain *dp;
+       int i;
+
+       i = 0;
+       printf("\nCountry codes:\n");
+       LIST_FOREACH(cp, &rdp->countries, next) {
+               printf("%2s %-15.15s%s", cp->isoname,
+                   cp->name, ((i+1)%4) == 0 ? "\n" : " ");
+               i++;
+       }
+       i = 0;
+       printf("\nRegulatory domains:\n");
+       LIST_FOREACH(dp, &rdp->domains, next) {
+               printf("%-15.15s%s", dp->name, ((i+1)%4) == 0 ? "\n" : " ");
+               i++;
+       }
+       printf("\n");
+}
+
+static void
+defaultcountry(const struct regdomain *rd)
+{
+       struct regdata *rdp = getregdata();
+       const struct country *cc;
+
+       cc = lib80211_country_findbycc(rdp, rd->cc->code);
+       if (cc == NULL)
+               errx(1, "internal error, ISO country code %d not "
+                   "defined for regdomain %s", rd->cc->code, rd->name);
+       regdomain.country = cc->code;
+       regdomain.isocc[0] = cc->isoname[0];
+       regdomain.isocc[1] = cc->isoname[1];
+}
+
+static
+DECL_CMD_FUNC(set80211regdomain, val, d)
+{
+       struct regdata *rdp = getregdata();
+       const struct regdomain *rd;
+
+       rd = lib80211_regdomain_findbyname(rdp, val);
+       if (rd == NULL) {
+               char *eptr;
+               long sku = strtol(val, &eptr, 0);
+
+               if (eptr != val)
+                       rd = lib80211_regdomain_findbysku(rdp, sku);
+               if (eptr == val || rd == NULL)
+                       errx(1, "unknown regdomain %s", val);
+       }
+       getregdomain(s);
+       regdomain.regdomain = rd->sku;
+       if (regdomain.country == 0 && rd->cc != NULL) {
+               /*
+                * No country code setup and there's a default
+                * one for this regdomain fill it in.
+                */
+               defaultcountry(rd);
+       }
+       callback_register(setregdomain_cb, &regdomain);
+}
+
+static
+DECL_CMD_FUNC(set80211country, val, d)
+{
+       struct regdata *rdp = getregdata();
+       const struct country *cc;
+
+       cc = lib80211_country_findbyname(rdp, val);
+       if (cc == NULL) {
+               char *eptr;
+               long code = strtol(val, &eptr, 0);
+
+               if (eptr != val)
+                       cc = lib80211_country_findbycc(rdp, code);
+               if (eptr == val || cc == NULL)
+                       errx(1, "unknown ISO country code %s", val);
+       }
+       getregdomain(s);
+       regdomain.regdomain = cc->rd->sku;
+       regdomain.country = cc->code;
+       regdomain.isocc[0] = cc->isoname[0];
+       regdomain.isocc[1] = cc->isoname[1];
+       callback_register(setregdomain_cb, &regdomain);
+}
+
+static void
+set80211location(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       getregdomain(s);
+       regdomain.location = d;
+       callback_register(setregdomain_cb, &regdomain);
+}
+
+static void
+set80211ecm(const char *val, int d, int s, const struct afswtch *rafp)
+{
+       getregdomain(s);
+       regdomain.ecm = d;
+       callback_register(setregdomain_cb, &regdomain);
+}
+
+static void
+LINE_INIT(char c)
+{
+       spacer = c;
+       if (c == '\t')
+               col = 8;
+       else
+               col = 1;
+}
+
+static void
+LINE_BREAK(void)
+{
+       if (spacer != '\t') {
+               printf("\n");
+               spacer = '\t';
+       }
+       col = 8;                /* 8-col tab */
+}
+
+static void
+LINE_CHECK(const char *fmt, ...)
+{
+       char buf[80];
+       va_list ap;
+       int n;
+
+       va_start(ap, fmt);
+       n = vsnprintf(buf+1, sizeof(buf)-1, fmt, ap);
+       va_end(ap);
+       col += 1+n;
+       if (col > MAXCOL) {
+               LINE_BREAK();
+               col += n;
+       }
+       buf[0] = spacer;
+       printf("%s", buf);
+       spacer = ' ';
+}
+
+static int
+getmaxrate(const uint8_t rates[15], uint8_t nrates)
+{
+       int i, maxrate = -1;
+
+       for (i = 0; i < nrates; i++) {
+               int rate = rates[i] & IEEE80211_RATE_VAL;
+               if (rate > maxrate)
+                       maxrate = rate;
+       }
+       return maxrate / 2;
+}
+
+static const char *
+getcaps(int capinfo)
+{
+       static char capstring[32];
+       char *cp = capstring;
 
        if (capinfo & IEEE80211_CAPINFO_ESS)
                *cp++ = 'E';
@@ -753,24 +2380,531 @@ getcaps(int capinfo)
        return capstring;
 }
 
+static const char *
+getflags(int flags)
+{
+       static char flagstring[32];
+       char *cp = flagstring;
+
+       if (flags & IEEE80211_NODE_AUTH)
+               *cp++ = 'A';
+       if (flags & IEEE80211_NODE_QOS)
+               *cp++ = 'Q';
+       if (flags & IEEE80211_NODE_ERP)
+               *cp++ = 'E';
+       if (flags & IEEE80211_NODE_PWR_MGT)
+               *cp++ = 'P';
+       if (flags & IEEE80211_NODE_HT) {
+               *cp++ = 'H';
+               if (flags & IEEE80211_NODE_HTCOMPAT)
+                       *cp++ = '+';
+       }
+       if (flags & IEEE80211_NODE_WPS)
+               *cp++ = 'W';
+       if (flags & IEEE80211_NODE_TSN)
+               *cp++ = 'N';
+       if (flags & IEEE80211_NODE_AMPDU_TX)
+               *cp++ = 'T';
+       if (flags & IEEE80211_NODE_AMPDU_RX)
+               *cp++ = 'R';
+       if (flags & IEEE80211_NODE_MIMO_PS) {
+               *cp++ = 'M';
+               if (flags & IEEE80211_NODE_MIMO_RTS)
+                       *cp++ = '+';
+       }
+       if (flags & IEEE80211_NODE_RIFS)
+               *cp++ = 'I';
+       if (flags & IEEE80211_NODE_SGI40) {
+               *cp++ = 'S';
+               if (flags & IEEE80211_NODE_SGI20)
+                       *cp++ = '+';
+       } else if (flags & IEEE80211_NODE_SGI20)
+               *cp++ = 's';
+       if (flags & IEEE80211_NODE_AMSDU_TX)
+               *cp++ = 't';
+       if (flags & IEEE80211_NODE_AMSDU_RX)
+               *cp++ = 'r';
+       *cp = '\0';
+       return flagstring;
+}
+
+static void
+printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
+{
+       printf("%s", tag);
+       if (verbose) {
+               maxlen -= strlen(tag)+2;
+               if (2*ielen > maxlen)
+                       maxlen--;
+               printf("<");
+               for (; ielen > 0; ie++, ielen--) {
+                       if (maxlen-- <= 0)
+                               break;
+                       printf("%02x", *ie);
+               }
+               if (ielen != 0)
+                       printf("-");
+               printf(">");
+       }
+}
+
+#define LE_READ_2(p)                                   \
+       ((u_int16_t)                                    \
+        ((((const u_int8_t *)(p))[0]      ) |          \
+         (((const u_int8_t *)(p))[1] <<  8)))
+#define LE_READ_4(p)                                   \
+       ((u_int32_t)                                    \
+        ((((const u_int8_t *)(p))[0]      ) |          \
+         (((const u_int8_t *)(p))[1] <<  8) |          \
+         (((const u_int8_t *)(p))[2] << 16) |          \
+         (((const u_int8_t *)(p))[3] << 24)))
+
+/*
+ * NB: The decoding routines assume a properly formatted ie
+ *     which should be safe as the kernel only retains them
+ *     if they parse ok.
+ */
+
+static void
+printwmeparam(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+#define        MS(_v, _f)      (((_v) & _f) >> _f##_S)
+       static const char *acnames[] = { "BE", "BK", "VO", "VI" };
+       const struct ieee80211_wme_param *wme =
+           (const struct ieee80211_wme_param *) ie;
+       int i;
+
+       printf("%s", tag);
+       if (!verbose)
+               return;
+       printf("<qosinfo 0x%x", wme->param_qosInfo);
+       ie += offsetof(struct ieee80211_wme_param, params_acParams);
+       for (i = 0; i < WME_NUM_AC; i++) {
+               const struct ieee80211_wme_acparams *ac =
+                   &wme->params_acParams[i];
+
+               printf(" %s[%saifsn %u cwmin %u cwmax %u txop %u]"
+                       , acnames[i]
+                       , MS(ac->acp_aci_aifsn, WME_PARAM_ACM) ? "acm " : ""
+                       , MS(ac->acp_aci_aifsn, WME_PARAM_AIFSN)
+                       , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMIN)
+                       , MS(ac->acp_logcwminmax, WME_PARAM_LOGCWMAX)
+                       , LE_READ_2(&ac->acp_txop)
+               );
+       }
+       printf(">");
+#undef MS
+}
+
+static void
+printwmeinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+       printf("%s", tag);
+       if (verbose) {
+               const struct ieee80211_wme_info *wme =
+                   (const struct ieee80211_wme_info *) ie;
+               printf("<version 0x%x info 0x%x>",
+                   wme->wme_version, wme->wme_info);
+       }
+}
+
+static void
+printhtcap(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+       printf("%s", tag);
+       if (verbose) {
+               const struct ieee80211_ie_htcap *htcap =
+                   (const struct ieee80211_ie_htcap *) ie;
+               const char *sep;
+               int i, j;
+
+               printf("<cap 0x%x param 0x%x",
+                   LE_READ_2(&htcap->hc_cap), htcap->hc_param);
+               printf(" mcsset[");
+               sep = "";
+               for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++)
+                       if (isset(htcap->hc_mcsset, i)) {
+                               for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++)
+                                       if (isclr(htcap->hc_mcsset, j))
+                                               break;
+                               j--;
+                               if (i == j)
+                                       printf("%s%u", sep, i);
+                               else
+                                       printf("%s%u-%u", sep, i, j);
+                               i += j-i;
+                               sep = ",";
+                       }
+               printf("] extcap 0x%x txbf 0x%x antenna 0x%x>",
+                   LE_READ_2(&htcap->hc_extcap),
+                   LE_READ_4(&htcap->hc_txbf),
+                   htcap->hc_antenna);
+       }
+}
+
+static void
+printhtinfo(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+       printf("%s", tag);
+       if (verbose) {
+               const struct ieee80211_ie_htinfo *htinfo =
+                   (const struct ieee80211_ie_htinfo *) ie;
+               const char *sep;
+               int i, j;
+
+               printf("<ctl %u, %x,%x,%x,%x", htinfo->hi_ctrlchannel,
+                   htinfo->hi_byte1, htinfo->hi_byte2, htinfo->hi_byte3,
+                   LE_READ_2(&htinfo->hi_byte45));
+               printf(" basicmcs[");
+               sep = "";
+               for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++)
+                       if (isset(htinfo->hi_basicmcsset, i)) {
+                               for (j = i+1; j < IEEE80211_HTRATE_MAXSIZE; j++)
+                                       if (isclr(htinfo->hi_basicmcsset, j))
+                                               break;
+                               j--;
+                               if (i == j)
+                                       printf("%s%u", sep, i);
+                               else
+                                       printf("%s%u-%u", sep, i, j);
+                               i += j-i;
+                               sep = ",";
+                       }
+               printf("]>");
+       }
+}
+
 static void
-printie(const char* tag, const uint8_t *ie, size_t ielen, int maxlen)
+printathie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
 {
+
        printf("%s", tag);
        if (verbose) {
-               maxlen -= strlen(tag)+2;
-               if (2*ielen > maxlen)
-                       maxlen--;
+               const struct ieee80211_ath_ie *ath =
+                       (const struct ieee80211_ath_ie *)ie;
+
                printf("<");
-               for (; ielen > 0; ie++, ielen--) {
-                       if (maxlen-- <= 0)
+               if (ath->ath_capability & ATHEROS_CAP_TURBO_PRIME)
+                       printf("DTURBO,");
+               if (ath->ath_capability & ATHEROS_CAP_COMPRESSION)
+                       printf("COMP,");
+               if (ath->ath_capability & ATHEROS_CAP_FAST_FRAME)
+                       printf("FF,");
+               if (ath->ath_capability & ATHEROS_CAP_XR)
+                       printf("XR,");
+               if (ath->ath_capability & ATHEROS_CAP_AR)
+                       printf("AR,");
+               if (ath->ath_capability & ATHEROS_CAP_BURST)
+                       printf("BURST,");
+               if (ath->ath_capability & ATHEROS_CAP_WME)
+                       printf("WME,");
+               if (ath->ath_capability & ATHEROS_CAP_BOOST)
+                       printf("BOOST,");
+               printf("0x%x>", LE_READ_2(ath->ath_defkeyix));
+       }
+}
+
+
+static void
+printmeshconf(const char *tag, const uint8_t *ie, size_t ielen, int maxlen)
+{
+#define MATCHOUI(field, oui, string)                                   \
+do {                                                                   \
+       if (memcmp(field, oui, 4) == 0)                                 \
+               printf("%s", string);                                   \
+} while (0)
+
+       printf("%s", tag);
+       if (verbose) {
+               const struct ieee80211_meshconf_ie *mconf =
+                       (const struct ieee80211_meshconf_ie *)ie;
+               printf("<PATH:");
+               if (mconf->conf_pselid == IEEE80211_MESHCONF_PATH_HWMP)
+                       printf("HWMP");
+               else
+                       printf("UNKNOWN");
+               printf(" LINK:");
+               if (mconf->conf_pmetid == IEEE80211_MESHCONF_METRIC_AIRTIME)
+                       printf("AIRTIME");
+               else
+                       printf("UNKNOWN");
+               printf(" CONGESTION:");
+               if (mconf->conf_ccid == IEEE80211_MESHCONF_CC_DISABLED)
+                       printf("DISABLED");
+               else
+                       printf("UNKNOWN");
+               printf(" SYNC:");
+               if (mconf->conf_syncid == IEEE80211_MESHCONF_SYNC_NEIGHOFF)
+                       printf("NEIGHOFF");
+               else
+                       printf("UNKNOWN");
+               printf(" AUTH:");
+               if (mconf->conf_authid == IEEE80211_MESHCONF_AUTH_DISABLED)
+                       printf("DISABLED");
+               else
+                       printf("UNKNOWN");
+               printf(" FORM:0x%x CAPS:0x%x>", mconf->conf_form,
+                   mconf->conf_cap);
+       }
+#undef MATCHOUI
+}
+
+static const char *
+wpa_cipher(const u_int8_t *sel)
+{
+#define        WPA_SEL(x)      (((x)<<24)|WPA_OUI)
+       u_int32_t w = LE_READ_4(sel);
+
+       switch (w) {
+       case WPA_SEL(WPA_CSE_NULL):
+               return "NONE";
+       case WPA_SEL(WPA_CSE_WEP40):
+               return "WEP40";
+       case WPA_SEL(WPA_CSE_WEP104):
+               return "WEP104";
+       case WPA_SEL(WPA_CSE_TKIP):
+               return "TKIP";
+       case WPA_SEL(WPA_CSE_CCMP):
+               return "AES-CCMP";
+       }
+       return "?";             /* NB: so 1<< is discarded */
+#undef WPA_SEL
+}
+
+static const char *
+wpa_keymgmt(const u_int8_t *sel)
+{
+#define        WPA_SEL(x)      (((x)<<24)|WPA_OUI)
+       u_int32_t w = LE_READ_4(sel);
+
+       switch (w) {
+       case WPA_SEL(WPA_ASE_8021X_UNSPEC):
+               return "8021X-UNSPEC";
+       case WPA_SEL(WPA_ASE_8021X_PSK):
+               return "8021X-PSK";
+       case WPA_SEL(WPA_ASE_NONE):
+               return "NONE";
+       }
+       return "?";
+#undef WPA_SEL
+}
+
+static void
+printwpaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+       u_int8_t len = ie[1];
+
+       printf("%s", tag);
+       if (verbose) {
+               const char *sep;
+               int n;
+
+               ie += 6, len -= 4;              /* NB: len is payload only */
+
+               printf("<v%u", LE_READ_2(ie));
+               ie += 2, len -= 2;
+
+               printf(" mc:%s", wpa_cipher(ie));
+               ie += 4, len -= 4;
+
+               /* unicast ciphers */
+               n = LE_READ_2(ie);
+               ie += 2, len -= 2;
+               sep = " uc:";
+               for (; n > 0; n--) {
+                       printf("%s%s", sep, wpa_cipher(ie));
+                       ie += 4, len -= 4;
+                       sep = "+";
+               }
+
+               /* key management algorithms */
+               n = LE_READ_2(ie);
+               ie += 2, len -= 2;
+               sep = " km:";
+               for (; n > 0; n--) {
+                       printf("%s%s", sep, wpa_keymgmt(ie));
+                       ie += 4, len -= 4;
+                       sep = "+";
+               }
+
+               if (len > 2)            /* optional capabilities */
+                       printf(", caps 0x%x", LE_READ_2(ie));
+               printf(">");
+       }
+}
+
+static const char *
+rsn_cipher(const u_int8_t *sel)
+{
+#define        RSN_SEL(x)      (((x)<<24)|RSN_OUI)
+       u_int32_t w = LE_READ_4(sel);
+
+       switch (w) {
+       case RSN_SEL(RSN_CSE_NULL):
+               return "NONE";
+       case RSN_SEL(RSN_CSE_WEP40):
+               return "WEP40";
+       case RSN_SEL(RSN_CSE_WEP104):
+               return "WEP104";
+       case RSN_SEL(RSN_CSE_TKIP):
+               return "TKIP";
+       case RSN_SEL(RSN_CSE_CCMP):
+               return "AES-CCMP";
+       case RSN_SEL(RSN_CSE_WRAP):
+               return "AES-OCB";
+       }
+       return "?";
+#undef WPA_SEL
+}
+
+static const char *
+rsn_keymgmt(const u_int8_t *sel)
+{
+#define        RSN_SEL(x)      (((x)<<24)|RSN_OUI)
+       u_int32_t w = LE_READ_4(sel);
+
+       switch (w) {
+       case RSN_SEL(RSN_ASE_8021X_UNSPEC):
+               return "8021X-UNSPEC";
+       case RSN_SEL(RSN_ASE_8021X_PSK):
+               return "8021X-PSK";
+       case RSN_SEL(RSN_ASE_NONE):
+               return "NONE";
+       }
+       return "?";
+#undef RSN_SEL
+}
+
+static void
+printrsnie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+       printf("%s", tag);
+       if (verbose) {
+               const char *sep;
+               int n;
+
+               ie += 2, ielen -= 2;
+
+               printf("<v%u", LE_READ_2(ie));
+               ie += 2, ielen -= 2;
+
+               printf(" mc:%s", rsn_cipher(ie));
+               ie += 4, ielen -= 4;
+
+               /* unicast ciphers */
+               n = LE_READ_2(ie);
+               ie += 2, ielen -= 2;
+               sep = " uc:";
+               for (; n > 0; n--) {
+                       printf("%s%s", sep, rsn_cipher(ie));
+                       ie += 4, ielen -= 4;
+                       sep = "+";
+               }
+
+               /* key management algorithms */
+               n = LE_READ_2(ie);
+               ie += 2, ielen -= 2;
+               sep = " km:";
+               for (; n > 0; n--) {
+                       printf("%s%s", sep, rsn_keymgmt(ie));
+                       ie += 4, ielen -= 4;
+                       sep = "+";
+               }
+
+               if (ielen > 2)          /* optional capabilities */
+                       printf(", caps 0x%x", LE_READ_2(ie));
+               /* XXXPMKID */
+               printf(">");
+       }
+}
+
+/* XXX move to a public include file */
+#define IEEE80211_WPS_DEV_PASS_ID      0x1012
+#define IEEE80211_WPS_SELECTED_REG     0x1041
+#define IEEE80211_WPS_SETUP_STATE      0x1044
+#define IEEE80211_WPS_UUID_E           0x1047
+#define IEEE80211_WPS_VERSION          0x104a
+
+#define BE_READ_2(p)                                   \
+       ((u_int16_t)                                    \
+        ((((const u_int8_t *)(p))[1]      ) |          \
+         (((const u_int8_t *)(p))[0] <<  8)))
+
+static void
+printwpsie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+#define        N(a)    (sizeof(a) / sizeof(a[0]))
+       u_int8_t len = ie[1];
+
+       printf("%s", tag);
+       if (verbose) {
+               static const char *dev_pass_id[] = {
+                       "D",    /* Default (PIN) */
+                       "U",    /* User-specified */
+                       "M",    /* Machine-specified */
+                       "K",    /* Rekey */
+                       "P",    /* PushButton */
+                       "R"     /* Registrar-specified */
+               };
+               int n;
+
+               ie +=6, len -= 4;               /* NB: len is payload only */
+
+               /* WPS IE in Beacon and Probe Resp frames have different fields */
+               printf("<");
+               while (len) {
+                       uint16_t tlv_type = BE_READ_2(ie);
+                       uint16_t tlv_len  = BE_READ_2(ie + 2);
+
+                       ie += 4, len -= 4;
+
+                       switch (tlv_type) {
+                       case IEEE80211_WPS_VERSION:
+                               printf("v:%d.%d", *ie >> 4, *ie & 0xf);
                                break;
-                       printf("%02x", *ie);
+                       case IEEE80211_WPS_SETUP_STATE:
+                               /* Only 1 and 2 are valid */
+                               if (*ie == 0 || *ie >= 3)
+                                       printf(" state:B");
+                               else
+                                       printf(" st:%s", *ie == 1 ? "N" : "C");
+                               break;
+                       case IEEE80211_WPS_SELECTED_REG:
+                               printf(" sel:%s", *ie ? "T" : "F");
+                               break;
+                       case IEEE80211_WPS_DEV_PASS_ID:
+                               n = LE_READ_2(ie);
+                               if (n < N(dev_pass_id))
+                                       printf(" dpi:%s", dev_pass_id[n]);
+                               break;
+                       case IEEE80211_WPS_UUID_E:
+                               printf(" uuid-e:");
+                               for (n = 0; n < (tlv_len - 1); n++)
+                                       printf("%02x-", ie[n]);
+                               printf("%02x", ie[n]);
+                               break;
+                       }
+                       ie += tlv_len, len -= tlv_len;
                }
-               if (ielen != 0)
-                       printf("-");
                printf(">");
        }
+#undef N
+}
+
+static void
+printtdmaie(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+       printf("%s", tag);
+       if (verbose && ielen >= sizeof(struct ieee80211_tdma_param)) {
+               const struct ieee80211_tdma_param *tdma =
+                  (const struct ieee80211_tdma_param *) ie;
+
+               /* XXX tstamp */
+               printf("<v%u slot:%u slotcnt:%u slotlen:%u bintval:%u inuse:0x%x>",
+                   tdma->tdma_version, tdma->tdma_slot, tdma->tdma_slotcnt,
+                   LE_READ_2(&tdma->tdma_slotlen), tdma->tdma_bintval,
+                   tdma->tdma_inuse[0]);
+       }
 }
 
 /*
@@ -815,6 +2949,52 @@ copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
        return maxlen;
 }
 
+static void
+printssid(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+       char ssid[2*IEEE80211_NWID_LEN+1];
+
+       printf("%s<%.*s>", tag, copy_essid(ssid, maxlen, ie+2, ie[1]), ssid);
+}
+
+static void
+printrates(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+       const char *sep;
+       int i;
+
+       printf("%s", tag);
+       sep = "<";
+       for (i = 2; i < ielen; i++) {
+               printf("%s%s%d", sep,
+                   ie[i] & IEEE80211_RATE_BASIC ? "B" : "",
+                   ie[i] & IEEE80211_RATE_VAL);
+               sep = ",";
+       }
+       printf(">");
+}
+
+static void
+printcountry(const char *tag, const u_int8_t *ie, size_t ielen, int maxlen)
+{
+       const struct ieee80211_country_ie *cie =
+          (const struct ieee80211_country_ie *) ie;
+       int i, nbands, schan, nchan;
+
+       printf("%s<%c%c%c", tag, cie->cc[0], cie->cc[1], cie->cc[2]);
+       nbands = (cie->len - 3) / sizeof(cie->band[0]);
+       for (i = 0; i < nbands; i++) {
+               schan = cie->band[i].schan;
+               nchan = cie->band[i].nchan;
+               if (nchan != 1)
+                       printf(" %u-%u,%u", schan, schan + nchan-1,
+                           cie->band[i].maxtxpwr);
+               else
+                       printf(" %u,%u", schan, cie->band[i].maxtxpwr);
+       }
+       printf(">");
+}
+
 /* unaligned little endian access */     
 #define LE_READ_4(p)                                   \
        ((u_int32_t)                                    \
@@ -823,44 +3003,132 @@ copy_essid(char buf[], size_t bufsize, const u_int8_t *essid, size_t essid_len)
          (((const u_int8_t *)(p))[2] << 16) |          \
          (((const u_int8_t *)(p))[3] << 24)))
 
-static int __inline
+static __inline int
 iswpaoui(const u_int8_t *frm)
 {
        return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
 }
 
-static int __inline
-iswmeoui(const u_int8_t *frm)
+static __inline int
+iswmeinfo(const u_int8_t *frm)
+{
+       return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
+               frm[6] == WME_INFO_OUI_SUBTYPE;
+}
+
+static __inline int
+iswmeparam(const u_int8_t *frm)
 {
-       return frm[1] > 3 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI);
+       return frm[1] > 5 && LE_READ_4(frm+2) == ((WME_OUI_TYPE<<24)|WME_OUI) &&
+               frm[6] == WME_PARAM_OUI_SUBTYPE;
 }
 
-static int __inline
+static __inline int
 isatherosoui(const u_int8_t *frm)
 {
        return frm[1] > 3 && LE_READ_4(frm+2) == ((ATH_OUI_TYPE<<24)|ATH_OUI);
 }
 
+static __inline int
+istdmaoui(const uint8_t *frm)
+{
+       return frm[1] > 3 && LE_READ_4(frm+2) == ((TDMA_OUI_TYPE<<24)|TDMA_OUI);
+}
+
+static __inline int
+iswpsoui(const uint8_t *frm)
+{
+       return frm[1] > 3 && LE_READ_4(frm+2) == ((WPS_OUI_TYPE<<24)|WPA_OUI);
+}
+
+static const char *
+iename(int elemid)
+{
+       switch (elemid) {
+       case IEEE80211_ELEMID_FHPARMS:  return " FHPARMS";
+       case IEEE80211_ELEMID_CFPARMS:  return " CFPARMS";
+       case IEEE80211_ELEMID_TIM:      return " TIM";
+       case IEEE80211_ELEMID_IBSSPARMS:return " IBSSPARMS";
+       case IEEE80211_ELEMID_CHALLENGE:return " CHALLENGE";
+       case IEEE80211_ELEMID_PWRCNSTR: return " PWRCNSTR";
+       case IEEE80211_ELEMID_PWRCAP:   return " PWRCAP";
+       case IEEE80211_ELEMID_TPCREQ:   return " TPCREQ";
+       case IEEE80211_ELEMID_TPCREP:   return " TPCREP";
+       case IEEE80211_ELEMID_SUPPCHAN: return " SUPPCHAN";
+       case IEEE80211_ELEMID_CSA:      return " CSA";
+       case IEEE80211_ELEMID_MEASREQ:  return " MEASREQ";
+       case IEEE80211_ELEMID_MEASREP:  return " MEASREP";
+       case IEEE80211_ELEMID_QUIET:    return " QUIET";
+       case IEEE80211_ELEMID_IBSSDFS:  return " IBSSDFS";
+       case IEEE80211_ELEMID_TPC:      return " TPC";
+       case IEEE80211_ELEMID_CCKM:     return " CCKM";
+       }
+       return " ???";
+}
+
 static void
 printies(const u_int8_t *vp, int ielen, int maxcols)
 {
        while (ielen > 0) {
                switch (vp[0]) {
+               case IEEE80211_ELEMID_SSID:
+                       if (verbose)
+                               printssid(" SSID", vp, 2+vp[1], maxcols);
+                       break;
+               case IEEE80211_ELEMID_RATES:
+               case IEEE80211_ELEMID_XRATES:
+                       if (verbose)
+                               printrates(vp[0] == IEEE80211_ELEMID_RATES ?
+                                   " RATES" : " XRATES", vp, 2+vp[1], maxcols);
+                       break;
+               case IEEE80211_ELEMID_DSPARMS:
+                       if (verbose)
+                               printf(" DSPARMS<%u>", vp[2]);
+                       break;
+               case IEEE80211_ELEMID_COUNTRY:
+                       if (verbose)
+                               printcountry(" COUNTRY", vp, 2+vp[1], maxcols);
+                       break;
+               case IEEE80211_ELEMID_ERP:
+                       if (verbose)
+                               printf(" ERP<0x%x>", vp[2]);
+                       break;
                case IEEE80211_ELEMID_VENDOR:
                        if (iswpaoui(vp))
-                               printie(" WPA", vp, 2+vp[1], maxcols);
-                       else if (iswmeoui(vp))
-                               printie(" WME", vp, 2+vp[1], maxcols);
+                               printwpaie(" WPA", vp, 2+vp[1], maxcols);
+                       else if (iswmeinfo(vp))
+                               printwmeinfo(" WME", vp, 2+vp[1], maxcols);
+                       else if (iswmeparam(vp))
+                               printwmeparam(" WME", vp, 2+vp[1], maxcols);
                        else if (isatherosoui(vp))
-                               printie(" ATH", vp, 2+vp[1], maxcols);
-                       else
+                               printathie(" ATH", vp, 2+vp[1], maxcols);
+                       else if (iswpsoui(vp))
+                               printwpsie(" WPS", vp, 2+vp[1], maxcols);
+                       else if (istdmaoui(vp))
+                               printtdmaie(" TDMA", vp, 2+vp[1], maxcols);
+                       else if (verbose)
                                printie(" VEN", vp, 2+vp[1], maxcols);
                        break;
                case IEEE80211_ELEMID_RSN:
-                       printie(" RSN", vp, 2+vp[1], maxcols);
+                       printrsnie(" RSN", vp, 2+vp[1], maxcols);
+                       break;
+               case IEEE80211_ELEMID_HTCAP:
+                       printhtcap(" HTCAP", vp, 2+vp[1], maxcols);
+                       break;
+               case IEEE80211_ELEMID_HTINFO:
+                       if (verbose)
+                               printhtinfo(" HTINFO", vp, 2+vp[1], maxcols);
+                       break;
+               case IEEE80211_ELEMID_MESHID:
+                       if (verbose)
+                               printssid(" MESHID", vp, 2+vp[1], maxcols);
+                       break;
+               case IEEE80211_ELEMID_MESHCONF:
+                       printmeshconf(" MESHCONF", vp, 2+vp[1], maxcols);
                        break;
                default:
-                       printie(" ???", vp, 2+vp[1], maxcols);
+                       if (verbose)
+                               printie(iename(vp[0]), vp, 2+vp[1], maxcols);
                        break;
                }
                ielen -= 2+vp[1];
@@ -868,65 +3136,79 @@ printies(const u_int8_t *vp, int ielen, int maxcols)
        }
 }
 
+static void
+printmimo(const struct ieee80211_mimo_info *mi)
+{
+       /* NB: don't muddy display unless there's something to show */
+       if (mi->rssi[0] != 0 || mi->rssi[1] != 0 || mi->rssi[2] != 0) {
+               /* XXX ignore EVM for now */
+               printf(" (rssi %d:%d:%d nf %d:%d:%d)",
+                   mi->rssi[0], mi->rssi[1], mi->rssi[2],
+                   mi->noise[0], mi->noise[1], mi->noise[2]);
+       }
+}
+
 static void
 list_scan(int s)
 {
        uint8_t buf[24*1024];
-       struct ieee80211req ireq;
        char ssid[IEEE80211_NWID_LEN+1];
-       uint8_t *cp;
-       int len, ssidmax;
+       const uint8_t *cp;
+       int len, ssidmax, idlen;
 
-       (void) memset(&ireq, 0, sizeof(ireq));
-       (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
-       ireq.i_type = IEEE80211_IOC_SCAN_RESULTS;
-       ireq.i_data = buf;
-       ireq.i_len = sizeof(buf);
-       if (ioctl(s, SIOCG80211, &ireq) < 0)
+       if (get80211len(s, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf), &len) < 0)
                errx(1, "unable to get scan results");
-       len = ireq.i_len;
        if (len < sizeof(struct ieee80211req_scan_result))
                return;
 
-       ssidmax = verbose ? IEEE80211_NWID_LEN : 14;
-       printf("%-*.*s  %-17.17s  %4s %4s  %-5s %3s %4s\n"
-               , ssidmax, ssidmax, "SSID"
+       getchaninfo(s);
+
+       ssidmax = verbose ? IEEE80211_NWID_LEN - 1 : 14;
+       printf("%-*.*s  %-17.17s  %4s %4s  %-7s  %3s %4s\n"
+               , ssidmax, ssidmax, "SSID/MESH ID"
                , "BSSID"
                , "CHAN"
                , "RATE"
-               , "S:N"
+               , " S:N"
                , "INT"
                , "CAPS"
        );
        cp = buf;
        do {
-               struct ieee80211req_scan_result *sr;
-               uint8_t *vp;
-
-               sr = (struct ieee80211req_scan_result *) cp;
-               vp = (u_int8_t *)(sr+1);
-               printf("%-*.*s  %s  %3d  %3dM %2d:%-2d  %3d %-4.4s"
+               const struct ieee80211req_scan_result *sr;
+               const uint8_t *vp, *idp;
+
+               sr = (const struct ieee80211req_scan_result *) cp;
+               vp = cp + sr->isr_ie_off;
+               if (sr->isr_meshid_len) {
+                       idp = vp + sr->isr_ssid_len;
+                       idlen = sr->isr_meshid_len;
+               } else {
+                       idp = vp;
+                       idlen = sr->isr_ssid_len;
+               }
+               printf("%-*.*s  %s  %3d  %3dM %3d:%-3d  %3d %-4.4s"
                        , ssidmax
-                         , copy_essid(ssid, ssidmax, vp, sr->isr_ssid_len)
+                         , copy_essid(ssid, ssidmax, idp, idlen)
                          , ssid
                        , ether_ntoa((const struct ether_addr *) sr->isr_bssid)
-                       , ieee80211_mhz2ieee(sr->isr_freq)
+                       , ieee80211_mhz2ieee(sr->isr_freq, sr->isr_flags)
                        , getmaxrate(sr->isr_rates, sr->isr_nrates)
-                       , sr->isr_rssi, sr->isr_noise
+                       , (sr->isr_rssi/2)+sr->isr_noise, sr->isr_noise
                        , sr->isr_intval
-                       , getcaps(sr->isr_capinfo2)
+                       , getcaps(sr->isr_capinfo)
                );
-               printies(vp + sr->isr_ssid_len, sr->isr_ie_len, 24);
+               printies(vp + sr->isr_ssid_len + sr->isr_meshid_len,
+                   sr->isr_ie_len, 24);
                printf("\n");
                cp += sr->isr_len, len -= sr->isr_len;
        } while (len >= sizeof(struct ieee80211req_scan_result));
 }
 
-#include <netproto/802_11/ieee80211_dragonfly.h>
-
 static void
 scan_and_wait(int s)
 {
+       struct ieee80211_scan_req sr;
        struct ieee80211req ireq;
        int sroute;
 
@@ -938,6 +3220,16 @@ scan_and_wait(int s)
        (void) memset(&ireq, 0, sizeof(ireq));
        (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
        ireq.i_type = IEEE80211_IOC_SCAN_REQ;
+
+       memset(&sr, 0, sizeof(sr));
+       sr.sr_flags = IEEE80211_IOC_SCAN_ACTIVE
+                   | IEEE80211_IOC_SCAN_NOPICK
+                   | IEEE80211_IOC_SCAN_ONCE;
+       sr.sr_duration = IEEE80211_IOC_SCAN_FOREVER;
+       sr.sr_nssid = 0;
+
+       ireq.i_data = &sr;
+       ireq.i_len = sizeof(sr);
        /* NB: only root can trigger a scan so ignore errors */
        if (ioctl(s, SIOCS80211, &ireq) >= 0) {
                char buf[2048];
@@ -968,6 +3260,36 @@ DECL_CMD_FUNC(set80211scan, val, d)
 
 static enum ieee80211_opmode get80211opmode(int s);
 
+static int
+gettxseq(const struct ieee80211req_sta_info *si)
+{
+       int i, txseq;
+
+       if ((si->isi_state & IEEE80211_NODE_QOS) == 0)
+               return si->isi_txseqs[0];
+       /* XXX not right but usually what folks want */
+       txseq = 0;
+       for (i = 0; i < IEEE80211_TID_SIZE; i++)
+               if (si->isi_txseqs[i] > txseq)
+                       txseq = si->isi_txseqs[i];
+       return txseq;
+}
+
+static int
+getrxseq(const struct ieee80211req_sta_info *si)
+{
+       int i, rxseq;
+
+       if ((si->isi_state & IEEE80211_NODE_QOS) == 0)
+               return si->isi_rxseqs[0];
+       /* XXX not right but usually what folks want */
+       rxseq = 0;
+       for (i = 0; i < IEEE80211_TID_SIZE; i++)
+               if (si->isi_rxseqs[i] > rxseq)
+                       rxseq = si->isi_rxseqs[i];
+       return rxseq;
+}
+
 static void
 list_stations(int s)
 {
@@ -976,141 +3298,329 @@ list_stations(int s)
                uint8_t buf[24*1024];
        } u;
        enum ieee80211_opmode opmode = get80211opmode(s);
-       struct ieee80211req ireq;
-       uint8_t *cp;
+       const uint8_t *cp;
        int len;
 
-       (void) memset(&ireq, 0, sizeof(ireq));
-       (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
        /* broadcast address =>'s get all stations */
        (void) memset(u.req.is_u.macaddr, 0xff, IEEE80211_ADDR_LEN);
        if (opmode == IEEE80211_M_STA) {
                /*
                 * Get information about the associated AP.
                 */
-               ireq.i_type = IEEE80211_IOC_BSSID;
-               ireq.i_data = u.req.is_u.macaddr;
-               ireq.i_len = IEEE80211_ADDR_LEN;
-               (void) ioctl(s, SIOCG80211, &ireq);
-       }
-       ireq.i_type = IEEE80211_IOC_STA_INFO;
-       ireq.i_data = &u;
-       ireq.i_len = sizeof(u);
-       if (ioctl(s, SIOCG80211, &ireq) < 0)
+               (void) get80211(s, IEEE80211_IOC_BSSID,
+                   u.req.is_u.macaddr, IEEE80211_ADDR_LEN);
+       }
+       if (get80211len(s, IEEE80211_IOC_STA_INFO, &u, sizeof(u), &len) < 0)
                errx(1, "unable to get station information");
-       len = ireq.i_len;
        if (len < sizeof(struct ieee80211req_sta_info))
                return;
 
-       printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %3s\n"
-               , "ADDR"
-               , "AID"
-               , "CHAN"
-               , "RATE"
-               , "RSSI"
-               , "IDLE"
-               , "TXSEQ"
-               , "RXSEQ"
-               , "CAPS"
-               , "ERP"
-       );
-       cp = (uint8_t *) u.req.info;
+       getchaninfo(s);
+
+       if (opmode == IEEE80211_M_MBSS)
+               printf("%-17.17s %4s %5s %5s %7s %4s %4s %4s %6s %6s\n"
+                       , "ADDR"
+                       , "CHAN"
+                       , "LOCAL"
+                       , "PEER"
+                       , "STATE"
+                       , "RATE"
+                       , "RSSI"
+                       , "IDLE"
+                       , "TXSEQ"
+                       , "RXSEQ"
+               );
+       else 
+               printf("%-17.17s %4s %4s %4s %4s %4s %6s %6s %4s %-7s\n"
+                       , "ADDR"
+                       , "AID"
+                       , "CHAN"
+                       , "RATE"
+                       , "RSSI"
+                       , "IDLE"
+                       , "TXSEQ"
+                       , "RXSEQ"
+                       , "CAPS"
+                       , "FLAG"
+               );
+       cp = (const uint8_t *) u.req.info;
        do {
-               struct ieee80211req_sta_info *si;
-               uint8_t *vp;
+               const struct ieee80211req_sta_info *si;
 
-               si = (struct ieee80211req_sta_info *) cp;
+               si = (const struct ieee80211req_sta_info *) cp;
                if (si->isi_len < sizeof(*si))
                        break;
-               vp = (u_int8_t *)(si+1);
-               printf("%s %4u %4d %3dM %4d %4d %6d %6d %-4.4s %3x"
-                       , ether_ntoa((const struct ether_addr*) si->isi_macaddr)
-                       , IEEE80211_AID(si->isi_associd)
-                       , ieee80211_mhz2ieee(si->isi_freq)
-                       , (si->isi_rates[si->isi_txrate] & IEEE80211_RATE_VAL)/2
-                       , si->isi_rssi
-                       , si->isi_inact
-                       , si->isi_txseqs[0]
-                       , si->isi_rxseqs[0]
-                       , getcaps(si->isi_capinfo2)
-                       , si->isi_erp
-               );
-               printies(vp, si->isi_ie_len, 24);
+               if (opmode == IEEE80211_M_MBSS)
+                       printf("%s %4d %5x %5x %7.7s %3dM %4.1f %4d %6d %6d"
+                               , ether_ntoa((const struct ether_addr*)
+                                   si->isi_macaddr)
+                               , ieee80211_mhz2ieee(si->isi_freq,
+                                   si->isi_flags)
+                               , si->isi_localid
+                               , si->isi_peerid
+                               , mesh_linkstate_string(si->isi_peerstate)
+                               , si->isi_txmbps/2
+                               , si->isi_rssi/2.
+                               , si->isi_inact
+                               , gettxseq(si)
+                               , getrxseq(si)
+                       );
+               else 
+                       printf("%s %4u %4d %3dM %4.1f %4d %6d %6d %-4.4s %-7.7s"
+                               , ether_ntoa((const struct ether_addr*)
+                                   si->isi_macaddr)
+                               , IEEE80211_AID(si->isi_associd)
+                               , ieee80211_mhz2ieee(si->isi_freq,
+                                   si->isi_flags)
+                               , si->isi_txmbps/2
+                               , si->isi_rssi/2.
+                               , si->isi_inact
+                               , gettxseq(si)
+                               , getrxseq(si)
+                               , getcaps(si->isi_capinfo)
+                               , getflags(si->isi_state)
+                       );
+               printies(cp + si->isi_ie_off, si->isi_ie_len, 24);
+               printmimo(&si->isi_mimo);
                printf("\n");
                cp += si->isi_len, len -= si->isi_len;
        } while (len >= sizeof(struct ieee80211req_sta_info));
 }
 
-static void
-print_chaninfo(const struct ieee80211_channel *c)
+static const char *
+mesh_linkstate_string(uint8_t state)
 {
-#define        IEEE80211_IS_CHAN_PASSIVE(_c) \
-       (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE))
-       char buf[14];
+#define        N(a)    (sizeof(a) / sizeof(a[0]))
+       static const char *state_names[] = {
+           [0] = "IDLE",
+           [1] = "OPEN-TX",
+           [2] = "OPEN-RX",
+           [3] = "CONF-RX",
+           [4] = "ESTAB",
+           [5] = "HOLDING",
+       };
+
+       if (state >= N(state_names)) {
+               static char buf[10];
+               snprintf(buf, sizeof(buf), "#%u", state);
+               return buf;
+       } else
+               return state_names[state];
+#undef N
+}
 
+static const char *
+get_chaninfo(const struct ieee80211_channel *c, int precise,
+       char buf[], size_t bsize)
+{
        buf[0] = '\0';
        if (IEEE80211_IS_CHAN_FHSS(c))
-               strlcat(buf, " FHSS", sizeof(buf));
+               strlcat(buf, " FHSS", bsize);
        if (IEEE80211_IS_CHAN_A(c))
-               strlcat(buf, " 11a", sizeof(buf));
-       /* XXX 11g schizophrenia */
-       if (IEEE80211_IS_CHAN_G(c) ||
-           IEEE80211_IS_CHAN_PUREG(c))
-               strlcat(buf, " 11g", sizeof(buf));
+               strlcat(buf, " 11a", bsize);
+       else if (IEEE80211_IS_CHAN_ANYG(c))
+               strlcat(buf, " 11g", bsize);
        else if (IEEE80211_IS_CHAN_B(c))
-               strlcat(buf, " 11b", sizeof(buf));
-       if (IEEE80211_IS_CHAN_T(c))
-               strlcat(buf, " Turbo", sizeof(buf));
-       printf("Channel %3u : %u%c Mhz%-14.14s",
-               ieee80211_mhz2ieee(c->ic_freq), c->ic_freq,
-               IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ', buf);
-#undef IEEE80211_IS_CHAN_PASSIVE
+               strlcat(buf, " 11b", bsize);
+       if (IEEE80211_IS_CHAN_HALF(c))
+               strlcat(buf, "/10MHz", bsize);
+       if (IEEE80211_IS_CHAN_QUARTER(c))
+               strlcat(buf, "/5MHz", bsize);
+       if (IEEE80211_IS_CHAN_TURBO(c))
+               strlcat(buf, " Turbo", bsize);
+       if (precise) {
+               if (IEEE80211_IS_CHAN_HT20(c))
+                       strlcat(buf, " ht/20", bsize);
+               else if (IEEE80211_IS_CHAN_HT40D(c))
+                       strlcat(buf, " ht/40-", bsize);
+               else if (IEEE80211_IS_CHAN_HT40U(c))
+                       strlcat(buf, " ht/40+", bsize);
+       } else {
+               if (IEEE80211_IS_CHAN_HT(c))
+                       strlcat(buf, " ht", bsize);
+       }
+       return buf;
 }
 
 static void
-list_channels(int s, int allchans)
+print_chaninfo(const struct ieee80211_channel *c, int verb)
 {
-       struct ieee80211req ireq;
-       struct ieee80211req_chaninfo chans;
-       struct ieee80211req_chaninfo achans;
+       char buf[14];
+
+       printf("Channel %3u : %u%c MHz%-14.14s",
+               ieee80211_mhz2ieee(c->ic_freq, c->ic_flags), c->ic_freq,
+               IEEE80211_IS_CHAN_PASSIVE(c) ? '*' : ' ',
+               get_chaninfo(c, verb, buf, sizeof(buf)));
+}
+
+static int
+chanpref(const struct ieee80211_channel *c)
+{
+       if (IEEE80211_IS_CHAN_HT40(c))
+               return 40;
+       if (IEEE80211_IS_CHAN_HT20(c))
+               return 30;
+       if (IEEE80211_IS_CHAN_HALF(c))
+               return 10;
+       if (IEEE80211_IS_CHAN_QUARTER(c))
+               return 5;
+       if (IEEE80211_IS_CHAN_TURBO(c))
+               return 25;
+       if (IEEE80211_IS_CHAN_A(c))
+               return 20;
+       if (IEEE80211_IS_CHAN_G(c))
+               return 20;
+       if (IEEE80211_IS_CHAN_B(c))
+               return 15;
+       if (IEEE80211_IS_CHAN_PUREG(c))
+               return 15;
+       return 0;
+}
+
+static void
+print_channels(int s, const struct ieee80211req_chaninfo *chans,
+       int allchans, int verb)
+{
+       struct ieee80211req_chaninfo *achans;
+       uint8_t reported[IEEE80211_CHAN_BYTES];
        const struct ieee80211_channel *c;
        int i, half;
 
-       (void) memset(&ireq, 0, sizeof(ireq));
-       (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
-       ireq.i_type = IEEE80211_IOC_CHANINFO;
-       ireq.i_data = &chans;
-       ireq.i_len = sizeof(chans);
-       if (ioctl(s, SIOCG80211, &ireq) < 0)
-               errx(1, "unable to get channel information");
+       achans = malloc(IEEE80211_CHANINFO_SPACE(chans));
+       if (achans == NULL)
+               errx(1, "no space for active channel list");
+       achans->ic_nchans = 0;
+       memset(reported, 0, sizeof(reported));
        if (!allchans) {
                struct ieee80211req_chanlist active;
 
-               ireq.i_type = IEEE80211_IOC_CHANLIST;
-               ireq.i_data = &active;
-               ireq.i_len = sizeof(active);
-               if (ioctl(s, SIOCG80211, &ireq) < 0)
+               if (get80211(s, IEEE80211_IOC_CHANLIST, &active, sizeof(active)) < 0)
                        errx(1, "unable to get active channel list");
-               memset(&achans, 0, sizeof(achans));
-               for (i = 0; i < chans.ic_nchans; i++) {
-                       c = &chans.ic_chans[i];
-                       if (isset(active.ic_channels, ieee80211_mhz2ieee(c->ic_freq)) || allchans)
-                               achans.ic_chans[achans.ic_nchans++] = *c;
+               for (i = 0; i < chans->ic_nchans; i++) {
+                       c = &chans->ic_chans[i];
+                       if (!isset(active.ic_channels, c->ic_ieee))
+                               continue;
+                       /*
+                        * Suppress compatible duplicates unless
+                        * verbose.  The kernel gives us it's
+                        * complete channel list which has separate
+                        * entries for 11g/11b and 11a/turbo.
+                        */
+                       if (isset(reported, c->ic_ieee) && !verb) {
+                               /* XXX we assume duplicates are adjacent */
+                               achans->ic_chans[achans->ic_nchans-1] = *c;
+                       } else {
+                               achans->ic_chans[achans->ic_nchans++] = *c;
+                               setbit(reported, c->ic_ieee);
+                       }
                }
-       } else
-               achans = chans;
-       half = achans.ic_nchans / 2;
-       if (achans.ic_nchans % 2)
+       } else {
+               for (i = 0; i < chans->ic_nchans; i++) {
+                       c = &chans->ic_chans[i];
+                       /* suppress duplicates as above */
+                       if (isset(reported, c->ic_ieee) && !verb) {
+                               /* XXX we assume duplicates are adjacent */
+                               struct ieee80211_channel *a =
+                                   &achans->ic_chans[achans->ic_nchans-1];
+                               if (chanpref(c) > chanpref(a))
+                                       *a = *c;
+                       } else {
+                               achans->ic_chans[achans->ic_nchans++] = *c;
+                               setbit(reported, c->ic_ieee);
+                       }
+               }
+       }
+       half = achans->ic_nchans / 2;
+       if (achans->ic_nchans % 2)
                half++;
-       for (i = 0; i < achans.ic_nchans / 2; i++) {
-               print_chaninfo(&achans.ic_chans[i]);
-               print_chaninfo(&achans.ic_chans[half+i]);
+
+       for (i = 0; i < achans->ic_nchans / 2; i++) {
+               print_chaninfo(&achans->ic_chans[i], verb);
+               print_chaninfo(&achans->ic_chans[half+i], verb);
                printf("\n");
        }
-       if (achans.ic_nchans % 2) {
-               print_chaninfo(&achans.ic_chans[i]);
+       if (achans->ic_nchans % 2) {
+               print_chaninfo(&achans->ic_chans[i], verb);
                printf("\n");
        }
+       free(achans);
+}
+
+static void
+list_channels(int s, int allchans)
+{
+       getchaninfo(s);
+       print_channels(s, chaninfo, allchans, verbose);
+}
+
+static void
+print_txpow(const struct ieee80211_channel *c)
+{
+       printf("Channel %3u : %u MHz %3.1f reg %2d  ",
+           c->ic_ieee, c->ic_freq,
+           c->ic_maxpower/2., c->ic_maxregpower);
+}
+
+static void
+print_txpow_verbose(const struct ieee80211_channel *c)
+{
+       print_chaninfo(c, 1);
+       printf("min %4.1f dBm  max %3.1f dBm  reg %2d dBm",
+           c->ic_minpower/2., c->ic_maxpower/2., c->ic_maxregpower);
+       /* indicate where regulatory cap limits power use */
+       if (c->ic_maxpower > 2*c->ic_maxregpower)
+               printf(" <");
+}
+
+static void
+list_txpow(int s)
+{
+       struct ieee80211req_chaninfo *achans;
+       uint8_t reported[IEEE80211_CHAN_BYTES];
+       struct ieee80211_channel *c, *prev;
+       int i, half;
+
+       getchaninfo(s);
+       achans = malloc(IEEE80211_CHANINFO_SPACE(chaninfo));
+       if (achans == NULL)
+               errx(1, "no space for active channel list");
+       achans->ic_nchans = 0;
+       memset(reported, 0, sizeof(reported));
+       for (i = 0; i < chaninfo->ic_nchans; i++) {
+               c = &chaninfo->ic_chans[i];
+               /* suppress duplicates as above */
+               if (isset(reported, c->ic_ieee) && !verbose) {
+                       /* XXX we assume duplicates are adjacent */
+                       prev = &achans->ic_chans[achans->ic_nchans-1];
+                       /* display highest power on channel */
+                       if (c->ic_maxpower > prev->ic_maxpower)
+                               *prev = *c;
+               } else {
+                       achans->ic_chans[achans->ic_nchans++] = *c;
+                       setbit(reported, c->ic_ieee);
+               }
+       }
+       if (!verbose) {
+               half = achans->ic_nchans / 2;
+               if (achans->ic_nchans % 2)
+                       half++;
+
+               for (i = 0; i < achans->ic_nchans / 2; i++) {
+                       print_txpow(&achans->ic_chans[i]);
+                       print_txpow(&achans->ic_chans[half+i]);
+                       printf("\n");
+               }
+               if (achans->ic_nchans % 2) {
+                       print_txpow(&achans->ic_chans[i]);
+                       printf("\n");
+               }
+       } else {
+               for (i = 0; i < achans->ic_nchans; i++) {
+                       print_txpow_verbose(&achans->ic_chans[i]);
+                       printf("\n");
+               }
+       }
+       free(achans);
 }
 
 static void
@@ -1119,89 +3629,215 @@ list_keys(int s)
 }
 
 #define        IEEE80211_C_BITS \
-"\020\1WEP\2TKIP\3AES\4AES_CCM\6CKIP\11IBSS\12PMGT\13HOSTAP\14AHDEMO" \
-"\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE\21MONITOR\22TKIPMIC\30WPA1" \
-"\31WPA2\32BURST\33WME"
-
-#define IEEE80211_CEXT_BITS    "\020\1PBCC"
+       "\20\1STA\002803ENCAP\7FF\10TURBOP\11IBSS\12PMGT" \
+       "\13HOSTAP\14AHDEMO\15SWRETRY\16TXPMGT\17SHSLOT\20SHPREAMBLE" \
+       "\21MONITOR\22DFS\23MBSS\30WPA1\31WPA2\32BURST\33WME\34WDS\36BGSCAN" \
+       "\37TXFRAG\40TDMA"
 
 static void
 list_capabilities(int s)
+{
+       struct ieee80211_devcaps_req *dc;
+
+       if (verbose)
+               dc = malloc(IEEE80211_DEVCAPS_SIZE(MAXCHAN));
+       else
+               dc = malloc(IEEE80211_DEVCAPS_SIZE(1));
+       if (dc == NULL)
+               errx(1, "no space for device capabilities");
+       dc->dc_chaninfo.ic_nchans = verbose ? MAXCHAN : 1;
+       getdevcaps(s, dc);
+       printb("drivercaps", dc->dc_drivercaps, IEEE80211_C_BITS);
+       if (dc->dc_cryptocaps != 0 || verbose) {
+               putchar('\n');
+               printb("cryptocaps", dc->dc_cryptocaps, IEEE80211_CRYPTO_BITS);
+       }
+       if (dc->dc_htcaps != 0 || verbose) {
+               putchar('\n');
+               printb("htcaps", dc->dc_htcaps, IEEE80211_HTCAP_BITS);
+       }
+       putchar('\n');
+       if (verbose) {
+               chaninfo = &dc->dc_chaninfo;    /* XXX */
+               print_channels(s, &dc->dc_chaninfo, 1/*allchans*/, verbose);
+       }
+       free(dc);
+}
+
+static int
+get80211wme(int s, int param, int ac, int *val)
 {
        struct ieee80211req ireq;
-       uint32_t caps, caps_ext;
 
-       memset(&ireq, 0, sizeof(ireq));
-       caps_ext = 0;
+       (void) memset(&ireq, 0, sizeof(ireq));
+       (void) strncpy(ireq.i_name, name, sizeof(ireq.i_name));
+       ireq.i_type = param;
+       ireq.i_len = ac;
+       if (ioctl(s, SIOCG80211, &ireq) < 0) {
+               warn("cannot get WME parameter %d, ac %d%s",
+                   param, ac & IEEE80211_WMEPARAM_VAL,
+                   ac & IEEE80211_WMEPARAM_BSS ? " (BSS)" : "");
+               return -1;
+       }
+       *val = ireq.i_val;
+       return 0;
+}
 
-       strncpy(ireq.i_name, name, sizeof(ireq.i_name));
-       ireq.i_data = &caps_ext;
-       ireq.i_len = sizeof(caps_ext);
-       ireq.i_type = IEEE80211_IOC_DRIVER_CAPS;
-       if (ioctl(s, SIOCG80211, &ireq) < 0)
-               errx(1, "unable to get driver capabilities");
-       caps = (((uint16_t)ireq.i_val) << 16) | ((uint16_t)ireq.i_len);
-       printb(name, caps, IEEE80211_C_BITS);
-       if (caps_ext != 0)
-               printb(", ext", caps_ext, IEEE80211_CEXT_BITS);