PCIのEthernetカードはMACアドレスがEEPROMに焼かれていますが、SOCでのEthernetサポートはMACアドレスはflashに保存されていてOSブート時にflashから読み出して設定するようになっています。
FreeBSDでのMACアドレスの設定は以下のような方法があります。
- hintsにMACアドレスを直接書く
- hintsにMACアドレスのFlashのアドレスを書く
- dtsにMACアドレスを直接書く
- dtsにMACアドレスのFlashのアドレスを書く
- ブートローダーから渡された値を使用
- rcでflashを読んで設定
- ドライバが乱数で生成
これらはEthernetドライバが対応している事が条件になります。大抵のドライバは設定が無い場合はデフォルトのMACアドレスがハードコードされています。
AtherosのSOCのInterfaceのargeはflashから読み込みコードが実装されています。これはcfiなflashな場合について、flashの指定アドレスから読み込みます。指定は以下のようにhintsでおこないます。
hint.arge.0.eeprommac=0xbfff120c
設定はcfiの中の相対アドレスではなく物理アドレスになります。この設定のターゲットは
cfi0 at mem 0xbe000000-0xbfffffff on nexus0
となっていて、flashの相対アドレスの0x1ff120cから読み出している事になります。
~~SPIなflashを使ったターゲットではこの仕組みは機能しません。~~と思ったのですが、SPIなflashでも中身がメモリにマップされて読めるSOCであればcfiと同じようにアクセスできるような気がします。
FON2201ではFlashの最後の64KにAtherosが規定したデータがありこの中にMACアドレスがあります。この構造はsys/dev/ath/ath_hal/ah_soc.hに定義があります。以下のようにこれを読んでrcで設定することができます。
# Import MAC addresses with known names
MAGIC=`dd if=/dev/flash/spi0 bs=0x10000 skip=0x7f count=1 2>/dev/null |
od -tx4 -N 4 | awk '/0000000/{print $2}'`
if [ ${MAGIC} = "35333131" ]; then
kenv WIFI_MAC_ADDR=`dd if=/dev/flash/spi0 bs=0x10000 skip=0x7f c
ount=1 2>/dev/null | od -t x1 | awk '/^0000140/{print $2":"$3":"$4":"$5":"$6":"$
7}'`
kenv LAN_MAC_ADDR=`dd if=/dev/flash/spi0 bs=0x10000 skip=0x7f co
unt=1 2>/dev/null | od -t x1 | awk '/^0000140/{print $8":"$9":"$10":"$11":"$12":
"$13}'`
ifconfig are0 ether `kenv LAN_MAC_ADDR`
fi
geom_redbootはこの領域をパティションにしないので、flash全体から読み出しています。ddを使っているのはodでスキップすると遅いからです。
以前はodのjオプションを使っていましたが、512単位以外のjオプションの指定ができなくなったので、使わないようにしました。
誤って一バイト目の上位ビットが立ったMACアドレスを設定してしまうと、パケットがブロードキャストとして扱われ通信できなくなるので注意が必要です。
RT1310のターゲットのBuffalo WZR2-G300NのFlashをダンプしてMACアドレスを探してみたのですが見つかりません。どうもこの機種はWIFIチップにEEPROMが付いていて、そこにMACアドレスが入っていて、それをEthernetでも使い回しているのではないかと考えられます。
RT1310のインターフェースのfvはdtsで設定できるようにしてあるので、この機能で設定してください。
&enet0 {
local-mac-address = [ 00 1a f1 01 1f 23 ];
};
RalinkのインターフェースのrtではカーネルオプションのUSE_GENERATED_MAC_ADDRESSで乱数でMACアドレスを生成する機能があります。
dev/usb/net/if_muge.cにも乱数でMACアドレスを生成する機能があるようです。
EtherチップのMACアドレスの設定方法は2種類あって、レジスタに放り込む方法とsetupframeというパケットに含めて送信する方法です。これはチップによって違ってて、areはレジスタに設定していてfvはsetupframeを使っています。
以下はu-bootの環境変数から拾い出すスクリプトです。
ENVPAT="/dev/flash/spi0s.u-boot-env"
kenvmac=`kenv -q LAN_MAC_ADDR`
if [ -z "$kenvmac" ]; then
ETHADDR=`strings ${ENVPAT} | grep "^ethaddr="`
if [ -n "$ETHADDR" ]; then
kenv LAN_MAC_ADDR=`echo ${ETHADDR} | awk -F"=" '{gsub("\"","",$2);print $2}'`
ifconfig rt0 ether `kenv LAN_MAC_ADDR`
fi
fi