連載 /OavaServer Pages—@ コこ冂第手 図 4 ctl:for のタクハンドラ (For. java) package control ; import Javax. servlet . jsp ・ tagext . * ; import javax. servlet ・ JSP ・ * ; import java. iO . IOException; public class For extends TagSupport private int count = 0 ; private String name = nuII ; private int start = 0 ; private int end = 0 ; private int step = 0 ; public void setName (String v) { na.me = V ; ゝ public int doStartTag() throws JspException { C ount start; if (count く end) { if (name ! = Ⅱ u11 ) { pageContext . setAttribute (name , new lnteger(count)) ; return EVAL_BODY_INCLUDE; else { return SKIP_BODY ; public int d0AfterBody ( ) { if (name ! = null) { try { count 十 = step , pageContext . setAttribute (name , new lnteger(count) ) ; } catch (NumberFormatException e) { } setStart(String v) { public void try { lnteger. parselnt(v) ; st art } catch (NumberFormatException if (count く end) { return EVAL_BODY_AGAIN ; } else { return SK 工 P_BODY ; public void setEnd(String v) { try { end = lnteger ・ parselnt(v) ; } catch (NumberFormatException public int d0EndTag() throws JspException { return EVAL_PAGE; public void setStep(String v) { try { step = lnteger ・ parselnt(v) ; } catch (NumberFormatException 図 5 JSP コードの鰰斤と呼び出されるメソッドの系 : く ctl:for name="number" start="l “ step="l “ > : end="411 ⑤ dosta ag ( ) を呼び出す ② setStart()1 " ) を呼び出す④ setStep()1 " ) を 呼び出す </ctl:for> : く % = number % > little<br> ⑥ doA 代 e 「 Body ( ) を呼び出す SK 旧ー BODY を返すと、終了 EVAL BODY_AGAIN を返 すと、タグ本体の先頭からもう タグを処理する 一度処理する ⑦ doEndTag() を呼び出す 85 UNIX MAGAZINE 2003.3
連載 . /JavaServer Pages—@ 図 8 変数に固定した名前日寸けるための TLD の く tag> く name>for く /name> く variable> く name—given> 変デ委廴名く /name—given> く variable—class>lnteger く /variable く /variable> く /tag> に示します。 —class> 図 6 の control.tld と図 7 の web. xml ファイルは、 JSP のアプリケーションをインストールしたディレクト に置いてください。 WEB—INF/web . xml WEB—INF/t1d/contr01. tld リの下の、 特定の名前をもつ変数 できるようになります。 こまでで、最初に紹介した図 1 の JSP ページを表示 には、このタグに関する variable の設定を次のようにし ctl:for タグか生成する変数の名前を、、 number" にする を付けるには、 TLD ファイルに図 8 のように言己します。 たとえば、 ctl:for タグで生成する変数に決まった名前 います。 方、固定した名前を付ける方式では、 name-given を使 name-from-attribute を使って変数名を指定します。 前者のタグの属性て指定する方式では、すでに説明した ・固定した名前を付ける。 ・タグの属生で指定する。 ります。 カスタムタグか生成する変数の名前の付け方は 2 通りあ ます。 く variable> く name—given>number く ,/name—given> く variable—class>lnteger く /variable く /variable> 88 —class> 図 9 固定した変数名を付けたときに変更するタグハンドラのメ public int doStartTag() throws JspException { count = start ; if (count く end) { return SKIP_BODY ; } else { return EVAL_BODY_INCLUDE ; new lnteger (count) ) ; pageContext . setAttribute ( "number" , , if (name ! = null) { UNIX MAGAZINE 2003.3 return SKIP_BODY; } else { return EVAL_BODY_AGAIN ; if (count く end) { } catch (NumberFormatException e) { } new lnteger(count) ) ; pageContext . setAttribute("number" , = 〉 count 十 = step ; try { if (name ! = null) { public int d0AfterBody() { ます。 name-given て指定した名前 ) を変数名として指定してい number" という決まった文字列 (TLD の のように lnteger (count) ) ; pageContext . setAttribute ( "number" , new - が、図 9 では、 性の値カイ呆存されている ) を変数名として指定しています は、 For クラスの name 変数 (ctl:for タグの name 属 lnteger (count) ) ; pageContext . setAttribute (name , new ドラのコード、 AfterBody() メソッドを示しています。もとのタグハン 図 9 は、書換え後の doStartTag() メソッドおよび do- せん。 グハンドラの対応するコードも書き換えなくてはなりま もちろん、 TLD で固定の変数名を付けたときは、タ
連載 /JavaServer Pages—@ 図 3 ctI:trueLoop タグを使った JSP ページ (indians ・ jsp) く %@ page contentType="text/htm1 ; charset=EUC—JP" % > く %@ taglib prefix="ctl" uri="http://www.astec ・ co ・ jp / co Ⅱ t て 01 " % > く ! DOCTYPE HTML PUBLIC "—//W3C//DTD HTML 4.0 Transitiona1//EN"> く html > く head> く meta http—equiv="Content—Type" content="text/html ; charset=EUC—JP"> く title > 10 人のインディアンく /title> く /he ad> く body> く % int number 1 ; く ct1 :trueLoop count="3"> く % = number + + % > little く br> く /ctI:trueLoop> lndians く /body> く /html > ・ setEnd( ” 4 ” ) ・ setStep( ” 1 ” ) を順番に呼び出します。これらのメソッドは受け取った属 性値を For クラスの変数に保存します。 次に、開始タグの最後で doStartTag() メソッドを呼 び出します。 doStartTag() の以下のコード、 return SKIP_BODY ; } else { return EVAL_BODY_ 工 NCLUDE ; if (count く end) { count = start ; 84 新したあと、 び出されます。 doAfterBody() では number 変数を更 タグ本体の処理カ鮗ると、次に doAfterBody() か呼 はあとで説明します。 number 変数のネ月化もしていますが、この処理について doStartTag() メソッドでは、今回のポイントである するかを制御します。 よって処理を続けるか、またはタグ本体の処理をスキップ 期化したり、区し処理の牛を満たしているかどうかに では、区し処理の回数をカウントする count 変数を初 ・タグ本体の処理をもう一度おこなう (return EVAL- BODY-AGAIN) ・終了タグを処理する (return SKIP-BODY) のどちらにするかを決めて JSP 工ンジンに知らせます。 最後に、終了タグを解析するときに doEndTag() メソ ッドを呼び出し、 ctl:for タグの処理を終了します。 変数の初期化と更新 ctl:trueLoop タグでは、 ・ number 変数の初期化 ・ number 変数の値の更新 をスクリプトレットや式タグで実現していましたが、 ctl: for タグはこれらの処理をタグハンドラの内部でおこない ます。具イ勺なコードをみてみましよう。 number 変数の初期化は、 doStartTag() メソッドの 次のコードでおこなっています。 pageContext . setAttribute (name , new lnteger(count) ) ; また、 number 変数の値の更新は、 doAfterBody() メ ソッドの次のコードでおこなっています。 UNIX MAGAZINE 2003.3
連載 / Linux のプートプロセスをみる一 0 図 8 do-fork() を呼び出す直前のスタック だけで、プロセスを生成する処理の実体は do-fork() で実 装されています。 0744 : int sys—clone(struct pt_regs regs) 0745 : { 00010F00 C0105030 clone—flags stack start regs stack Si ze sys—clon e ( ) system—call() 0749 : 0750 : 0751 : 0752 : 0753 : clone—flags = regs. ebx ; newsp = regs . ecx; if ( ! newsp) newsp = regs . esp; return do—fork(clone—flags , newsp , ®s, 0 ) ; 00000000 EBX 戻りアドレス EBX ECX EDX 0754 : } こで注目すべきポイントは構造体 pt-regs です。 の十冓造イ本は、ファイル include/asm-i386/ptrace. h で 以下のように定義されています。 struct pt—regs { 10 Ⅱ g ebx ; 1 ong ecx; 10 Ⅱ g edx ; 1 ong esl; 10 Ⅱ g edi ; 10 Ⅱ g ebp ; 1 ong eax; i nt xds ; int xes; 1 ong orlg—eax ; 10 Ⅱ g elp; int XCS; 10 Ⅱ g eflags; long esp; int XSS,• ています。 #define CLONE_SIGNAL (CLONE_SIGHAND ー CLONE THREAD) したがって、正確には、 CLONE_FS ー CLONE_FILES ー CLONE_SIGHAND ー CLONE_THREAD ー CLONE_VM を未することになります。 舌はそれますが、 do-fork() は sys-clone() だけでな この構造は、 system-call() がレジスタの内容をスタ く、 fork と vfork システムコールを実装する関数からも ックに格納した順番と同しです ( 図 7 も参照してくださ 呼び出されます。その違いは、以下のように引数のフラグ い ) 。そして、 202 行目の CALL 命令により戻りアドレ だけです。 ス ( 203 行目のアドレス ) がスタックに積まれます。この int sys-fork(struct pt-regs regs) ため、 sys-clone() はスタック上のレジスタの内容を、関 0739 : 0740 : { 数に渡された引数のように参照することができます。 return d0—fork(SIGCHLD, regs ・ esp, 0741 : kernel-thread() では、フラグの値を EBX に、 init() ®s , 0 ) ; のアドレスを ECX にオ褓内して INT 命令を実行しました ( 図 4 ) 。よって、 749 ~ 750 行目の regs. ebx と regs. ecx により、それぞれの値を取り出すことができます。 do-fork() を呼び出す直前のスタックの内容を図 8 に 示します。 do%rk() への引数であるフラグ ( 00010F00 ) は、 rest-init() の 532 行目と kernel-thread() の 508 行 目を合わせたものです。しかし、 CLONE-SIGNAL につ いては include/linux/sched. h で以下のように定義され 1 三ロ 0742. int sys—vfork (struct pt—regs regs) 0766 : 0767 : return do—fork ( 0768 : CLONE_VFORK ー CLONE_VM ー SIGCHLD , regs ・ esp, ®s, 0 ) ; 0769. つまり、 do-fork() はプロセス生成の全般を受け持つル ーチンなのです。 154 UNIX MAGAZINE 2003.3
連載 / IPv6 の実装ー⑩ 図 2 残りの中継ノード、 0 ではない場合 ~ 里 176 177 178 179 icmp6—error(m , ICMP6—PARAM-PROB, ICMP6—PARAMPROB_HEADER, (caddr—t)&rh—>ip6r—type ー (caddr—t) ip6) ; return (IPPROTO_DONE) ; 171 172 173 174 if ( rh- 230 } ; 最初の 2 オクテットはすべての刻に、、ツダに共通の内容 です。 ip6r-nxt には経路制餌ヘッダの次に続くへッダの プロトコル番号をオ村します。 ip6r-len には糸各制笹ッ ダの長さを 8 オクテット単位でオ内します。ただし、先 頭の 8 オクテットは含みません。 ip6r-type は経路制御 ヘッダの不頁を示します。現在はタイプ 0 のみが定義さ れています。 ip6rsegleft には残りの中継ノード数をオ褓内 します。この値は、経路制笹いッダが中継ノードで処理さ れるたびに 1 っすっ減っていき、最後の中継ノードがヘッ ダを処理した時点で 0 になります。 106 switch (rh—>ip6r—type) { 107 case IPV6_RTHDR_TYPE_0 : 続いて、 106 行目で経路制餌ヘッダの不頁ごとに処理が 分岐します。ただし、一屬己のとおり現在定義されているの はタイプ 0 だけなので、実際には処理は 1 つしかありま せん。 108 rhlen = (rh->ip6r—1en + 1 ) くく 3 ; ip6r-len には経各制徊ヘッダの長さが 8 オクテット単 位てオ褓内されています。 : 頁の 8 オクテットの長さは含 まれないので、そのぶんを考慮して 108 行目で経路制御 ヘッダ全体の長さを言算し、 rhlen に取り出します。 115 IP6—EXTHDR_CHECK (), off , rhlen , IPPROTO_DONE) ; 115 行目では、経路缶雅卩ヘッダ本カ漣続メモリ領域に 配置されているかどうかを石忍します。 131 if (ip6—rthdrO (), 土 p6 , (struct ip6—rthdrO >ip6r—seg1eft rhlen = (rh—>ip6r_1en + 1 ) くく 3 ; break ; タイプ 0 以外の経路制御ヘッダを受信した場合は、残 りの中継ノード数によって処理が分かれます。残りの中継 ノード数が 0 、すなわち自分自身か冬的な終点ノードで ある場合 ( 171 行目 ) は、経路卸ヘッダの内容を処理す る必要はありません。 172 行目で経路缶膽いッダの全体長 を計算し、次のヘッダの処理に進むために 173 行目でルー プを抜けます。 残りの中継ノード数が 0 でなければ、自分自身が中継 ノードとして指定されていることになります。しかし、未 知の不頁の経路制餌ヘッダは処理できませんから、図 2 の 176 ~ 177 行目で経路制御ヘッダの不頁 (ip6r-type) が 不正であることを ICMP で送信者に通知します。そして、 178 行目で IPPROTODONE を ip6-input() に返し、 バケットの処理を中断します。 181 182 183 } *offp + = rhlen ; return (rh—>ip6r—nxt) ; これで経路制征いッダの処理は完了したので、 181 行目 でオフセットの値か次に続くへッダを示すように更新し、 182 行目で次に処理するプロトコル番号を ip6-input() へ 返します。 タイプ 0 経路制御ヘッダの入力里 タイプ 0 糸響各制御ヘッダは ip6-rthdrO() で処理され 132 133 break ; return (IPPROTO_DONE) ; ます。 191 192 193 194 195 196 static int ip6—rthdrO (m , ip6 , て hO ) struct mbuf *m; struct ip6—hdr *ip6 ; struct ip6—rthdrO * て hO ; 間題がなければ、 131 行目で ip6-rthdr0() を呼び出し、 タイプ 0 経路制御ヘッダを処理します。 169 default : 68 ip6-rthdr0() は 3 つの引数をもちます。 m は入力した バケットかオ褓内されている mbuf へのポインタ、 ip6 は UNIX MAGAZINE 2003.3
連載 / 旧 v6 の実装ー① 図 3 ヘッタ展の正当性のチェック ( 1 ) 205 if (rhO—>ip6rO_1en % 2 ) { 216 217 218 219 } icmp6—error (m , ICMP6—PARAM-PROB , ICMP6—PARAMPROB_HEADER, (caddr—t) &rhO—>ip6rO-1en ー (caddr-t) 土 p6 ) ; return ( ー 1 ) ; 図 4 ヘッタ・長の正当性のチェック ( 2 ) if ( (addrs = rhO—>ip6rO-1en / 2 ) く rhO—>ip6rO-seg1eft) { 221 223 224 225 icmp6—error (), ICMP6—PARAM PROB , ICMP6—PARAMPROB_HEADER, (caddr—t) ip6) ; (caddr-t) &rhO->ip6rO—seg1eft return ( ー 1 ) ; 226 } 入力した IP バケットの先頭アドレス、 rh0 は経路制御 ヘッダの地頁アドレスです。タイプ 0 経路制御ヘッダは ip6•thdrO 構造体で定義されます。 ip6. h 233 struct ip6—rthdr0 { 234 235 236 237 238 240 } ; u_int8_t u_int8_t u_int8_t u_int8_t u_int32_t ip6rO—nxt ; ip6rO—Ien ; ip6rO—type ; ip6rO—seg1eft; ip6rO—reserved ; タイプに依存しない糸響各制御ヘッタ構造体である ip6- rthdr 構造体と上交してみると、予約フィールド (ip6rO- reserved) 以外はまったく同しであることが分かります。 タイプ 0 経路制御ヘッダの場合、 ip6-rthdr0 構造体のあ とに中継ノードのアドレスカ例挙されます。 = の 202 if (rhO—>ip6rO—seg1eft 8 オクテット単位でオ褓内されています。タイプ 0 経路制御 ヘッダは、 8 オクテットの ip6 ー rthdrO 構造体と、 16 オク テットの中継ノードアドレスの組合ぜです。 ip6r0 」 en の 単位は 8 オクテットで、最初の 8 オクテットを引算に含め ませんから、 ip6r0 」 en はかならす偶数になります。ヘッ ダ長か不正な場合、 216 ~ 217 行目で ip6rO 」 en の値カ坏 正であることを、 ICMP を使って送信者に知らせます。 タイプ 0 糸各制御ヘッダの場合、 ip6r0 」 en の値か列 挙された中継ノード部分の長さと等しくなります。 ip6r0- len は 8 オクテット単位で、 IPv6 アドレスが 16 オクテッ トですから、 ip6r0Aen を 2 て割った値が中継ノードの総 数になるはすです。もし、 ip6r0-segIeft で指定された残 りの中継ノード数よりも、列挙されているアドレスが少な ければ ( 図 4 の 221 行目 ) 、処理を継続することができま せん。 223 ~ 224 行目で ip6rO-segIeft か不正な値である ことを ICMP で送信者に通知します。 203 return ( 0 ) ; ます、バケットを受信したノードが最終的な終点ノード かどうかを石忍します ( 202 行目 ) 。 ip6r0-segIeft は残り の中継ノード数です。 0 の場合は自分が最終的な終点ノー ドになりますから、経路制御ヘッダを処理する必要はあり ません。 route6-input() に処理を返し、次のヘッダの処 理に進みます。 タイプ 0 経路制御ヘッダの正当性チェック 205 ~ 226 行目 ( 図 3 ~ 4 ) はヘッダ長の正当性のチェ ックです。 ip6r0 」 en ( 205 行目 ) には、経路制御ヘッダの本長が UNIX MAGAZINE 2003.3 228 229 230 index = addrs ー rhO—>ip6rO—seg1eft ; rhO->ip6rO—seg1eft— ( (struct in6-addr * ) ( て hO + 1 ) ) nextaddr 十 index ; 列挙された中継ノード数は、 221 行目で addrs に設定 されています。 228 行目では、その値と残りの中継ノー ド数から、次に処理すべき中継ノードのアドレスかオ褓内さ れている位置を計算して index に設定します。そして、 図 1 ー 3 を実行するために、交換すべき中継ノードのアド レスへのポインタを nextaddr に設定します ( 230 行目 ) 。 229 行目では、残り中継ノード数を減らしています。 237 if (IN6—IS-ADDR_MULTICAST(nextaddr) Ⅱ 69
SoIaris 特集 図 3 リモートダンプに失敗したときのメッセージ DUMP: Protoc01 to remote tape server botched (code stty: lnvalid argument?) . rdump: LOSt connection tO remote host. DUMP : Bad return code from dump : 1 端末制御が必要ならば、 . login で設定すればよい。 nfs mount: mars:/work: アクセス権がありません。 ージが出力された。 症状マウントしようとしたら、次のようなエラーメッセ NFS に関する間題と、その対処の例を挙げる。 NFS に関するもの 症状 : 下記のメッセージか表示さファイルにアクセス を石忍し、されていなけれは適切なエントリを追加する。 dfstab で、クライアント・マシンが share されているか ていないことが原因である。 NFS サーバーの /etc/dfs/ これは、 NFS サーバー側で share の設定がおこなわれ Sta1e NFS % ls できない。 ステムの状態に不整合が発生したときに表示される。これ このメッセージは、 NFS で共有しているファイルシ Fi1e Hand1e UNIX MAGAZINE 2003.3 場合は、リマウント操作をおこなう必がある。これは、 CD-ROM が NFS サーバー側で変更されてしまった し、必要ならバックアップから復旧する。 なくなる。そのディレクトリを復旧すべきかどうかを石忍 ディレクトリに移動ければ ls コマンドはエラーを出力し ディレクトリか削除されたときは、 cd コマンドで別の ROM メディアと入れ替えてマウントしなおした場合 側でその CD-ROM をアンマウントしたり、別の CD- ・ CD-ROM を NFS マウントしている最中に、サーバー クトリを削除した場合 ント上のユーサーがそのファイルか置かれているディレ いるファイルをオープンしている最中に、別のクライア ・あるクライアント上のユーザーが NFS マウントされて は、次のようなケースて起こることが多い。 次のように mount コマンドに ンを付けて実行すれはよい。 # mount ー 0 remount /work ー 0 remount' オフ。ショ テープ、フロッピーに関するもの テーフ。やフロッピーディスクを扱う際に出力される可能 性のあるエラーメッセージと、その対処の例を挙げる。 ・フロッピーディスクの操作に関するもの フロッピーディスクの実際の容量とは異なる誤ったオ プションを指定すると、エラーメッセージが表小され る。たとえば 2HD のフロッピーディスクを挿入し、一 1 オプションを指定してフォーマットしようとすると、次 のようなエラーメッセージか表示される。 % fdformat -dl Press return t0 start formatting floppy ・ fdformat : can't read verify data, I/O error ・テーフ。ヘッドの汚れに関するもの DAT ドライプのテーフ。ヘッドが汚れていると、 /var/ adm/messages ファイルに図 4 のようなエラーメッ 25 オ功売み出せるかをチェックするとよい。 なら、バックアップをとったあと、別のドライプでそ もあるが、それでもかなりの時間がかかる。慎重を期す る。メーカーの工ンジニアによる調整が可能な場合 換すると、バックアップ・データか読めないことにな なる。つまり、古章などによってテーブドライプを交 ライプと大きくずれていると、別のドライフで読めなく の角度でテープにデータを言隶するが、これがはかのド にそうなったのかは分からない ) 。テーフ。ヘッドは一定 のであった ( 最初から歪んでいたのか、使っているうち がある ( 図 5 ) 。これは、テーフ。ヘッドの歪みによるも のドライプでは読み出せないという問題が発生したこと あるテーブドライプでテープに書き込んだデータが、別 ヘッドのクリーニングをおこなう。 が出力されたら、専用のクリーニング・キットでテープ セージか記録されることがある。この種のメッセージ
連載 / lPv6 の実装ー① 図 9 頁バケットを言済みの場合 ~ 里 if (q6—>ip6q—unfrg1en + fragoff + frgpartlen > IPV6—MAXPACKET) { icmp6-error (m , ICMP6—PARAM-PROB , ICMP6—PARAMPROB-HEADER, offset ー sizeof (struct ip6—frag) + offsetof (struct ip6—frag, ip6f—off1g) ) ; IP6Q-UNLOCK ( ) ; return (IPPROTO_DONE) ; 374 375 376 377 378 379 380 図 10 381 382 383 384 385 386 387 頁バケットを受信していない場合 ~ 里 } else if (fragoff + frgpartlen > IPV6-MAXPACKET) { icmp6—error (), ICMP6—PARAM—PROB , ICMP6—PARAMPROB—HEADER, sizeof (struct ip6—frag) + offset offsetof(struct ip6—frag, ip6f—off1g)) ; IP6Q-UNLOCK() ; return (IPPROTO_DONE) ; 381 ~ 387 行目 ( 図 10 ) は、まだ頁バケットを受信し 392 は、一嗹の分割バケットの地ルヾケットを受信したときに いるバケットの大きさをチェックします。このチェック 392 ~ 423 行目では、分割バケットリストにイ尉寺されて if (fragoff ドです。 れます。すぐ後ろに続くコードか再チェックのためのコー 分割バケットの地ルサットを受信したときに再度実行さ トである可能生カ戯っています。完全なチェックは一連の たしません。つまり、チェックに合格しても不正なバケッ このチェックは必要条件を満たしますが、十分条件は満 理を終了します。 うかを不忍します。超えていたら、 ICMP を返信して処 トの最大長 IPV6-MAXPACKET を超えていないかど 割バケットの大きさを示す frgpartlen の合計が、バケッ バケットか本来配置されていた位置を示す fragoff と、分 きない部分の大きさがまだ分からないので、受信した分割 ていない状態での正当性チェックです。この場合、分割で 393 for (af6 = q6—>ip6q-down; af6 ! = 実行されます。 397 398 if (q6—>ip6q-unfrg1en + af6—>ip6af—0ff + af6—>ip6af—frg1en > IPV6_MAXPACKET) { 394 395 (struct ip6asfrag *)q6 ; af6 = af6dwn) { af6dwn = af6->ip6af—down; 再構築バケット凵寺されている分割バケットリスト の要素を 1 っすったどり、 374 ~ 380 行目と同様の正当生 チェックを実施します。 UNIX MAGAZINE 2003.3 ip6af-off と ip6af-frglen にはそれぞオし断片ヘッダの オフセット値と分割バケットの長さが一寺されています。 再構築後に IP バケットの最大長を超えるようであれば、 この分割バケットは不正なバケットです。 399 struct mbuf *merr = IP6—REASS MBUF (af6) ; 401 int erroff = af6—>ip6af—offset ; 工ラーを通知するために、イ寺しておいた分割バケット かオ褓内されている mbuf ポインタを merr に、そのバケッ トにおける IP ヘッダの : 麪頁から断片ヘッダの知頁までの オフセットを erroff に言殳定します。 404 frag6—deq(af6) ; 405 free (af6 , M—FTABLE) ; バケットの内容か不正であることカ半」明したので、 404 ~ 405 行目で分割バケットリストから該当するバケット を削除します。 frag6-deq() は分割バケットリストから要 素を削除する関数です。 408 ip6err = mtod(merr , struct ip6—hdr * ) ; 414 ip6err—>ip6—src = q6¯>ip6q—src. sin6—addr ; ip6err->ip6-dst = q6—>ip6q-dst . sin6-addr ; 415 もともとの分割バケットの始点 / 終点アドレスを設定し ます。一連の分割バケットはすべて同し始点 / 終点アドレ スをもっています。再構築バケットをイ寺している ip6q 75
238 239 240 242 243 連載 / IPv6 の実装ー⑩ return ( ー 1 ) ; m—freem(m) ; IN6_IS_ADDR_V4COMPAT(nextaddr) ) { IN6_IS_ADDR_V4MAPPED(nextaddr) Ⅱ IN6_IS_ADDR_UNSPECIFIED (nextaddr) Ⅱ 244 } い通信を防ぐためのものです。 性があります。このコードは、誤った設定による意図しな グを実施していなければ、フィルタを j 面茴してしまう可能 IPv4 射影アドレスや IPv4 互換アドレスのフィルタリン 法で特定の IPv6 アドレスを遮断していても、対応する 処理系を通過します。たとえば、フィルタリングなどの手 ドレスカ甘旨定されたバケットは、転送の過程で IPv4 の 定されている経路制ヘッダも処理しません。これらのア IPv4 互換アドレス (IPv4 Compatible Address) カ甘旨 理由から IPv4 射影アドレス (IPv4 Mapped Address) 、 ス ) の利用も禁止しています。さらに、セキュリティ上の では、未定義アドレス ( すべてのビットが 0 であるアドレ スとしてマルチキャスト・アドレスは使えません。 KAME レスの正当性チェックです。仕様上、中継ノードのアドレ 237 ~ 244 行目は中継ノードとして指定されているアド goto bad ; IN6_IS_ADDR_V4COMPAT (&ip6—>ip6_dst) ) { IN6_IS_ADDR_V4MAPPED (&ip6—>ip6_dst) Ⅱ ip6-dst) Ⅱ IN6_IS_ADDR_UNSPECIFIED (&ip6—> ip6-dst) Ⅱ 245 if (IN6—IS_ADDR_MULTICAST(&ip6—> 248 247 246 251 } 250 258 if ( (ifa = ip6_getdstifaddr (m) ) = = NULL) 終点アドレスと次の中継ノードアドレスの交換 います。 チェックです。 237 ~ 244 行目と同様のチェックをおこな 245 ~ 251 行目は IP バケットの終点アドレスの正当性 267 next_sa. sin6_addr = *nextaddr ・ next-sa は次の中継ノードを示す sockaddr-in6 構造体 てす。経路制御ヘッダから取り出した nextaddr にはアド レスの情報しかないので、不足しているスコープ情報を補 わなければなりません。必要な情報を sockaddr-in6 構造 体にオ内していきます。 268 if (in6—addr2zoneid(ifa—>ia_ifp , nextaddr 270 &next—sa. sin6—scope—id)) { goto bad; 271 } 次の中継ノードのスコープは、バケットを受信したアド レスのスコープと同一になります。 268 行目では、 258 行 目で取得した受信アドレスの情報 ifa を使って、次の中継 ノードのスコープ情報を決定します。 272 if (in6_embedscope (&next_sa. sin6_addr 275 &next-sa) ) { goto bad ; 276 } 272 行目は、アドレスの一部にスコーフ精報を埋め込む ための定型処理てす。 277 if ( ! ip6_setpktaddrs (), NULL , &next_sa)) 278 goto bad ; 以 .. ヒでスコープ情報を含む中継ノードアドレスか完成し ました。このアドレスか新しい終点アドレスになります。 277 行目で、 ip6-setpktaddrs() を使って次の中継ノー ドのアドレスを終点アドレスに設定します。 283 tmpaddr = *nextaddr ; 284 *nextaddr = ip6—>ip6—dst ; 285 ip6->ip6—dst = tmpaddr ; 283 ~ 285 行目で、経路制脚ヘッダの中継ノードのアド レスと、 IP ヘッダの終点アドレスを交換します。 259 goto bad ; 293 296 301 } ip6-forward(), 1 ) ; return ( ー 1 ) ; ip6-getdstifaddr() は、 IP ノヾケットの終点アドレスに 対応するインターフェイス・アドレスを in6-ifaddr 構造 体で返す関数です。この情報は、次の中継ノードのスコー フ 3 辭にを決定するために必要になります。 264 265 266 70 bzero(&next—sa, sizeof(next—sa) ) ; next—sa. sin6—famiIy = AF_INET6 ; next_sa. sin6_len = sizeof (next_sa) ; アドレスか交換されたバケットはもはや自分宛ではない ので、 293 行目で ip6-forward() を使って転送します。 転送されたバケットは ip6-forward() の内部で解放され ます。 UNIX MAGAZINE 2003.3
連載 / lPv6 の実装ー① 図 6 分割されたバケットのべイロード確認 282 283 284 285 287 288 2 73 274 } if ( (ip6f—>ip6f—0ff1g & IP6F—MORE—FRAG) & & ( ( (nt0hs(ip6->ip6—p1en) offset) & 0X7 ) ! = 0 ) ) { icmp6-error(), ICMP6—PARAM-PROB , ICMP6-PARAMPROB_HEADER, return IPPROTO_DONE ; offset) ; 工 CMP6_PARAMPROB_HEADER , return IPPROTO_DONE; offsetof (struct ip6-hdr , ip6—p1en) ) ; 270 ~ 274 行目は巨大ペイロード・オプションカ甘旨定さ れている場合の処理です。巨大ペイロード・オプションと 断片ヘッダを同時に利用することはできません。断片ヘッ ダのオフセット値は 13 ビットで表現さ 8 オクテット 単位の値をとるので、最大でも 65 , 535 オクテットまでし か表現できません。巨大ペイロード・オプションは 65 , 536 オクテット以トのバケットにのみ適用されます。巨大ペイ ロード・オプションカイ吏われるときは、 IP バケットのペ イロード長 (ip6-pIen) が 0 に設定されます。この場合、 ICMP を使って送信者にエラーを通知します。 282 ~ 288 行目 ( 図 6 ) では、分割されたバケットのペ イロード長が正当な値かどうかを石忍します。分割バケッ トの分割される前の位置は、 ip6f-offlg に設定されている オフセット値から判断できます。オフセットは 8 オクテッ ト単イ立で表されるので、各分割バケットも 8 の倍数でなけ ればなりません ( 283 行目 ) 。ただし、一連の分割バケッ トのうち、最後尾のバケットは伊外です。麦尾の分割パ ケットかどうかは、 M フラグ (IP6F-MORE-FRAG : 後続分割バケットあり ) て判断できます。 282 行目て断片 ヘッダに M フラグカイ寸いているかどうかを調べ、付いて いれば 283 行目でペイロード長が 8 の倍数になっている ことを石忍します。 8 の倍数でなければ、 284 ~ 285 行目 でペイロード長カ坏正であることを送信者に通知します。 冓築バケットリストへの挿入 バケットの正当性カ蔀忍されたら、分割されたバケット の再構築処理に進みます。 . 294 offset + = sizeof(struct ip6—frag) ; 変数 0 仕 sét は frag6-input() の冒頭で、 IP バケットの 72 知頁から断片ヘッダの頁までのオフセットにネ月化され ています。 294 行目で ip6-frag 構造体の大きさお助日し、 分割されたデータ本体までのオフセットに更新します。 296 IP6Q—LOCK ( ) ; IP6Q-LOCK() は、分割されたバケットか再構築され るまで f 尉寺されるリスト構造体をロックする関数です。タ イマー割込みによるリスト解放処理との競合を避けるた め、リストを操作する前にロックする必要があります。以 後このリストを再構築バケットリストと呼びます。 303 if (ip6—maxfrags く 0 ) 304 305 else if (frag6—nfrags > = 306 (u—int) ip6-maxfrags) goto dropfrag; 多量の分割バケットの受信により発生するメモリの楡曷 を防ぐため、一度にイ寺できる分割バケットは ip6-max- frags で指定される値に制限されます。この値が 0 より 小さい場合は無制限 0 ンサットを受信します ( 303 行目 ) 。 ip6-maxfrags に 0 以丘の値か設定されており、現在処理 中の分割バケット数 (frag6-nfrags) が ip6-maxfrags を 超えていたら ( 305 行目 ) 、バケットを破棄します。 308 ~ 312 行目 ( 図 7 ) では、受信した分割バケットが 現在再構築中のバケットの一にかどうかを調べます。再構 築中のバケットは ip6q を : 頁とする再構築バケットリス トに「尉寺されているので、リストをたどりながら次の 3 つ の情報カしいリスト要素を本し、 q6 に設定します。 ・断片ヘッダの識別子 (ip6q-ident) ・バケットの始点アドレス (src-sa) ・バケットの終点アドレス (dst-sa) 308 行目の for ループを抜けた段階で、再構築中のパ ケットがみつかった場合は q6 にリスト要素へのポインタ が、みつからなければリストの : 原である ip6q へのポイ ンタか設定されることになります。 UNIX MAGAZINE 2003.3