Table of Contents

Flashing La Fonera

In questa pagina trovate i miei appunti generici per aggiornare le immagini flash (il firmware) e in particolare per installare OpenWrt. Altri documenti migliori di questo:

La Fonera bricked

Si è deciso di installare OpenWrt perché la Fonera si è danneggiata e non si avvia più (in gergo: bricked). Il danno è accaduto installando e poi rimuovendo un pacchetto con ipkg (per la precisione il pacchetto gpsd): si è avuto un segmentation fault e da quel momento la Fonera non si è più riavviata. Dalla console seriale il boot si blocca con questi messaggi:

mini_fo_lookup: ERROR, meta data corruption detected.
mini_fo_d_delete: negative dentry passed.
mini_fo_d_release: no private data.

Tipi di filesystem

squashfs Squashfs is a readonly filesystem, OpenWrt boots from this one.
jffs2 For writable support, OpenWrt creates a jffs2 partition and on bootup swaps to the jffs2 root.

Un filesystem di tipo JFFS2 generalmente viene montato da un device MTD, per montarlo da un file immagine si può usare questa procedura (Linux kernel 2.6):

# Associate a loop device with the regular file:
modprobe loop; sleep 1
losetup /dev/loop0 /path/mtdblock2.jffs2
 
# Load the MTD support and the emulation using a block device:
modprobe mtdblock
modprobe block2mtd block2mtd=/dev/loop0,256; sleep 1
 
# Load the filesystem support and mount it:
modprobe jffs2
mount -t jffs2 /dev/mtdblock0 /mnt

FIXME I was unable to mount the jffs image (rootfs1) downloaded from the Fonera, may be for an endianess problem? Check the jffs2dump command with a syntax like this:

jffs2dump -l -c -e <rootfs.jffs2.be> <rootfs.jffs2>
Magic bitmask is backwards at offset 0x00560000. Wrong endian filesystem?

The following code will undo the previous setup:

umount /mnt
modprobe -r jffs2
modprobe -r block2mtd
modprobe -r mtdblock
losetup --detach /dev/loop0
modprobe -r loop

Backup delle immagini flash

Se la Fonera non è bricked ed è accessibile via ssh, possiamo fare una copia delle immagini flash esistenti:

root@OpenWrt:~# cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00030000 00010000 "RedBoot"
mtd1: 006f0000 00010000 "rootfs"
mtd2: 00570000 00010000 "rootfs1"
mtd3: 00010000 00010000 "config"
mtd4: 000b0000 00010000 "vmlinux.bin.l7"
mtd5: 0000f000 00010000 "FIS directory"
mtd6: 00001000 00010000 "RedBoot config"
mtd7: 00010000 00010000 "board_config"

Questo il contenuto di ciascuna immagine:

RedBoot mtd0
rootfs mtd1 Root filesystem di tipo squashfs (read-only, per failsafe boot?) (versione 0.7.1-1)
rootfs1 mtd2 Immagine principale del root filesystem, tipo jffs2 (versione 0.7.1-3)
config mtd3
vmlinux.bin.l7 mtd4 Immagine del kernel Linux
FIS directory mtd5
RedBoot config mtd6 Configurazione del boot manager RedBoot
board_config mtd7

Non si capisce bene il significato di rootfs e rootfs1. Dal prompt RedBoot è visibile solo un blocco di nome rootfs, che è quello che viene sovrascritto con l'immagine ufficiale squashfs durante l'operazione di flash.

Con questo comando lanciato dal PC possiamo salvare sul PC stesso un file con l'immagine che contiene il kernel:

ssh root@169.254.255.1 'dd if=/dev/mtdblock/4' > mtdblock4

FIXME L'immagine del rootfs1 (mtd2) ottenuta in questo modo non è adatta ad essere flashata come descritto in seguito! Con il seguente metodo si ottiene un file di 5.5M (di tipo data), mentre l'immagine rootfs distribuita da Fon è un file di 1.5M (di tipo Squashfs filesystem).

Flash di un'immagine ufficiale Fon

Questa procedura è stata sperimentata flashando un'immagine rootfs originale Fon (versione fonera_0.7.1.3.fon), per recuperare una Fonera bricked. Abbiamo flashato due file sulla Fonera: rootfs.squashfs e kernel.lzma

Il flashing è stato fatto operando dal prompt di RedBoot. In teoria dovrebbe essere possibile riscrivere la flash anche da riga di comando utilizzando il comando write di mtd, ma noi non ci siamo riusciti! Abbiamo riscritto sia l'mtd device rootfs che rootfs1: al reboot successivo abbiamo ritrovato la Fonera con il vecchio rootfs.

Iniziamo con rootfs.squashfs, si tratta di un Squashfs filesystem. Avviare La Fonera controllandola via seriale, interrompere la sequenza ed entrare al prompt RedBoot:

+PHY ID is 0022:5521
Ethernet eth0: MAC address 00:18:84:1e:61:98
IP: 169.254.255.1/255.255.0.0, Gateway: 0.0.0.0
Default server: 169.254.255.46

RedBoot(tm) bootstrap and debug environment [ROMRAM]
Non-certified release, version v1.3.0 - built 16:57:58, Aug  7 2006

Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.

Board: ap51
RAM: 0x80000000-0x81000000, [0x80040450-0x80fe1000] available
FLASH: 0xa8000000 - 0xa87f0000, 128 blocks of 0x00010000 bytes each.
== Executing boot script in 10.000 seconds - enter ^C to abort
^C
RedBoot>

Controlliamo le immagini presenti nella memoria flash (Fonera originale, versione 0.7.1-3):

RedBoot> fis list
Name              FLASH addr  Mem addr    Length      Entry point
RedBoot           0xA8000000  0xA8000000  0x00030000  0x00000000
rootfs            0xA8030000  0xA8030000  0x00700000  0x00000000
vmlinux.bin.l7    0xA8730000  0x80041000  0x000B0000  0x80041000
FIS directory     0xA87E0000  0xA87E0000  0x0000F000  0x00000000
RedBoot config    0xA87EF000  0xA87EF000  0x00001000  0x00000000

Se RedBoot non avesse già assegnato un indirizzo IP alla Ethernet lo si fa adesso, qui lo facciamo solo a scopo didattico, perché l'indirizzo è stato già assegnato come si vede dall'output sopra. Si carica quindi in RAM l'immagine del nuovo rootfs tramite protocollo tftp (bisogna configurare un PC con tftpd e condividere il file immagine):

RedBoot> ip_address -l 169.254.255.1/16 -h 169.254.255.46
IP: 169.254.255.1/255.255.0.0, Gateway: 0.0.0.0
Default server: 169.254.255.46
RedBoot> load -r -b %{FREEMEMLO} -m tftp -h 169.254.255.46 rootfs.squashfs
Raw file loaded 0x80040800-0x801c07ff, assumed entry at 0x80040800

I parametri specificati al comando load sono:

-r Indica che il file è raw data.
-b Indirizzo in RAM a cui caricare il file. Si usa un alias che rappresenta l'inizio della RAM libera.

Quindi si crea l'immagine nella memoria flash:

RedBoot> fis create rootfs -e 0
An image named 'rootfs' exists - continue (y/n)? y
... Erase from 0xa8030000-0xa8730000: ..........................................
... Program from 0x80040800-0x801c0800 at 0xa8030000: ........................
... Erase from 0xa87e0000-0xa87f0000: .
... Program from 0x80ff0000-0x81000000 at 0xa87e0000: .

Non abbiamo specificato né l'indirizzo di origine della memoria RAM (parametro -b) né l'indirizzo destinazione nella memoria flash (parametro -f) dei dati da scrivere. Come valori predefiniti sono stati presi rispettivamente l'indirizzo dell'ultimo file caricato (0x80040800) e l'indirizzo dell'immagine rootfs esistente (0xA8030000). È stato dato il parametro -e 0, perché per l'immagine rootfs non ha senso specificare un entry point. Vedere eventualmente la documentazione di RedBoot.

Controlliamo nuovamente le immagini esistenti:

RedBoot> fis list
Name              FLASH addr  Mem addr    Length      Entry point
RedBoot           0xA8000000  0xA8000000  0x00030000  0x00000000
rootfs            0xA8030000  0x80040800  0x00700000  0x00000000
vmlinux.bin.l7    0xA8730000  0x80041000  0x000B0000  0x80041000
FIS directory     0xA87E0000  0xA87E0000  0x0000F000  0x00000000
RedBoot config    0xA87EF000  0xA87EF000  0x00001000  0x00000000

Si esegue operazione analoga per caricare l'immagine del kernel kernel.lzma:

RedBoot> load -r -v -b 0x80041000 -m tftp -h 169.254.255.46 kernel.lzma
Raw file loaded 0x80041000-0x800c0fff, assumed entry at 0x80041000
RedBoot> fis create -r 0x80041000 -e 0x80041000 vmlinux.bin.l7
An image named 'vmlinux.bin.l7' exists - continue (y/n)? y
... Erase from 0xa8730000-0xa87e0000: ...........
... Program from 0x80041000-0x800c1000 at 0xa8730000: ........
... Erase from 0xa87e0000-0xa87f0000: .
... Program from 0x80ff0000-0x81000000 at 0xa87e0000: .

In questo caso si è indicato il base address per il caricamento in ram (-b). Nel creare la nuova immagine si è indicato l'indirizzo di rilocazione (-r) e l'entry point (-e) rispettando lo schema originale.

Per riavviare:

RedBoot> reset

OpenWrt

Sulla Fonera si possono installare due versioni di OpenWrt: Kamikaze e Backfire, occorre il build per Atheros:

Compilazione

ATTENZIONE: Operazione da fare solo in casi particolari, la distribuzione binaria precompilata va più che bene.

OpenWrt Download

In una directory dedicata, si scarica da SVN il trunk di OpenWrt e tutti i pacchetti extra disponibili:

svn co https://svn.openwrt.org/openwrt/trunk/
svn co https://svn.openwrt.org/openwrt/packages

La compilazione di OpenWrt cerca i pacchetti nella directory trunk/package, quindi si creano dei link simbolici alle directory dei pacchetti extra:

cd trunk/package
ln -sv ../../packages/*/* .
cd ../..

OpenWrt Configure

cd trunk
make menuconfig
Target System (Atheros [2.6])  --->
Base System --->
  <*> busybox
    Configuration  --->
      Networking Utilities  --->
        [*] arp
        [*] ether-wake
        [*] hostname
Network  --->
  <*> vtun
  <*> wget
  <*> wol
  <*> wpa-supplicant
  <*>   wpa-cli
...
...

La configurazione viene salvata nel file .config.

OpenWrt Compile

cd trunk
make

Al termine della compilazione le immagini e i pacchetti *.ipk si trovano nella directory trunk/bin.

L'immagine del root filesystem viene create in alcune varianti:

squashfs The firmwares with squashfs in the filename use a combination of a readonly squashfs partition and a writable jffs2 partition. This gives you a /rom with all the files that shipped with the firmware and a writable root containing symlinks to /rom. This is considered the standard install.
jffs2 The firmwares with jffs2 in the name are jffs2 only; all of the files are fully writable.
64k, 128k, … Most 4M flash chips use a block size of 64k while most 8M chips tend to use a 128k block size. The jffs2 partition needs to be formatted for the correct block size.

Flash dell'immagine OpenWrt Backfire

Qui le istruzioni ufficiali: http://wiki.openwrt.org/toh/fon/fonera.

Scaricati i file openwrt-atheros-vmlinux.lzma e openwrt-atheros-root.squashfs dal repository e resi disponibili sul server tftp all'indirizzo IP 169.254.255.46.

Avviata La Fonera e raggiunto il prompt RedBoot dalla console seriale, con fis list si possono vedere le immagini caricate in flash:

RedBoot> fis list
Name              FLASH addr  Mem addr    Length      Entry point
RedBoot           0xA8000000  0xA8000000  0x00030000  0x00000000
rootfs            0xA8030000  0xA8030000  0x00700000  0x00000000
vmlinux.bin.l7    0xA8730000  0x80041000  0x000B0000  0x80041000
FIS directory     0xA87E0000  0xA87E0000  0x0000F000  0x00000000
RedBoot config    0xA87EF000  0xA87EF000  0x00001000  0x00000000

Si carica in RAM l'immagine del kernel via tftp, quindi si copia in flash memory specificando a che indirizzo dovrà essere caricata in RAM (-r) e specificando anche l'entry point (-e) a cui iniziare l'esecuzione (si mantengono gli stessi valori del kernel Fon):

RedBoot> ip_address -h 169.254.255.46 -l 169.254.255.1/24
IP: 169.254.255.1/255.255.255.0, Gateway: 0.0.0.0
Default server: 169.254.255.46

RedBoot> load -r -b %{FREEMEMLO} openwrt-atheros-vmlinux.lzma
Using default protocol (TFTP)
Raw file loaded 0x80040800-0x801207ff, assumed entry at 0x80040800

RedBoot> fis init
About to initialize [format] FLASH image system - continue (y/n)? y
*** Initialize FLASH Image System
... Erase from 0xa87e0000-0xa87f0000: .
... Program from 0x80ff0000-0x81000000 at 0xa87e0000: .

RedBoot> fis create -e 0x80041000 -r 0x80041000 vmlinux.bin.l7
... Erase from 0xa8030000-0xa8110000: ..............
... Program from 0x80040800-0x80120800 at 0xa8030000: ..............
... Erase from 0xa87e0000-0xa87f0000: .
... Program from 0x80ff0000-0x81000000 at 0xa87e0000: .

Si carica in RAM via ftp l'immagine del root filesystem (nella posizione più bassa della RAM, variabile FREEMEMLO) e si copia in flash alla prima posizione libera:

RedBoot> load -r -b %{FREEMEMLO} openwrt-atheros-root.squashfs
Using default protocol (TFTP)
Raw file loaded 0x80040800-0x802207ff, assumed entry at 0x80040800

RedBoot> fis create rootfs
... Erase from 0xa8110000-0xa82f0000: ..............................
... Program from 0x80040800-0x80220800 at 0xa8110000: ..............................
... Erase from 0xa87e0000-0xa87f0000: .
... Program from 0x80ff0000-0x81000000 at 0xa87e0000: .

Si verifica la configurazione di boot, per sicurezza la si riscrive:

RedBoot> fconfig -l -n
boot_script: true
boot_script_data: 
.. fis load -l vmlinux.bin.l7
.. exec

boot_script_timeout: 1
bootp: false
bootp_my_gateway_ip: 0.0.0.0
bootp_my_ip: 0.0.0.0
bootp_my_ip_mask: 255.255.255.255
bootp_server_ip: 0.0.0.0
console_baud_rate: 9600
gdb_port: 9000
info_console_force: false
net_debug: false

RedBoot> fconfig boot_script_data
boot_script_data: 
.. fis load -l vmlinux.bin.l7
.. exec
Enter script, terminate with empty line
>> fis load -l vmlinux.bin.l7
>> exec
>> 
Update RedBoot non-volatile configuration - continue (y/n)? y
... Erase from 0xa87e0000-0xa87f0000: .
... Program from 0x80ff0000-0x81000000 at 0xa87e0000: .

Infine si riavvia:

RedBoot> reset

OpenWrt Backfire installa l'interfaccia web LuCI e un telenet con accesso root senza password, l'indirizzo di rete predefinito è 192.168.1.1. Una volta impostata una password per l'utente root il telenet viene disabilitato e al suo posto viene abilitato l'ssh.

Configurare OpenWrt

/etc/config/network

Configurazione Ethernet via DHCP:

config interface wan
        option ifname   eth0.1
        option proto    dhcp
        option hostname MyRouter

Configurazione Ethernet statica:

config interface lan
        option ifname   eth0.0
        option proto    static
        option ipaddr   192.168.1.2
        option netmask  255.255.255.0
        option gateway  192.168.1.1
        option dns      192.168.1.1

Dopo aver modificato la configurazione dovrebbe bastare dare il comando:

/sbin/ifup lan

/etc/config/wireless

Per attivare l'interfaccia wireless bisogna mettere nel file di configurazione due sezioni. Una sezione wifi-device con la configurazione della radio, il cui risultato è l'attivazione dell'interfaccia wifi0. Una seconda sezione di nome wifi-iface con la configurazione dell'interfaccia di rete vera e propria (quella effettivamente usata con il TCP/IP ecc.), il cui risultato è l'attivazione dell'interfaccia ath0:

config wifi-device  wifi0
        option type     atheros
        option channel  5
#       option diversity 1
#       option txantenna 0
#       option rxantenna 0
#       option distance  2000
# disable radio to prevent an open ap after reflashing:
        option disabled 0

config wifi-iface
        option device   wifi0
        option network  lan
# Mode is "ap" (master access point), "sta" (station, managed client):
        option mode     sta
        option ssid     OpenWrt
        option hidden   0
#       option txpower  15
#       option bgscan   enable
        option encryption none

Un esempio per associarsi come client ad un access point con crittografia wep:

config wifi-iface
        option device      wifi0
        option network     wan
        option mode        sta
        option ssid        MyEssid
        option encryption  wep
        option key         's:supersecret01'

Per creare una nuova interfaccia wireless ath1 (ovviamente basata sullo stesso hardware wifi0) si aggiunge un'altra sezione config wifi-iface. Non è possibile avere due interfacce contemporaneamente in modalità managed.

Un altro comando per creare interfacce wlan:

wlanconfig ath1 create wlandev wifi0 wlanmode monitor

Per applicare la nuova configurazione wireless:

/sbin/wifi down
/sbin/wifi up

/etc/init.d/

Per avviare e formare i servizi ci sono gli script in /etc/init.d/. Oltre ai classici start e stop dovrebbero essere supportate anche le opzioni enable e disable per abilitare o meno l'avvio automatico del servizio al bootstrap.

Attivare un servizio al bootstrap generalmente significa creare l'opportuno link simbolico in /etc/rc.d/.

/etc/config/firewall e /etc/firewall.user

Nel file /etc/config/firewall si scrive la configurazione con una sintassi semplificata, ad esempio:

accept:proto=tcp dport=22

Altre istruzioni iptables vanno invece in /etc/firewall.user. Rispetto ad una configurazione vanilla si può approfittare di alcune catene predefinite:

Come configurazione predefinita vengono accettate tutte le connessioni RELATED, ESTABLISHED e il traffico icmp. Vedere per maggiori dettagli /etc/init.d/firewall.

## Allow full forwarding
iptables -A forwarding_rule -i eth0 -o ath0 -j ACCEPT
## Allow masquerading
iptables -t nat -A postrouting_rule -s 192.168.1.0/24 -o ath0 -j MASQUERADE