summaryrefslogtreecommitdiffstats
path: root/src/wireless.subr
blob: fb81ff53f6a4fff189088f18fecac78bd4315325 (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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#! /bin/bash

# Uses wpa_supplicant to check for association to a network
# wpa_check interface [timeout]
wpa_check()
{
    INTERFACE=$1; TIMEOUT=$2
    
    [[ -z "$TIMEOUT" ]] && TIMEOUT=15
    let timeout=0
    while [[ $timeout -ne $TIMEOUT ]]; do
        eval `wpa_cli status|grep wpa_state` 
        [[ "$wpa_state" = "COMPLETED" ]] && return 0
        sleep 1
        let timeout++
    done

    wpa_cli terminate >/dev/null 2>&1
    err_append "Wireless association failed."
    return 1 
}

# Uses wireless_tools, to check for association to a network.
# wep_check interface [timeout]
wep_check()
{
    INTERFACE=$1; TIMEOUT=$2
 
    [[ -z "$TIMEOUT" ]] && TIMEOUT=15
    let timeout=0
    while [[ $timeout -ne $TIMEOUT ]]; do
        bssid=`iwgetid $INTERFACE -ra`
        [[ ! "$bssid" = "00:00:00:00:00:00" ]] && return 0
        sleep 1
        let timeout++
    done
    
    err_append "Wireless association failed."
    return 1
}

# Check if a particular network is within range
# find_essid interface essid
find_essid()
{
    INTERFACE=$1; ESSID=$2; RETRIES=4
    try=0;
    while [[ $try -ne $RETRIES ]]; do
        if iwlist $INTERFACE scan|sed "s/ESSID://g"|grep -q "\"$ESSID\""; then
            return 0 # network found
        fi
        sleep 0.5
        let try++
    done
    return 1
}

# Return a filename containing a list of network ESSID's found.
# list_networks interface
list_networks()
{
    # 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 "$1" ]] && return 1
    essids=$(mktemp /tmp/essid.XXXXX)

    let try 0;
    while [[ $try -ne $RETRIES ]]; do        
        iwlist $1 scan 2> /dev/null|grep ESSID|sed 's/.*ESSID:"\([^"]\+\)".*/\1/' > $essids
        sleep 0.5; let try++
    done
    sort -u $essids -o $essids
  
    # File of 0 length, ie. no ssid's.
    if [[ ! -s $essids ]]; then
        return 1
    fi

    echo $essids
    return 0
}

start_wpa() 
{
    INTERFACE=$1; WPA_CONF=$2; WPA_OPTS=$3
     
    [[ "$WPA_OPTS" == "" ]] && WPA_OPTS="-Dwext"

    wpa_supplicant -wB -P/var/run/wpa_supplicant_${INTERFACE}.pid -i${INTERFACE} -c $WPA_CONF $WPA_OPTS    
    sleep 1
    
    if [[ ! -f /var/run/wpa_supplicant_${INTERFACE}.pid ]]; then
        err_append "wpa_supplicant did not start, possible configuration error"
        return 1
    fi
}

wireless_up() {

    load_profile $1
    
    if [[ ! -d /sys/class/net/$INTERFACE/wireless ]]; then 
        err_append "Interface $INTERFACE is not a wireless interface"
        return 1
    fi

    # Was required by broadcom
    # iwlist $INTERFACE scan &> /dev/null
  
    # Required by atheros to enable device
    ifconfig $INTERFACE up 

    # Required by ipw3945 to properly re-associate
    eval "iwconfig $INTERFACE mode managed essid \"$ESSID\""

    # Kill any lingering wpa_supplicants.
    if [[ -f /var/run/wpa_supplicant_$INTERFACE.pid ]]; then
        kill $(cat /var/run/wpa_supplicant_$INTERFACE.pid)
    fi
    
    if checkyesno $SCAN; then
        if ! find_essid $INTERFACE "$ESSID"; then
            err_append "Network unavailable"
            return 1
        fi 
    fi

    case $SECURITY in
    wep|none)
        # 'none' security uses iwconfig, like wep, so use same code, minus keysetting.
        # Use sane default if no alternative is specified
        if [[ "$SECURITY" = "wep" && "$WEP_OPTS" = "" ]]; then 
            WEP_OPTS="mode managed essid \"$ESSID\" key open $KEY"
        elif [[ "$SECURITY" = "none" && "$WEP_OPTS" = "" ]]; then
            WEP_OPTS="mode managed essid \"$ESSID\""
        fi 
        
        if ! eval iwconfig $INTERFACE $WEP_OPTS; then
            err_append "Could not set wireless configuration"
            return 1
        fi

        wep_check $INTERFACE $TIMEOUT|| return 1
        ;;    
    wpa)
        local WPA_CONF=`mktemp /tmp/wpa.XXXXXXXX`
        
        # Temporary bugfix for broken drivers... http://bbs.archlinux.org/viewtopic.php?id=36384
        if ! eval iwconfig $INTERFACE mode managed essid "\"$ESSID\""; then
            err_append "Could not set wireless configuration"
            return 1
        fi
        
        # Create a random file to store configuration, make it root only. 
        chmod 600 $WPA_CONF
        echo "ctrl_interface=/var/run/wpa_supplicant" >> $WPA_CONF
        echo "ctrl_interface_group=0" >> $WPA_CONF        
        
        # Generate configuration
        if ! wpa_passphrase "$ESSID" "$KEY" >> $WPA_CONF; then
            err_append "Configuration generation failed: `cat $WPA_CONF`"
            return 1
        fi

        # Connect!
        start_wpa $INTERFACE $WPA_CONF $WPA_OPTS || return 1
        wpa_check $INTERFACE $TIMEOUT || return 1
        ;;
    wpa-config)
        # If user hasnt defined one, use stock config.
        [[ -z "$WPA_CONF" ]] && WPA_CONF="/etc/wpa_supplicant.conf"
        start_wpa $INTERFACE $WPA_CONF $WPA_OPTS || return 1
        wpa_check $INTERFACE $TIMEOUT || return 1
        ;;        
    esac
    
    . $SUBR_DIR/ethernet.subr
    if ! ethernet_up $1; then
        wireless_down $1 YES
        return 1
    fi
}
 
wireless_down() {
    PROFILE=$1 NOETHERNETDOWN=$2
    if ! checkyesno $2; then
        . $SUBR_DIR/ethernet.subr
        ethernet_down $1
       fi
    wpa_cli terminate &> /dev/null 
    iwconfig $INTERFACE essid off key off &> /dev/null 
    ifconfig $INTERFACE down
}

wireless_clean_scope() {
    unset INTERFACE CONNECTION
    unset TIMEOUT WPA_CONF WPA_OPTS KEY ESSID SECURITY WEP_OPTS
    . $SUBR_DIR/ethernet.subr
    ethernet_clean_scope
}


# vim: set ts=4 et sw=4: