ShellScript
Bash
Linux
Network
RaspberryPi

スクリプトで無線LANにWi-Fi接続する -Linux編 (Raspberry Pi対応)-

More than 2 years have passed since last update.

Wi-Fiダイレクトで直接デバイスに無線接続するときに、いちいち/etc/network/interfacesをいじってifdown wlan0 && ifup wlan0とかしていた訳ですが、いかんせん面倒くさい。
そこで、SSIDとパスワードを指定するだけでお手軽に接続できるスクリプトを作りました。
Raspbian Wheezy、Ubuntu14.04で動作確認済みです。ちなみにMac編はこちらです。

wificonn_linux.sh
#!/bin/bash
set -u
export LANG="C"

function usage() {
  cat <<EOT
Usage: bash ${0##*/} <interface-name> <network-SSID> <password>
EOT
}

# 引数チェック
if [ $# -ne 3 ]; then usage && exit 1; fi

# 指定されたインターフェースが存在するか調べる
iwconfig $1 > /dev/null 2>&1
if [ $? -ne 0 ]; then
  echo "Device named '$1' not found."
  exit 2
fi

# すでに接続されていれば終了
iwconfig $1 | grep -wq "ESSID:\"$2\"" && ifconfig $1 | grep -q 'inet addr'
if [ $? -eq 0 ]; then
  echo "Already connected."
  exit 0
fi

# インターフェースを再起動
ifconfig $1 down
ifconfig $1 up
if [ $? -ne 0 ]; then
  echo "Failed to activate interface $1"
  exit 4
fi

# 指定のSSIDを持つアクセスポイントがあるか調べる
iwlist $1 scan | grep -wq "ESSID:\"$2\""
if [ $? -ne 0 ]; then
  echo "The wi-fi network with SSID:'$2' not found."
  exit 3
fi

# wpa_supplicantが動いていたら殺す
pkill -f "wpa_supplicant.+-i *$1 .*"

# SSIDを設定
iwconfig $1 essid $2

# WPA認証タイムアウト秒数
WPA_AUTH_TIMEOUT=20
is_connected=false
current_time=$(date +%s)
# wpa_supplicantをnohupで起動し接続。stdbufはバッファリングを防止するために必要
while read -t ${WPA_AUTH_TIMEOUT} line; do
  echo "  $line"
  echo $line | grep -wq 'CTRL-EVENT-CONNECTED'
  if [ $? -eq 0 ]; then
    is_connected=true
    break
  fi
  # タイムアウト判定
  if [ $(($(date +%s) - ${current_time})) -gt ${WPA_AUTH_TIMEOUT} ]; then
    echo "Timeout."
    break
  fi
done < <(nohup bash -c "wpa_passphrase $2 $3 | stdbuf -oL wpa_supplicant -i $1 -D wext -c /dev/stdin 2>&1 &")
if ! $is_connected; then
  echo 'WPA authentication failed.'
  pkill -f "wpa_supplicant.+-i *$1 .*"
  exit 5
fi

# IPアドレス割り当て
ifconfig $1 | grep -q 'inet addr'
if [ $? -ne 0 ]; then
  dhclient $1
  ifconfig $1 | grep -q 'inet addr'
  if [ $? -ne 0 ]; then
    echo 'IP address cannot not be assgined.'
    exit 6
  fi
fi

echo 'Connected successfully.'
exit 0

使いかた

$ bash wificonn_linux.sh <interface-name> <network-SSID> <password>
  • 実行にはルート権限が必要です。一般ユーザーはsudoしてください。
  • <interface-name>はwlan0, wlan1などのインターフェース名を指定します。インターフェース名はiwconfigで確認できます(老婆心)。
  • 生のパスワードを入力する必要があるので、共同のマシンでは注意してください。

一応解説

Debian系Linuxで無線LANの設定を行うときは、種々の解説サイトにもあるように

  1. wpa_passphraseの出力をリダイレクトし、PSKの暗号化と同時に設定ファイルを作成する
  2. /etc/network/interfaceswpa-conf <設定ファイルのパス>と書く

のが一般的です。こうしておくとwpa_supplicantが勝手に立ち上がり、設定ファイルを読み込んでよろしく認証を行ってくれます。今回は設定ファイルを使わないため、wpa_supplicantの設定ファイルを-c /dev/stdinとして標準入力に設定し、wpa_passphraseの出力をパイプで流しこむようにしました。

  • wpa_supplicantを起動させたらそのログ出力を一行ずつ読み込んで、OKっぽいログ(CTRL-EVENT-CONNECTED)が出ていたら成功とみなします。もっといい判定方法があるかも?
  • 一定時間以上経ってもダメならタイムアウトエラーにしています。環境によってはWPA_AUTH_TIMEOUTの値を調整する必要があるかもしれません。
  • stdbuf -oLはバッファリング動作を変更するコマンドで、wpa_supplicantが出力をバッファに貯めずに一行ずつ吐き出すようにしています。
  • IPアドレスはdhclientコマンドで動的に割り当てています。

バグや指摘などありましたら、ぜひコメント欄かTwitterの方までお願い致しますm(__)m