2014年7月9日 星期三

OpenWrt boot

OpenWrt 的開機可以分成 bootloader、kernel、preinit、init 階段。

bootloader 階段

  • 硬體初始化及測試
  • 載入 kernel image:Downloading Kernel Image and Initial Ram Disk: 從 flash 或網路載入到記憶體, 需要時作解壓縮。
  • 設定 Linux kernel 需要的開機參數。
  • 跳到 Kernel Entry Point,控制權轉移到 Linux kernel。

kernel 階段

一般 Linux 電腦開機在 kernel 階段最後會去執行 /sbin/init,而 OpenWrt 是去執行 /etc/preinit,進入 preinit 階段。

preinit 階段

/etc/preinit 是 shell script,會載入 /lib/preinit 下更多的 shell script 依序執行,最後掛載根目錄後會去執行 busybox 提供的 /sbin/init,進入 init 階段。

init 階段

/sbin/init 執行哪些程式,由 /etc/inittab 決定。/etc/inittab 有四的欄位,格式是 tty:runlevel;action:command,其中 tty 是 optional,runlevel 沒用到,action 決定執行順序及時機,command 是執行的指令。init 依據 action,依序執行 sysinit → wait → once 的指令,然後進入無窮迴圈執行不斷重新執行 respawn 跟 askfirst 的指令。askfirst 跟 respawn 的差別只是多了等候連接的 tty 按 Enter。但在 NOMMU 處理器無法等候,所以兩者是一樣的。除了上述所提 action 外,還有其它 action:ctrlaltdel (SIGINT 時執行)、shutdown (SIGUSR1, SIGTERM, SIGUSR2 時執行) 跟 restart (SIGQUIT 時執行)。ctrlaltdel 通常設成執行重開機,restart 會重開機,而 shutdown 可能重開機或者關閉電源。

OpenWrt 的 inittab 依處理器或板子不同而有所不同,基本上大概的樣子是
::sysinit:/etc/init.d/rcS S boot
::shutdown:/etc/init.d/rcS K shutdown
ttyS0::askfirst:/bin/ash --login
tty1::askfirst:/bin/ash --login

所以開機時執行 /etc/init.d/rcS S boot,也就是依序執行 /etc/rc.d/ 下,所有 S 開頭的程式裡的 boot() 功能。/etc/rc.d/ 下的程式是連結到 /etc/init.d/ 下的命令檔,這些命令檔大多會帶入 /etc/rc.common,提供預設的動作函數,boot() 預設是執行 start()。也會帶入 /lib/functions.sh (一些共同的函數,包括 config_ 開頭的函數)、/lib/config/uci.sh (uci_ 開頭存取 uci 的函數)、及 /lib/functions/service.sh (使用 busybox start-stop-daemon 提供 service_ 開頭的函數)。

第一個執行的 rc.d 程式通常是 boot,再來可能是 sysctl、ubus、firewall、network

設定

OpenWrt 的設定用 UCI,並提供標準的命令檔函數以便於存取,放在 /etc/functions.sh (也就是 /lib/functions.sh)。

. /etc/functions.sh #載入

config_load config_file # 載入設定檔

如果要特別的回呼,要在 config_load 之前設好 config_cb() 或 option_cb()。config_cb() 每遇到一個新 section 或設定檔載入完畢時呼叫,有兩個參數 -- section type 跟 section name。option_cb() 每個 option 或 list 時呼叫,一樣有兩個參數 -- option name 跟 option value。config_cb() 裡可以修改 option_cb(),讓每個 section 可以有不同的 option_cb()。變數 CONFIG_SECTION 紀錄目前 section 的 ID。

以下對記憶體處理:
  • config_foreach function-called [section-name [function-args ...]]
    • 補充 function-called 的參數
  • config_get variable-stored section-id option-name [default-value]
  • config_set section-id option-name value
  • config_list_foreach section-id  list-name function-called [function-args...]
    • 補充 function-called 的參數
  • config_get_bool:跟 config_get 一樣,多了把 on, true, enabled 取得為 1
參考:http://wiki.openwrt.org/doc/devel/config-scripting

Wi-Fi 啟用

Wi-Fi 預設的設定檔是 /etc/config/wireless。/sbin/wifi 啟用 Wi-Fi,有 detect、up、跟 down 三種動作。在開機 init 階段的 boot 時執行 /sbin/wifi detect,產生設定檔;network 時的 start() 最後執行 /sbin/wifi down 跟 /sbin/wifi up 動作來啟用 Wi-Fi。

/sbin/wifi 整理:
  • 三種動作
    • detect:偵測 Wi-Fi,產生 /etc/config/wireless
    • down:停用 Wi-Fi
    • up (沒指定或其它):啟用 Wi-Fi
  • 載入共用函數 /lib/functions.sh。
  • 載入 /lib/wifi/ 下所有的 .sh:每個 .sh 檔是跟 Wi-Fi 驅動程式搭配,會附加 driver 名稱到 DRIVERS 變數,讓 /sbin/wifi 知道有什麼 driver,並提供 detect_driver()、scan_driver()、disable_driver()、enable_driver() 函數,為完成上述三種動作所需要。
  • 執行 scan_wifi 來載入設定檔。設定檔有一些 type 為 wifi-device 跟 wifi-iface 的 section,一個 wifi-device 可以有多個 wifi-iface。載入過程中,會將 wifi-device 的 section-name 附加到 DEVICES 變數,並把其對應的 wifi-iface 的 section-name 設到 wifi-device 的 vifs 選項,以便後續利用
  • 最後依動作執行對應的函數。
  • 提供的函數
    • find_net_config()
    • bridge_interface()
    • prepare_key_wep()
    • wifi_fix_hwmode()
    • wifi_updown:動作 up 或 down 時執行
      • down → wifi_updown disable→對每個 DEVICES 的 type,也就是 driver 名稱,執行 scan_driver() 跟 disable_driver()
      • up (沒指定或其它)→wifi_updown enable→會先執行 wifi_updown disable,並重新 scan_wifi。如果設定不是 disabled,執行 scan_driver() 跟 enable_driver()
    • wifi_detect:動作 detect 執行的函數, 對每個 DRIVERS 執行 detect_driver(),產生設定檔。最終設定檔會存到 /etc/config/wireless
    • start_net ifname network vifmac:啟用界面,將網路界面 ifname 連到 network 網域。vifmac 作用待研究。
    • set_wifi_up()
    • set_wifi_down
    • scan_wifi
  • 執行 scan_wifi 來載入預設的 Wi-Fi 設定檔
/ib/wifi/*.sh 整理
  • 附加 driver 名稱到 DRIVERS 變數,讓 /sbin/wifi 知道有什麼 driver
  • 提供的函數
    • detect_driver():只有 detect 動作用到,偵測 Wi-Fi 界面,輸出設定檔
    • scan_driver():up 跟 down 動作都會用到,掃描 wifi-iface 的 mode,設定 ifname。wifi-device 設 phy 及重設 vifs
    • enable_driver():
    • disable_driver():
/etc/config/wireless 範例:
config wifi-device radio0 # section name 給 wifi-iface 的 device 選項對應用
        option type     driver # driver 名稱,對應函數 detect_driver(), scan_driver(), enable_driver(), disable_driver()
        option channel  11
        option disabled 1 # 非必要,是否 disabled

config wifi-iface
        option device   radio0 # 對應到 wifi-device
        option mode   ap # 運作模式
        option network  lan # 搭到哪個網域使用
        option ssid     SSID
        option encryption none
完整的 wireless 設定參考 http://wiki.openwrt.org/doc/uci/wireless

參考來源

busybox init/init.c

沒有留言:

張貼留言

SIP header Via

所有 SIP 訊息 都要有 Via,縮寫 v。一開始的 UAC 和後續途經的每個 proxy 都會疊加一個 Via 放傳送的位址,依序作為回應的路徑。 格式 sent-protocol sent-by [ ;branch= branch ][ ; 參數 ...] s...