メモの日々


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 というのはどのように決まるのか。と思ったけど、切りがないので終了。今知りたいことはもう分かった。

[dev][c] OS/Programming (千葉滋さん)

東工大での授業用の資料かな。Cコンパイラ、GUIツールキット、ウェブサーバ、スレッドライブラリの作成についての説明がある。

[fs] 1236位 時価総額8億6790万

仕事とファンタジーサッカーを繰り返す生活。9節は104fpで高ポイントだったが全体的にポイント高かったようで順位はあまり上がらず。小笠原とキャプテントゥーリオとリカルドが活躍、西部だけ失敗。トップとの差は85fp。

次節もまた7チームで構成。ジュビロの選手を使わないのは初めてかも。

GK高木 義成東京V3640万ボーナスの高さが魅力だがウェズレイ怖い
DF森岡 隆三清水5600万斉藤がおらず不安
DF三浦 淳宏東京V4240万やっと使えた。応援している選手
DFシジクレイG大阪5040万虫垂炎宮本は不安なので
DFジャーンF東京7150万加地のポイント伸びないので
MF奥 大介横浜FM6350万裏切られ続けているがジュビロの独走を止めたいから
MF阿部 勇樹市原2050万とにかく勝ってくれ
MF遠藤 保仁(C)G大阪4330万久しぶり。最近印象薄いが実績でキャプテン
MF鈴木 慎吾新潟2220万ずっと使ってみたかったのだ
MF今野 泰幸F東京2470万連続得点中
FWアラウージョ清水6880万なんか調子いい

やること

  • プリンタ処分
  • 靴磨き
  • 防虫剤