From: Felix Fietkau <nbd@openwrt.org>
Date: Fri, 2 Oct 2009 15:18:44 +0000 (+0000)
Subject: mac80211: merge Pat Erley's mac80211.sh from openwrt-devel@ with many cleanups and... 
X-Git-Tag: reboot~22313
X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=5c3c14b02fc9f3926ab50abccf91b0384aec4d10;p=openwrt%2Fstaging%2Fblogic.git

mac80211: merge Pat Erley's mac80211.sh from openwrt-devel@ with many cleanups and other changes by me. adds support for multiple interfaces, tested with ath9k

SVN-Revision: 17821
---

diff --git a/package/mac80211/Makefile b/package/mac80211/Makefile
index 789ddb38c2c2..1ca2314d64d5 100644
--- a/package/mac80211/Makefile
+++ b/package/mac80211/Makefile
@@ -36,7 +36,7 @@ endef
 define KernelPackage/mac80211
   $(call KernelPackage/mac80211/Default)
   TITLE:=Linux 802.11 Wireless Networking Stack
-  DEPENDS+= +kmod-crypto-arc4 +kmod-crypto-aes +wireless-tools @!LINUX_2_6_21 @!LINUX_2_6_25
+  DEPENDS+= +kmod-crypto-arc4 +kmod-crypto-aes +wireless-tools +@PACKAGE_iw @!LINUX_2_6_21 @!LINUX_2_6_25
   FILES:= \
 	$(PKG_BUILD_DIR)/net/mac80211/mac80211.$(LINUX_KMOD_SUFFIX) \
 	$(PKG_BUILD_DIR)/net/wireless/cfg80211.$(LINUX_KMOD_SUFFIX)
diff --git a/package/mac80211/files/lib/wifi/mac80211.sh b/package/mac80211/files/lib/wifi/mac80211.sh
index 5d4fcee27132..703131cc4f68 100644
--- a/package/mac80211/files/lib/wifi/mac80211.sh
+++ b/package/mac80211/files/lib/wifi/mac80211.sh
@@ -1,16 +1,35 @@
 #!/bin/sh
 append DRIVERS "mac80211"
 
+find_mac80211_phy() {
+	config_get device "$1"
+
+	local macaddr="$(config_get "$device" macaddr | tr 'A-Z' 'a-z')"
+	config_get phy "$device" phy
+	[ -z "$phy" -a -n "$macaddr" ] && {
+		for phy in $(ls /sys/class/ieee80211); do
+			[ "$macaddr" = "$(cat /sys/class/ieee80211/${phy}/macaddress)" ] || continue
+			config_set "$device" phy "$phy"
+			break
+		done
+		config_get phy "$device" phy
+	}
+	[ -n "$phy" -a -d "/sys/class/ieee80211/$phy" ] || {
+		echo "PHY for wifi device $1 not found"
+		return 1
+	}
+	[ -z "$macaddr" ] && {
+		config_set "$device" macaddr "$(cat /sys/class/ieee80211/${phy}/macaddress)"
+	}
+	return 0
+}
+
 scan_mac80211() {
 	local device="$1"
 	local adhoc sta ap monitor mesh
 
 	config_get vifs "$device" vifs
 	for vif in $vifs; do
-
-		config_get ifname "$vif" ifname
-		config_set "$vif" ifname "${ifname:-$device}"
-
 		config_get mode "$vif" mode
 		case "$mode" in
 			adhoc|sta|ap|monitor|mesh)
@@ -27,6 +46,9 @@ scan_mac80211() {
 disable_mac80211() (
 	local device="$1"
 
+	find_mac80211_phy "$device" || return 0
+	config_get phy "$device" phy
+
 	set_wifi_down "$device"
 	# kill all running hostapd and wpa_supplicant processes that
 	# are running on atheros/mac80211 vifs
@@ -36,13 +58,12 @@ disable_mac80211() (
 	done
 
 	include /lib/network
-	cd /proc/sys/net
-	for dev in *; do
-		grep "$device" "$dev/%parent" >/dev/null 2>/dev/null && {
-			ifconfig "$dev" down
-			unbridge "$dev"
-		}
+	for wdev in $(ls /sys/class/ieee80211/${phy}/device/net); do
+		ifconfig "$wdev" down 2>/dev/null
+		unbridge "$dev"
+		iw dev "$wdev" del
 	done
+
 	return 0
 )
 
@@ -51,77 +72,109 @@ enable_mac80211() {
 	config_get channel "$device" channel
 	config_get vifs "$device" vifs
 	config_get txpower "$device" txpower
+	find_mac80211_phy "$device" || return 0
+	config_get phy "$device" phy
+	local i=0
 
-	local first=1
-	local mesh_idx=0
 	wifi_fixup_hwmode "$device" "g"
 	for vif in $vifs; do
-		ifconfig "$ifname" down 2>/dev/null
-		config_get ifname "$vif" ifname
-		config_get enc "$vif" encryption
-		config_get eap_type "$vif" eap_type
-		config_get mode "$vif" mode
+		while [ -d "/sys/class/net/wlan$i" ]; do
+			i=$(($i + 1))
+		done
 
 		config_get ifname "$vif" ifname
-		[ $? -ne 0 ] && {
-			echo "enable_mac80211($device): Failed to set up $mode vif $ifname" >&2
-			continue
+		[ -n "$ifname" ] || {
+			ifname="wlan$i"
 		}
-		config_set "$vif" ifname "$ifname"
-
-		[ "$first" = 1 ] && {
-			# only need to change freq band and channel on the first vif
-			iwconfig "$ifname" channel "$channel" >/dev/null 2>/dev/null
-			if [ "$mode" = adhoc ]; then
-				iwlist "$ifname" scan >/dev/null 2>/dev/null
-				sleep 1
-				iwconfig "$ifname" mode ad-hoc >/dev/null 2>/dev/null
-			fi
-			# mesh interface should be created only for the first interface
-			if [ "$mode" = mesh ]; then
-				config_get mesh_id "$vif" mesh_id
-				if [ -n "$mesh_id" ]; then
-					iw dev "$ifname" interface add msh$mesh_idx type mp mesh_id $mesh_id
-				fi
-			fi
-			sleep 1
-			iwconfig "$ifname" channel "$channel" >/dev/null 2>/dev/null
-		}
-		if [ "$mode" = sta ]; then
-			iwconfig "$ifname" mode managed >/dev/null 2>/dev/null
-		else
-			iwconfig "$ifname" mode $mode >/dev/null 2>/dev/null
-		fi
+		config_set ifname "$vif" ifname
 
-		wpa=
-		case "$enc" in
-			WEP|wep)
-				for idx in 1 2 3 4; do
-					config_get key "$vif" "key${idx}"
-					iwconfig "$ifname" enc "[$idx]" "${key:-off}"
-				done
-				config_get key "$vif" key
-				key="${key:-1}"
-				case "$key" in
-					[1234]) iwconfig "$ifname" enc "[$key]";;
-					*) iwconfig "$ifname" enc "$key";;
-				esac
-			;;
-			PSK|psk|PSK2|psk2)
-				config_get key "$vif" key
-			;;
-		esac
+		config_get enc "$vif" encryption
+		config_get mode "$vif" mode
+		config_get ssid "$vif" ssid
 
+		# It is far easier to delete and create the desired interface
 		case "$mode" in
 			adhoc)
-				config_get addr "$vif" bssid
-				[ -z "$addr" ] || {
-					iwconfig "$ifname" ap "$addr"
-				}
+				iw phy "$phy" interface add "$ifname" type adhoc
+			;;
+			ap)
+				# Hostapd will handle recreating the interface and
+				# it's accompanying monitor
+				iw phy "$phy" interface add "$ifname" type managed
+			;;
+			mesh)
+				config_get mesh_id "$vif" mesh_id
+				iw phy "$phy" interface add "$ifname" type mp mesh_id "$mesh_id"
+			;;
+			monitor)
+				iw phy "$phy" interface add "$ifname" type monitor
+			;;
+			sta)
+				iw phy "$phy" interface add "$ifname" type managed
 			;;
 		esac
-		config_get ssid "$vif" ssid
 
+		# All interfaces must have unique mac addresses
+		# which can either be explicitly set in the device 
+		# section, or automatically generated
+		config_get macaddr "$device" macaddr
+		local mac_1="${macaddr%%:*}"
+		local mac_2="${macaddr#*:}"
+
+		config_get vif_mac "$vif" macaddr
+		[ -n "$vif_mac" ] || {
+			if [ "$i" -gt 0 ]; then 
+				offset="$(( 2 + $i * 4 ))"
+			else
+				offset="0"
+			fi
+			vif_mac="$( printf %02x $(($mac_1 + $offset)) ):$mac_2"
+		}
+		ifconfig "$ifname" hw ether "$vif_mac"
+
+		# We attempt to set teh channel for all interfaces, although
+		# mac80211 may not support it or the driver might not yet
+		iw dev "$ifname" set channel "$channel" 
+
+		local key keystring
+
+		# Valid values are:
+		# wpa / wep / none
+		#
+		# !! ap !!
+		#
+		# ALL ap functionality will be passed to hostapd
+		#
+		# !! mesh / adhoc / station !!
+		# none -> NO encryption
+		#
+		# wep + keymgmt = '' -> we use iw to connect to the
+		# network.  
+		#
+		# wep + keymgmt = 'NONE' -> wpa_supplicant will be
+		# configured to handle the wep connection
+		if [ ! "$mode" = "ap" ]; then
+			case "$enc" in
+				wep)
+					config_get keymgmt "$vif" keymgmt
+					if [ -e "$keymgmt" ]; then
+						for idx in 1 2 3 4; do
+							local zidx
+							zidx = idx - 1
+							config_get key "$vif" "key${idx}"
+							if [ -n "$key" ]; then
+								append keystring "${zidx}:${key} " 
+							fi
+						done
+					fi
+				;;
+				wpa)
+					config_get key "$vif" key
+				;;
+			esac
+		fi
+
+		# txpower is not yet implemented in iw
 		config_get vif_txpower "$vif" txpower
 		# use vif_txpower (from wifi-iface) to override txpower (from
 		# wifi-device) if the latter doesn't exist
@@ -130,16 +183,15 @@ enable_mac80211() {
 
 		config_get frag "$vif" frag
 		if [ -n "$frag" ]; then
-			iwconfig "$ifname" frag "${frag%%.*}"
+			iw phy "$phy" set frag "${frag%%.*}"
 		fi
 
 		config_get rts "$vif" rts
 		if [ -n "$rts" ]; then
-			iwconfig "$ifname" rts "${rts%%.*}"
+			iw phy "$phy" set rts "${frag%%.*}"
 		fi
 
 		ifconfig "$ifname" up
-		iwconfig "$ifname" channel "$channel" >/dev/null 2>/dev/null
 
 		local net_cfg bridge
 		net_cfg="$(find_net_config "$vif")"
@@ -148,7 +200,7 @@ enable_mac80211() {
 			config_set "$vif" bridge "$bridge"
 			start_net "$ifname" "$net_cfg"
 		}
-		iwconfig "$ifname" essid "$ssid"
+
 		set_wifi_up "$vif" "$ifname"
 		case "$mode" in
 			ap)
@@ -161,48 +213,82 @@ enable_mac80211() {
 					}
 				fi
 			;;
-			sta)
-				if eval "type wpa_supplicant_setup_vif" 2>/dev/null >/dev/null; then
-					wpa_supplicant_setup_vif "$vif" wext || {
-						echo "enable_mac80211($device): Failed to set up wpa_supplicant for interface $ifname" >&2
-						# make sure this wifi interface won't accidentally stay open without encryption
-						ifconfig "$ifname" down
-						continue
-					}
-				fi
-			;;
-			mesh)
-				# special case where physical interface should be down for mesh to work
-				ifconfig "$ifname" down
-				ifconfig "msh$mesh_idx" up
-				iwlist msh$mesh_idx scan 2>/dev/null >/dev/null
+			sta|mesh|adhoc)
+				# Fixup... sometimes you have to scan to get beaconing going
+				iw dev "$ifname" scan &> /dev/null
+				case "$enc" in												 
+					wep)
+						if [ -e "$keymgmt" ]; then
+							[ -n "$keystring" ] &&
+								iw dev "$ifname" connect "$ssid" key "$keystring"
+						else
+							if eval "type wpa_supplicant_setup_vif" 2>/dev/null >/dev/null; then
+								wpa_supplicant_setup_vif "$vif" wext || {
+									echo "enable_mac80211($device): Failed to set up wpa_supplicant for interface $ifname" >&2
+									# make sure this wifi interface won't accidentally stay open without encryption
+									ifconfig "$ifname" down
+									continue
+								}
+							fi
+						fi
+					;;
+					wpa)
+						if eval "type wpa_supplicant_setup_vif" 2>/dev/null >/dev/null; then
+							wpa_supplicant_setup_vif "$vif" wext || {
+								echo "enable_mac80211($device): Failed to set up wpa_supplicant for interface $ifname" >&2
+								# make sure this wifi interface won't accidentally stay open without encryption
+								ifconfig "$ifname" down
+								continue
+							}
+						fi
+					;;
+				esac
+
 			;;
 		esac
-		first=0
-		mesh_idx=$(expr $mesh_idx + 1)
 	done
 }
 
 
+check_device() {
+	config_get phy "$1" phy
+	[ -z "$phy" ] && {
+		find_mac80211_phy "$1" || return 0
+		config_get phy "$1" phy
+	}
+	[ "$phy" = "$dev" ] && found=1
+}
+
 detect_mac80211() {
-	cd /sys/class/net
-	for dev in $(ls -d wlan* 2>&-); do
-		config_get type "$dev" type
-		[ "$type" = mac80211 ] && return
+	devidx=0
+	config_load wireless
+	for dev in $(ls /sys/class/ieee80211); do
+		found=0
+		config_foreach check_device wifi-device
+		[ "$found" -gt 0 ] && continue
+
+		while :; do 
+			config_get type "wifi$devidx" type
+			[ -n "$type" ] || break
+			devidx=$(($devidx + 1))
+		done
+
 		cat <<EOF
-config wifi-device  $dev
+config wifi-device  wifi$devidx
 	option type     mac80211
 	option channel  5
-
+	option macaddr	$(cat /sys/class/ieee80211/${dev}/macaddress)
 	# REMOVE THIS LINE TO ENABLE WIFI:
 	option disabled 1
 
 config wifi-iface
-	option device	$dev
-	option network	lan
-	option mode	ap
-	option ssid	OpenWrt
+	option device   wifi$devidx
+	option network  lan
+	option mode     ap
+	option ssid     OpenWrt
 	option encryption none
+
 EOF
 	done
 }
+