source: trunk/package/mac80211/files/lib/wifi/mac80211.sh @ 25837

Last change on this file since 25837 was 25837, checked in by nbd, 6 years ago

mac80211: allow AP configuration of beacon interval, DTIM period, maximum permissible STA listen interval, and basic rates

This introduces beacon_int and basic_rate (per wifi-device), and
dtim_period and max_listen_int (per wifi-iface) for mac80211. These
configure the beacon interval, basic rate specification, DTIM period
(one DTIM per this many beacon frames), and maximum listen interval
that a STA will be permitted to associate with. All of the new
settings are optional; if they're absent, the existing hostapd (or, in
the case of basic_rate, driver) defaults will be used.

The existing bintval property only used for type adhoc is moved from
wifi-iface to wifi-device, and is renamed to beacon_interval because
bintval isn't a great name. The beacon interval is property of the
wifi-device; while the choice between wifi-device and wifi-iface may
not be relevant with an adhoc network, there's no reason to configure
the same property one way for type adhoc and another for type ap. This
change isn't expected to cause many problems, as bintval was added
recently, in r25111.

Similarly, the list of basic rates, also added for type adhoc in
r25111, is a property of the device and not the interface. Further, it
ought to be represented in UCI as a list, not a string dependent on
the format that iw uses. I’ve moved it onto the device, renamed it to
basic_rate, and made it configurable for APs via hostapd. Finally, I
adapted it to use the same kb/s representation as mcast_rate; there's
precedent for this format in that it's also how madwifi interprets
mcast_rate.

Neither bintval nor basicrates were ever documented in the UCI
wireless configuration page on the wiki. When this change is
committed, I'll update the documentation as needed.

Signed-off-by: Mark Mentovai <mark@…>

File size: 14.2 KB
Line 
1#!/bin/sh
2append DRIVERS "mac80211"
3
4mac80211_hostapd_setup_base() {
5        local phy="$1"
6        local ifname="$2"
7
8        cfgfile="/var/run/hostapd-$phy.conf"
9        macfile="/var/run/hostapd-$phy.maclist"
10        [ -e "$macfile" ] && rm -f "$macfile"
11
12        config_get device "$vif" device
13        config_get country "$device" country
14        config_get hwmode "$device" hwmode
15        config_get channel "$device" channel
16        config_get beacon_int "$device" beacon_int
17        config_get basic_rate_list "$device" basic_rate
18        config_get_bool noscan "$device" noscan
19        [ -n "$channel" -a -z "$hwmode" ] && wifi_fixup_hwmode "$device"
20        [ "$channel" = auto ] && channel=
21        [ -n "$hwmode" ] && {
22                config_get hwmode_11n "$device" hwmode_11n
23                [ -n "$hwmode_11n" ] && {
24                        hwmode="$hwmode_11n"
25                        append base_cfg "ieee80211n=1" "$N"
26                        config_get htmode "$device" htmode
27                        config_get ht_capab_list "$device" ht_capab
28                        case "$htmode" in
29                                HT20|HT40+|HT40-) ht_capab="[$htmode]";;
30                                *)ht_capab=;;
31                        esac
32                        for cap in $ht_capab_list; do
33                                ht_capab="$ht_capab[$cap]"
34                        done
35                        [ -n "$ht_capab" ] && append base_cfg "ht_capab=$ht_capab" "$N"
36                }
37        }
38
39        config_get macfilter "$vif" macfilter
40        case "$macfilter" in
41                allow)
42                        append base_cfg "macaddr_acl=1" "$N"
43                        append base_cfg "accept_mac_file=$macfile" "$N"
44                        ;;
45                deny)
46                        append base_cfg "macaddr_acl=0" "$N"
47                        append base_cfg "deny_mac_file=$macfile" "$N"
48                        ;;
49        esac
50        config_get maclist "$vif" maclist
51        [ -n "$maclist" ] && {
52                for mac in $maclist; do
53                        echo "$mac" >> $macfile
54                done
55        }
56
57        local br brval brstr
58        [ -n "$basic_rate_list" ] && {
59                for br in $basic_rate_list; do
60                        brval="$(($br / 100))"
61                        [ -n "$brstr" ] && brstr="$brstr "
62                        brstr="$brstr$brval"
63                done
64        }
65       
66        cat >> "$cfgfile" <<EOF
67ctrl_interface=/var/run/hostapd-$phy
68driver=nl80211
69wmm_ac_bk_cwmin=4
70wmm_ac_bk_cwmax=10
71wmm_ac_bk_aifs=7
72wmm_ac_bk_txop_limit=0
73wmm_ac_bk_acm=0
74wmm_ac_be_aifs=3
75wmm_ac_be_cwmin=4
76wmm_ac_be_cwmax=10
77wmm_ac_be_txop_limit=0
78wmm_ac_be_acm=0
79wmm_ac_vi_aifs=2
80wmm_ac_vi_cwmin=3
81wmm_ac_vi_cwmax=4
82wmm_ac_vi_txop_limit=94
83wmm_ac_vi_acm=0
84wmm_ac_vo_aifs=2
85wmm_ac_vo_cwmin=2
86wmm_ac_vo_cwmax=3
87wmm_ac_vo_txop_limit=47
88wmm_ac_vo_acm=0
89tx_queue_data3_aifs=7
90tx_queue_data3_cwmin=15
91tx_queue_data3_cwmax=1023
92tx_queue_data3_burst=0
93tx_queue_data2_aifs=3
94tx_queue_data2_cwmin=15
95tx_queue_data2_cwmax=63
96tx_queue_data2_burst=0
97tx_queue_data1_aifs=1
98tx_queue_data1_cwmin=7
99tx_queue_data1_cwmax=15
100tx_queue_data1_burst=3.0
101tx_queue_data0_aifs=1
102tx_queue_data0_cwmin=3
103tx_queue_data0_cwmax=7
104tx_queue_data0_burst=1.5
105${hwmode:+hw_mode=$hwmode}
106${channel:+channel=$channel}
107${beacon_int:+beacon_int=$beacon_int}
108${country:+country_code=$country}
109${noscan:+noscan=$noscan}
110${brstr:+basic_rates=$brstr}
111$base_cfg
112
113EOF
114}
115
116mac80211_hostapd_setup_bss() {
117        local phy="$1"
118        local vif="$2"
119
120        hostapd_cfg=
121        cfgfile="/var/run/hostapd-$phy.conf"
122        config_get ifname "$vif" ifname
123
124        if [ -f "$cfgfile" ]; then
125                append hostapd_cfg "bss=$ifname" "$N"
126        else
127                mac80211_hostapd_setup_base "$phy" "$ifname"
128                append hostapd_cfg "interface=$ifname" "$N"
129        fi
130
131        local net_cfg bridge
132        net_cfg="$(find_net_config "$vif")"
133        [ -z "$net_cfg" ] || bridge="$(bridge_interface "$net_cfg")"
134        config_set "$vif" bridge "$bridge"
135
136        hostapd_set_bss_options hostapd_cfg "$vif"
137
138        config_get_bool wds "$vif" wds 0
139        [ "$wds" -gt 0 ] && append hostapd_cfg "wds_sta=1" "$N"
140
141        local macaddr hidden maxassoc wmm
142        config_get macaddr "$vif" macaddr
143        config_get maxassoc "$vif" maxassoc
144        config_get dtim_period "$vif" dtim_period
145        config_get max_listen_int "$vif" max_listen_int
146        config_get_bool hidden "$vif" hidden 0
147        config_get_bool wmm "$vif" wmm 1
148        cat >> /var/run/hostapd-$phy.conf <<EOF
149$hostapd_cfg
150wmm_enabled=$wmm
151bssid=$macaddr
152ignore_broadcast_ssid=$hidden
153${dtim_period:+dtim_period=$dtim_period}
154${max_listen_int:+max_listen_interval=$max_listen_int}
155${maxassoc:+max_num_sta=$maxassoc}
156EOF
157}
158
159mac80211_start_vif() {
160        local vif="$1"
161        local ifname="$2"
162
163        local net_cfg
164        net_cfg="$(find_net_config "$vif")"
165        [ -z "$net_cfg" ] || start_net "$ifname" "$net_cfg"
166
167        set_wifi_up "$vif" "$ifname"
168}
169
170find_mac80211_phy() {
171        local device="$1"
172
173        local macaddr="$(config_get "$device" macaddr | tr 'A-Z' 'a-z')"
174        config_get phy "$device" phy
175        [ -z "$phy" -a -n "$macaddr" ] && {
176                for phy in $(ls /sys/class/ieee80211 2>/dev/null); do
177                        [ "$macaddr" = "$(cat /sys/class/ieee80211/${phy}/macaddress)" ] || continue
178                        config_set "$device" phy "$phy"
179                        break
180                done
181                config_get phy "$device" phy
182        }
183        [ -n "$phy" -a -d "/sys/class/ieee80211/$phy" ] || {
184                echo "PHY for wifi device $1 not found"
185                return 1
186        }
187        [ -z "$macaddr" ] && {
188                config_set "$device" macaddr "$(cat /sys/class/ieee80211/${phy}/macaddress)"
189        }
190        return 0
191}
192
193scan_mac80211() {
194        local device="$1"
195        local adhoc sta ap monitor mesh
196
197        config_get vifs "$device" vifs
198        for vif in $vifs; do
199                config_get mode "$vif" mode
200                case "$mode" in
201                        adhoc|sta|ap|monitor|mesh)
202                                append $mode "$vif"
203                        ;;
204                        *) echo "$device($vif): Invalid mode, ignored."; continue;;
205                esac
206        done
207
208        config_set "$device" vifs "${ap:+$ap }${adhoc:+$adhoc }${sta:+$sta }${monitor:+$monitor }${mesh:+$mesh}"
209}
210
211list_phy_interfaces() {
212        local phy="$1"
213        if [ -d "/sys/class/ieee80211/${phy}/device/net" ]; then
214                ls "/sys/class/ieee80211/${phy}/device/net" 2>/dev/null;
215        else
216                ls "/sys/class/ieee80211/${phy}/device" 2>/dev/null | grep net: | sed -e 's,net:,,g'
217        fi
218}
219
220disable_mac80211() (
221        local device="$1"
222
223        find_mac80211_phy "$device" || return 0
224        config_get phy "$device" phy
225
226        set_wifi_down "$device"
227        # kill all running hostapd and wpa_supplicant processes that
228        # are running on atheros/mac80211 vifs
229        for pid in `pidof hostapd`; do
230                grep -E "$phy" /proc/$pid/cmdline >/dev/null && \
231                        kill $pid
232        done
233
234        include /lib/network
235        for wdev in $(list_phy_interfaces "$phy"); do
236                [ -f "/var/run/$wdev.pid" ] && kill $(cat /var/run/$wdev.pid) >&/dev/null 2>&1
237                for pid in `pidof wpa_supplicant`; do
238                        grep "$wdev" /proc/$pid/cmdline >/dev/null && \
239                                kill $pid
240                done
241                ifconfig "$wdev" down 2>/dev/null
242                unbridge "$dev"
243                iw dev "$wdev" del
244        done
245
246        return 0
247)
248get_freq() {
249        local phy="$1"
250        local chan="$2"
251        iw "$phy" info | grep -E -m1 "(\* ${chan:-....} MHz${chan:+|\\[$chan\\]})" | grep MHz | awk '{print $2}'
252}
253enable_mac80211() {
254        local device="$1"
255        config_get channel "$device" channel
256        config_get vifs "$device" vifs
257        config_get txpower "$device" txpower
258        config_get country "$device" country
259        config_get distance "$device" distance
260        config_get txantenna "$device" txantenna all
261        config_get rxantenna "$device" rxantenna all
262        config_get frag "$device" frag
263        config_get rts "$device" rts
264        find_mac80211_phy "$device" || return 0
265        config_get phy "$device" phy
266        local i=0
267        local macidx=0
268        local apidx=0
269        fixed=""
270        local hostapd_ctrl=""
271
272        [ -n "$country" ] && iw reg set "$country"
273        [ "$channel" = "auto" -o "$channel" = "0" ] || {
274                fixed=1
275        }
276
277        iw phy "$phy" set antenna $txantenna $rxantenna >/dev/null 2>&1
278
279        [ -n "$distance" ] && iw phy "$phy" set distance "$distance"
280        [ -n "$frag" ] && iw phy "$phy" set frag "${frag%%.*}"
281        [ -n "$rts" ] && iw phy "$phy" set rts "${rts%%.*}"
282
283        export channel fixed
284        # convert channel to frequency
285        local freq="$(get_freq "$phy" "${fixed:+$channel}")"
286
287        wifi_fixup_hwmode "$device" "g"
288        for vif in $vifs; do
289                while [ -d "/sys/class/net/wlan$i" ]; do
290                        i=$(($i + 1))
291                done
292
293                config_get ifname "$vif" ifname
294                [ -n "$ifname" ] || {
295                        ifname="wlan$i"
296                }
297                config_set "$vif" ifname "$ifname"
298
299                config_get mode "$vif" mode
300                config_get ssid "$vif" ssid
301
302                # It is far easier to delete and create the desired interface
303                case "$mode" in
304                        adhoc)
305                                iw phy "$phy" interface add "$ifname" type adhoc
306                        ;;
307                        ap)
308                                # Hostapd will handle recreating the interface and
309                                # it's accompanying monitor
310                                apidx="$(($apidx + 1))"
311                                i=$(($i + 1))
312                                [ "$apidx" -gt 1 ] || iw phy "$phy" interface add "$ifname" type managed
313                        ;;
314                        mesh)
315                                config_get mesh_id "$vif" mesh_id
316                                iw phy "$phy" interface add "$ifname" type mp mesh_id "$mesh_id"
317                        ;;
318                        monitor)
319                                iw phy "$phy" interface add "$ifname" type monitor
320                        ;;
321                        sta)
322                                local wdsflag
323                                config_get_bool wds "$vif" wds 0
324                                [ "$wds" -gt 0 ] && wdsflag="4addr on"
325                                iw phy "$phy" interface add "$ifname" type managed $wdsflag
326                                config_get_bool powersave "$vif" powersave 0
327                                [ "$powersave" -gt 0 ] && powersave="on" || powersave="off"
328                                iwconfig "$ifname" power "$powersave"
329                        ;;
330                esac
331
332                # All interfaces must have unique mac addresses
333                # which can either be explicitly set in the device
334                # section, or automatically generated
335                config_get macaddr "$device" macaddr
336                local mac_1="${macaddr%%:*}"
337                local mac_2="${macaddr#*:}"
338
339                config_get vif_mac "$vif" macaddr
340                [ -n "$vif_mac" ] || {
341                        if [ "$macidx" -gt 0 ]; then
342                                offset="$(( 2 + $macidx * 4 ))"
343                        else
344                                offset="0"
345                        fi
346                        vif_mac="$( printf %02x $((0x$mac_1 + $offset)) ):$mac_2"
347                        macidx="$(($macidx + 1))"
348                }
349                [ "$mode" = "ap" ] || ifconfig "$ifname" hw ether "$vif_mac"
350                config_set "$vif" macaddr "$vif_mac"
351
352                # !! ap !!
353                #
354                # ALL ap functionality will be passed to hostapd
355                #
356                # !! station !!
357                #
358                # ALL station functionality will be passed to wpa_supplicant
359                #
360                if [ ! "$mode" = "ap" ]; then
361                        # We attempt to set the channel for all interfaces, although
362                        # mac80211 may not support it or the driver might not yet
363                        # for ap mode this is handled by hostapd
364                        [ -n "$fixed" -a -n "$channel" ] && iw dev "$ifname" set channel "$channel"
365                fi
366
367                config_get vif_txpower "$vif" txpower
368                # use vif_txpower (from wifi-iface) to override txpower (from
369                # wifi-device) if the latter doesn't exist
370                txpower="${txpower:-$vif_txpower}"
371                [ -z "$txpower" ] || iw dev "$ifname" set txpower fixed "${txpower%%.*}00"
372        done
373
374        local start_hostapd=
375        rm -f /var/run/hostapd-$phy.conf
376        for vif in $vifs; do
377                config_get mode "$vif" mode
378                [ "$mode" = "ap" ] || continue
379                mac80211_hostapd_setup_bss "$phy" "$vif"
380                start_hostapd=1
381        done
382
383        [ -n "$start_hostapd" ] && {
384                hostapd -P /var/run/wifi-$phy.pid -B /var/run/hostapd-$phy.conf || {
385                        echo "Failed to start hostapd for $phy"
386                        return
387                }
388                sleep 2
389
390                for vif in $vifs; do
391                        config_get mode "$vif" mode
392                        config_get ifname "$vif" ifname
393                        [ "$mode" = "ap" ] || continue
394                        hostapd_ctrl="${hostapd_ctrl:-/var/run/hostapd-$phy/$ifname}"
395                        mac80211_start_vif "$vif" "$ifname"
396                done
397        }
398
399        for vif in $vifs; do
400                config_get mode "$vif" mode
401                config_get ifname "$vif" ifname
402                [ ! "$mode" = "ap" ] || continue
403                ifconfig "$ifname" up
404
405                if [ ! "$mode" = "ap" ]; then
406                        ifconfig "$ifname" up
407                        case "$mode" in
408                                adhoc)
409                                        config_get bssid "$vif" bssid
410                                        config_get ssid "$vif" ssid
411                                        config_get beacon_int "$device" beacon_int
412                                        config_get basic_rate_list "$device" basic_rate
413                                        config_get encryption "$vif" encryption
414                                        config_get key "$vif" key 1
415                                        config_get mcast_rate "$vif" mcast_rate
416
417                                        local keyspec=""
418                                        [ "$encryption" == "wep" ] && {
419                                                case "$key" in
420                                                        [1234])
421                                                                local idx
422                                                                for idx in 1 2 3 4; do
423                                                                        local ikey
424                                                                        config_get ikey "$vif" "key$idx"
425
426                                                                        [ -n "$ikey" ] && {
427                                                                                ikey="$(($idx - 1)):$(prepare_key_wep "$ikey")"
428                                                                                [ $idx -eq $key ] && ikey="d:$ikey"
429                                                                                append keyspec "$ikey"
430                                                                        }
431                                                                done
432                                                        ;;
433                                                        *) append keyspec "d:0:$(prepare_key_wep "$key")" ;;
434                                                esac
435                                        }
436
437                                        local br brval brsub brstr
438                                        [ -n "$basic_rate_list" ] && {
439                                                for br in $basic_rate_list; do
440                                                        brval="$(($br / 1000))"
441                                                        brsub="$((($br / 100) % 10))"
442                                                        [ "$brsub" -gt 0 ] && brval="$brval.$brsub"
443                                                        [ -n "$brstr" ] && brstr="$brstr,"
444                                                        brstr="$brstr$brval"
445                                                done
446                                        }
447
448                                        local mcval=""
449                                        [ -n "$mcast_rate" ] && {
450                                                mcval="$(($mcast_rate / 1000))"
451                                                mcsub="$(( ($mcast_rate / 100) % 10 ))"
452                                                [ "$mcsub" -gt 0 ] && mcval="$mcval.$mcsub"
453                                        }
454
455                                        iw dev "$ifname" ibss join "$ssid" $freq \
456                                                ${fixed:+fixed-freq} $bssid \
457                                                ${beacon_int:+beacon-interval $beacon_int} \
458                                                ${brstr:+basic-rates $brstr} \
459                                                ${mcval:+mcast-rate $mcval} \
460                                                ${keyspec:+keys $keyspec}
461                                ;;
462                                sta)
463                                        if eval "type wpa_supplicant_setup_vif" 2>/dev/null >/dev/null; then
464                                                wpa_supplicant_setup_vif "$vif" nl80211 "${hostapd_ctrl:+-H $hostapd_ctrl}" || {
465                                                        echo "enable_mac80211($device): Failed to set up wpa_supplicant for interface $ifname" >&2
466                                                        # make sure this wifi interface won't accidentally stay open without encryption
467                                                        ifconfig "$ifname" down
468                                                        continue
469                                                }
470                                        fi
471                                ;;
472                        esac
473                        mac80211_start_vif "$vif" "$ifname"
474                fi
475        done
476
477}
478
479
480check_device() {
481        config_get phy "$1" phy
482        [ -z "$phy" ] && {
483                find_mac80211_phy "$1" >/dev/null || return 0
484                config_get phy "$1" phy
485        }
486        [ "$phy" = "$dev" ] && found=1
487}
488
489detect_mac80211() {
490        devidx=0
491        config_load wireless
492        while :; do
493                config_get type "radio$devidx" type
494                [ -n "$type" ] || break
495                devidx=$(($devidx + 1))
496        done
497        for dev in $(ls /sys/class/ieee80211); do
498                found=0
499                config_foreach check_device wifi-device
500                [ "$found" -gt 0 ] && continue
501
502                mode_11n=""
503                mode_band="g"
504                channel="11"
505                ht_cap=0
506                for cap in $(iw phy "$dev" info | grep 'Capabilities:' | cut -d: -f2); do
507                        ht_cap="$(($ht_cap | $cap))"
508                done
509                ht_capab="";
510                [ "$ht_cap" -gt 0 ] && {
511                        mode_11n="n"
512                        append ht_capab "       option htmode   HT20" "$N"
513
514                        list="  list ht_capab"
515                        [ "$(($ht_cap & 1))" -eq 1 ] && append ht_capab "$list  LDPC" "$N"
516                        [ "$(($ht_cap & 16))" -eq 16 ] && append ht_capab "$list        GF" "$N"
517                        [ "$(($ht_cap & 32))" -eq 32 ] && append ht_capab "$list        SHORT-GI-20" "$N"
518                        [ "$(($ht_cap & 64))" -eq 64 ] && append ht_capab "$list        SHORT-GI-40" "$N"
519                        [ "$(($ht_cap & 128))" -eq 128 ] && append ht_capab "$list      TX-STBC" "$N"
520                        [ "$(($ht_cap & 768))" -eq 256 ] && append ht_capab "$list      RX-STBC1" "$N"
521                        [ "$(($ht_cap & 768))" -eq 512 ] && append ht_capab "$list      RX-STBC12" "$N"
522                        [ "$(($ht_cap & 768))" -eq 768 ] && append ht_capab "$list      RX-STBC123" "$N"
523                        [ "$(($ht_cap & 4096))" -eq 4096 ] && append ht_capab "$list    DSSS_CCK-40" "$N"
524                }
525                iw phy "$dev" info | grep -q '2412 MHz' || { mode_band="a"; channel="36"; }
526
527                cat <<EOF
528config wifi-device  radio$devidx
529        option type     mac80211
530        option channel  ${channel}
531        option macaddr  $(cat /sys/class/ieee80211/${dev}/macaddress)
532        option hwmode   11${mode_11n}${mode_band}
533$ht_capab
534        # REMOVE THIS LINE TO ENABLE WIFI:
535        option disabled 1
536
537config wifi-iface
538        option device   radio$devidx
539        option network  lan
540        option mode     ap
541        option ssid     OpenWrt
542        option encryption none
543
544EOF
545        devidx=$(($devidx + 1))
546        done
547}
548
Note: See TracBrowser for help on using the repository browser.