2004年05月14日(金) [長年日記]
- 昨日の夜、家を囲うパイプがぐわーんとなってた。
- セキュリティホールmemo 見て手元の環境でOffice Update 実行してみたら KB833858 が出てきた。うーむ。
■ [unix][net] ioctl
プログラムがうまく動かないので、調べながらまとめてみる。対象はNetBSD 1.6。
ioctl へのパラメータ
manに
int ioctl(int d, unsigned long request, void *argp);
とある。d には操作対象と関連づいたファイルディスクリプタを、request には行いたい操作を表す定数を、argp には操作で利用するデータを指すポインタを指定する。
request の定義
ioctl で使える request を新たに追加したい場合は、sys/ioccom.h で定義されている _IO* マクロ達を使う。
#define _IO(g,n) argp を使わないとき #define _IOR(g,n,t) argp が入力パラメータのとき #define _IOW(g,n,t) argp が出力パラメータのとき #define _IOWR(g,n,t) argp が入出力パラメータのとき
g は request の種類(グループ)を表す8ビットの数値、n は そのグループ内で request を特定する8ビットの数値、t は argp の型。g は 'r' のように文字で表す風習のようだ。t のサイズは13ビットに収まる必要がありそう。書籍「詳解TCP/IP Vol.2 実装」の17.5節「fcntlシステムコールとioctlシステムコール」で request の構造を図解している。
request に対し sys/ioccom.h で定義されている IOCPARM_LEN、IOCBASECMD、IOCGROUPマクロを使うと、t のサイズ、request から t のサイズを除いたもの(何に使う?)、g をそれぞれ取り出せる。
soo_ioctl
ioctl のソースは見つけられなかった(あー、kern/sys_generic.c にある sys_ioctl がそうなのかな)。で、詳解TCP/IP17.5節にある別の図を見ると、ソケットに対する操作の場合は soo_ioctl が呼ばれるようだ。soo_ioctl は kern/sys_socket.c にある。
soo_ioctl は最後のところで
/* * Interface/routing/protocol specific ioctls: * interface and routing ioctls should have a * different entry since a socket's unnecessary */ if (IOCGROUP(cmd) == 'i') return (ifioctl(so, cmd, data, p)); if (IOCGROUP(cmd) == 'r') return (rtioctl(cmd, data, p)); return ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, (struct mbuf *)cmd, (struct mbuf *)data, (struct mbuf *)0, p));
となっている。だから、ioctl に渡された request のグループが 'i' なら ifioctl が呼ばれ、'r' なら rtioctl が呼ばれ、それ以外なら別の関数が呼ばれる。それぞれインタフェース、ルーティング、プロトコルに対する操作になるようだ。
ifioctl
おれが関係するのはグループ 'i' なので net/if.c にある ifioctl を見る。
ifioctl は巨大な switch 文から成る関数だ。はじめの方に
ifp = ifunit(ifr->ifr_name); if (ifp == 0) return (ENXIO);
という箇所がある。ifr は ioctl に渡された argp を struct ifreq * へキャストしたもの。ってことは、argp の型は何でもいいわけではなくて、ifr_name に相当するフィールドを持っている必要があることになる。net/if.h 内の struct ifreq のコメントに説明があった。
/* * Interface request structure used for socket * ioctl's. All interface ioctl's must have parameter * definitions which begin with ifr_name. The * remainder may be interface specific. */ struct ifreq { char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */ union {
request のグループが 'i' の場合は argp の型は IFNAMESIZ 個の char の配列で始まるものである必要があると。ここに操作対象のインタフェース名をセットする決まりなのだ。
ifioctl に戻って、上に引用したコードにある ifunit は、インタフェース名を渡すと対応する ifnet 構造体を返してくれる関数。どうやってマッピングしているかは追わないでおく。独自の request が指定された場合は巨大なswitch文のdefalut caseに行き着く。
default: if (so->so_proto == 0) return (EOPNOTSUPP); #if !defined(COMPAT_43) && !defined(COMPAT_LINUX) && !defined(COMPAT_SVR4) && !defined(LKM) error = ((*so->so_proto->pr_usrreq)(so, PRU_CONTROL, (struct mbuf *)cmd, (struct mbuf *)data, (struct mbuf *)ifp, p)); #else
(#if に入らない場合はちょっと複雑だけど、結局同じことをしているのだと思う。 )so は socket 構造体で、ioctl に指定された d に対応しているもの。so にセットされている関数が呼び出されている。これは soo_ioctl の最後で request のグループが 'i' でも 'r' でもなかった場合とほとんど同じだ。request のグループを 'i' にしておくと5番目のパラメータに ifnet 構造体が設定されるようになるわけね。
で、*so->so_proto->pr_usrreq というのはどのように決まるのか。と思ったけど、切りがないので終了。今知りたいことはもう分かった。
■ [fs] 1236位 時価総額8億6790万
仕事とファンタジーサッカーを繰り返す生活。9節は104fpで高ポイントだったが全体的にポイント高かったようで順位はあまり上がらず。小笠原とキャプテントゥーリオとリカルドが活躍、西部だけ失敗。トップとの差は85fp。
次節もまた7チームで構成。ジュビロの選手を使わないのは初めてかも。
GK | 高木 義成 | 東京V | 3640万 | ボーナスの高さが魅力だがウェズレイ怖い |
DF | 森岡 隆三 | 清水 | 5600万 | 斉藤がおらず不安 |
DF | 三浦 淳宏 | 東京V | 4240万 | やっと使えた。応援している選手 |
DF | シジクレイ | G大阪 | 5040万 | 虫垂炎宮本は不安なので |
DF | ジャーン | F東京 | 7150万 | 加地のポイント伸びないので |
MF | 奥 大介 | 横浜FM | 6350万 | 裏切られ続けているがジュビロの独走を止めたいから |
MF | 阿部 勇樹 | 市原 | 2050万 | とにかく勝ってくれ |
MF | 遠藤 保仁(C) | G大阪 | 4330万 | 久しぶり。最近印象薄いが実績でキャプテン |
MF | 鈴木 慎吾 | 新潟 | 2220万 | ずっと使ってみたかったのだ |
MF | 今野 泰幸 | F東京 | 2470万 | 連続得点中 |
FW | アラウージョ | 清水 | 6880万 | なんか調子いい |
■ やること
- プリンタ処分
- 靴磨き
防虫剤