summaryrefslogtreecommitdiffstats
path: root/src/8021x
blob: 0c3a8c283867195e44bb437c27f0b144bc2d1b85 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
WPA_CLI="wpa_cli -p /run/wpa_supplicant"

# Uses wpa_supplicant to check for association to a network
# wpa_check interface [timeout]
wpa_check()
{
    local timeout=0 INTERFACE="$1" TIMEOUT="${2:-15}" CONDITION="${3:-COMPLETED}"
    # CONDITION is required as wired connections are ready at ASSOCIATED not COMPLETED FS#20150

    while [[ $timeout -lt "$TIMEOUT" ]]; do
        ( # Sometimes wpa_supplicant isn't ready so silence errors for 2s only to avoid hiding real errors
        if [[ $timeout -lt 2 ]]; then
            eval $($WPA_CLI -i "$INTERFACE" status 2> /dev/null | fgrep "wpa_state=")
        else
            eval $($WPA_CLI -i "$INTERFACE" status | fgrep "wpa_state=")
        fi
        [[ "$wpa_state" = "$CONDITION" ]]
        ) && return 0
        sleep 1
        let timeout++
    done
    echo "$wpa_state"
    # wpa_cli -i "$INTERFACE" terminate >/dev/null 2>&1   # callers sometimes called stop_wpa, which does more but seems redundant
                                                        # termination should either be handled properly here, or by callers
    stop_wpa "$INTERFACE"
    return 1
}

start_wpa()
{
    local INTERFACE="$1" WPA_CONF="$2" WPA_DRIVER="$3"
    shift 3
    local WPA_OPTS="$*"

    wpa_supplicant -B -P "/run/wpa_supplicant_${INTERFACE}.pid" -i "$INTERFACE" -D "$WPA_DRIVER" -c "$WPA_CONF" $WPA_OPTS
    sleep 1

    if [[ ! -f "/run/wpa_supplicant_${INTERFACE}.pid" ]]; then
        return 1
    fi
}

stop_wpa()
{
    $WPA_CLI -i "$1" terminate &> /dev/null
    sleep 1         # JP: need this else the file tends to disappear after [[ -f ... ]] but before cat...
                    # see <http://bbs.archlinux.org/viewtopic.php?pid=515667#p515667>
    if [[ -f "/run/wpa_supplicant_$1.pid" ]]; then
        kill "$(cat "/run/wpa_supplicant_$1.pid")" &>/dev/null &
    fi
}

# Return a filename containing a list of network APs and ESSIDs found (sorted by decreasing signal strength)
# list_networks interface
list_networks() {
    wpa_supplicant_scan_info "$1" 1,5
}

wpa_supplicant_scan_info() {
    local INTERFACE="$1" fields="$2" essids
    # temp file used, as keeping ESSID's with spaces in their name in arrays
    # is hard, obscure and kinda nasty. This is simpler and clearer.

    [[ -z "$INTERFACE" ]] && return 1
    essids=$(mktemp --tmpdir essid.XXXXXXXX)

    wpa_supplicant -B -i"$INTERFACE" -Dnl80211,wext -C/run/wpa_supplicant -P/run/wpa_supplicant.pid || return 1
    $WPA_CLI -i "$INTERFACE" scan &> /dev/null
    sleep 2.5
    $WPA_CLI -i "$INTERFACE" scan_results |
        grep -v "^Selected" |
        grep -v "^bssid" |
        sort -rn -k3 |
        sort -u -k5 |
        sort -rn -k3 |
        cut -f"$fields"  > "$essids"

    # Fields are tab delimited
    # Remove extraneous output from wpa_cli
    # Sort by strength
    # Remove duplicates
    # Re-sort by strength as the removal disorders the list
    # Cut to the AP/essid fields only

    kill "$(cat /run/wpa_supplicant.pid)"

    # File of 0 length, ie. no ssid's.
    if [[ ! -s "$essids" ]]; then
        rm -f "$essids"
        return 1
    fi

    echo $essids
    return 0
}

# Requires already loaded profile
make_wpa_config_file() {
    local interface=$1
    local WPA_CONF="${TMPDIR:-/tmp}/wpa.${interface}" # substitute spaces out

    # make empty tmp dir with correct permissions, rename it
    rm -rf "$WPA_CONF"
    mv -f "$(mktemp -d)" "$WPA_CONF" || return 1
    echo "ctrl_interface=/run/wpa_supplicant" >> "$WPA_CONF/wpa.conf"    # we know $WPA_CONF now has no spaces, but it may have other nasty chars, so still needs to be quoted
    echo "ctrl_interface_group=${WPA_GROUP:-wheel}" >> "$WPA_CONF/wpa.conf"
    [[ $WPA_COUNTRY ]] && echo "country=$WPA_COUNTRY" >> "$WPA_CONF/wpa.conf"
    [[ -n "$ADHOC" ]] && echo "ap_scan=2" >> "$WPA_CONF/wpa.conf"
    echo "$WPA_CONF/wpa.conf"
}

# Requires already loaded profile
make_wpa_config() {
    case $SECURITY in
    wep|wep-old|wpa|none|none-old)
        echo "ssid=\"$ESSID\""
        if [[ -n "$AP" ]]; then
            echo "bssid=$AP"
        fi
        [[ -n "$ADHOC" ]] && echo "mode=1"
        ;;
    wpa-configsection)
        echo "$CONFIGSECTION"
        ;;
    *)
        return 1
        ;;
    esac

    # Key management
    case $SECURITY in
    wep|wep-old)
        echo "key_mgmt=NONE"
        echo "wep_tx_idx=0"
        if [[ ${KEY:0:2} == "s:" ]]; then # TODO: does wpa_supplicant handle this as expected?
            echo "wep_key0=\"${KEY:2}\""
        else
            echo "wep_key0=$KEY"
        fi
        ;;
    none|none-old)
        echo "key_mgmt=NONE"
        ;;
    wpa)
        if [[ "${#KEY}" -eq 64 ]]; then
            echo "proto=RSN WPA\npsk=$KEY"
        else
            echo "proto=RSN WPA\npsk=\"$KEY\""
        fi
        ;;
    esac

    # Hidden SSID
    if checkyesno ${HIDDEN:-no}; then
      echo "scan_ssid=1"
    fi
}

# vim: ft=sh ts=4 et sw=4: