* copy vendor drop to trunk
[lab.git] / Dev / utvpn / utvpn-unix-v101-7101-public / src / Cedar / Layer3.c
1 // SoftEther UT-VPN SourceCode\r
2 // \r
3 // Copyright (C) 2004-2010 SoftEther Corporation.\r
4 // Copyright (C) 2004-2010 University of Tsukuba, Japan.\r
5 // Copyright (C) 2003-2010 Daiyuu Nobori.\r
6 // All Rights Reserved.\r
7 // \r
8 // http://utvpn.tsukuba.ac.jp/\r
9 // \r
10 // This program is free software; you can redistribute it and/or\r
11 // modify it under the terms of the GNU General Public License\r
12 // version 2 as published by the Free Software Foundation.\r
13 // \r
14 // This program is distributed in the hope that it will be useful,\r
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
17 // GNU General Public License for more details.\r
18 // \r
19 // You should have received a copy of the GNU General Public License version 2\r
20 // along with this program; if not, write to the Free Software\r
21 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
22 // \r
23 // このファイルは GPL バージョン 2 ライセンスで公開されています。\r
24 // 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布\r
25 // することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示\r
26 // を除去することはできません。改変した著作物を配布する場合は、改変実施者の\r
27 // 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。\r
28 // \r
29 // この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の\r
30 // ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )\r
31 // および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって\r
32 // ホストされています。\r
33 // 本プログラムの配布者は、本プログラムを、業としての利用以外のため、\r
34 // および、試験または研究のために利用が行われることを想定して配布\r
35 // しています。\r
36 // SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に\r
37 // あります。\r
38 // 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード\r
39 // の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して\r
40 // いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して\r
41 // ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース\r
42 // に組み込みさせていただきます。\r
43 // \r
44 // GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する\r
45 // 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。\r
46 // \r
47 // 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社\r
48 // (SoftEther Corporation) およびその他の著作権保持者が保有しています。\r
49 // ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの\r
50 // 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意\r
51 // ください。\r
52 // \r
53 // お願い: どのような通信ソフトウェアにも通常は必ず未発見の\r
54 // セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、\r
55 // UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの\r
56 // 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社\r
57 // および脆弱性情報の届出を受け付ける公的機関まで通報いただき、\r
58 // 公益保護にご協力いただきますようお願い申し上げます。\r
59 // \r
60 // ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を\r
61 // 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客\r
62 // を保護するための努力を行います。\r
63 // \r
64 // ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/\r
65 // 日本国内の脆弱性情報届出受付公的機関:\r
66 //         独立行政法人 情報処理推進機構\r
67 //         http://www.ipa.go.jp/security/vuln/report/\r
68 // \r
69 // 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。\r
70 // 連絡先: http://www.softether.co.jp/jp/contact/\r
71 \r
72 // -----------------------------------------------\r
73 // [ChangeLog]\r
74 // 2010.05.20\r
75 //  新規リリース by SoftEther\r
76 // -----------------------------------------------\r
77 \r
78 // Layer3.c\r
79 // Layer-3 スイッチ モジュール\r
80 \r
81 #include "CedarPch.h"\r
82 \r
83 static UCHAR broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\r
84 \r
85 // IP キューの処理\r
86 void L3PollingIpQueue(L3IF *f)\r
87 {\r
88         L3PACKET *p;\r
89         // 引数チェック\r
90         if (f == NULL)\r
91         {\r
92                 return;\r
93         }\r
94 \r
95         // 別のセッションから来たパケットを処理する\r
96         while (p = GetNext(f->IpPacketQueue))\r
97         {\r
98                 PKT *pkt = p->Packet;\r
99 \r
100                 // IP パケットとして送信する\r
101                 L3SendIp(f, p);\r
102         }\r
103 }\r
104 \r
105 // IP パケットの処理\r
106 void L3RecvIp(L3IF *f, PKT *p, bool self)\r
107 {\r
108         IPV4_HEADER *ip;\r
109         UINT header_size;\r
110         UINT next_hop = 0;\r
111         L3IF *dst;\r
112         L3PACKET *packet;\r
113         UINT new_ttl = 0;\r
114         // 引数チェック\r
115         if (f == NULL || p == NULL)\r
116         {\r
117                 return;\r
118         }\r
119 \r
120         ip = p->L3.IPv4Header;\r
121         header_size = IPV4_GET_HEADER_LEN(p->L3.IPv4Header) * 4;\r
122 \r
123         // チェックサムの計算\r
124         if (IpCheckChecksum(ip) == false)\r
125         {\r
126                 // チェックサムが一致しない\r
127                 goto FREE_PACKET;\r
128         }\r
129 \r
130         // ARP テーブルに登録\r
131         L3KnownArp(f, ip->SrcIP, p->MacAddressSrc);\r
132 \r
133         if (p->BroadcastPacket)\r
134         {\r
135                 // ブロードキャストパケットの場合はルーティングしない\r
136                 goto FREE_PACKET;\r
137         }\r
138 \r
139         // TTL を計算\r
140         if (ip->TimeToLive >= 1)\r
141         {\r
142                 new_ttl = ip->TimeToLive - 1;\r
143         }\r
144         else\r
145         {\r
146                 new_ttl = 0;\r
147         }\r
148 \r
149         if (new_ttl == 0)\r
150         {\r
151                 if (ip->DstIP != f->IpAddress)\r
152                 {\r
153                         UINT src_packet_size = p->PacketSize - sizeof(MAC_HEADER);\r
154                         UINT icmp_packet_total_size = sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4 + header_size + 8;\r
155                         UCHAR *buf;\r
156                         IPV4_HEADER *ipv4;\r
157                         ICMP_HEADER *icmpv4;\r
158                         UCHAR *data;\r
159                         PKT *pkt;\r
160                         UINT data_size = MIN(p->PacketSize - header_size, header_size + 8);\r
161 \r
162                         // TTL 切れが発生したことを知らせる ICMP メッセージを生成する\r
163                         buf = ZeroMalloc(icmp_packet_total_size);\r
164                         ipv4 = (IPV4_HEADER *)(buf + sizeof(MAC_HEADER));\r
165                         icmpv4 = (ICMP_HEADER *)(buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER));\r
166                         data = buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4;\r
167 \r
168                         IPV4_SET_VERSION(ipv4, 4);\r
169                         IPV4_SET_HEADER_LEN(ipv4, sizeof(IPV4_HEADER) / 4);\r
170                         ipv4->TotalLength = Endian16((USHORT)(icmp_packet_total_size - sizeof(MAC_HEADER)));\r
171                         ipv4->TimeToLive = 0xff;\r
172                         ipv4->Protocol = IP_PROTO_ICMPV4;\r
173                         ipv4->SrcIP = f->IpAddress;\r
174                         ipv4->DstIP = ip->SrcIP;\r
175                         ipv4->Checksum = IpChecksum(ipv4, sizeof(IPV4_HEADER));\r
176 \r
177                         icmpv4->Type = 11;\r
178                         Copy(data, ip, data_size);\r
179                         icmpv4->Checksum = IpChecksum(icmpv4, sizeof(ICMP_HEADER) + data_size + 4);\r
180 \r
181                         buf[12] = 0x08;\r
182                         buf[13] = 0x00;\r
183 \r
184                         pkt = ParsePacket(buf, icmp_packet_total_size);\r
185                         if (pkt == NULL)\r
186                         {\r
187                                 Free(buf);\r
188                         }\r
189                         else\r
190                         {\r
191                                 L3RecvIp(f, pkt, true);\r
192                         }\r
193 \r
194                         // TTL が切れたパケット本体は破棄する\r
195                         goto FREE_PACKET;\r
196                 }\r
197         }\r
198 \r
199         // 書き換える\r
200         p->L3.IPv4Header->TimeToLive = (UCHAR)new_ttl;\r
201 \r
202         // 宛先 IP アドレスに対するインターフェイスを取得する\r
203         dst = L3GetNextIf(f->Switch, ip->DstIP, &next_hop);\r
204 \r
205         if (dst == NULL && self == false)\r
206         {\r
207                 UINT src_packet_size = p->PacketSize - sizeof(MAC_HEADER);\r
208                 UINT icmp_packet_total_size = sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4 + header_size + 8;\r
209                 UCHAR *buf;\r
210                 IPV4_HEADER *ipv4;\r
211                 ICMP_HEADER *icmpv4;\r
212                 UCHAR *data;\r
213                 PKT *pkt;\r
214                         UINT data_size = MIN(p->PacketSize - header_size, header_size + 8);\r
215 \r
216                 // ルートが見つからない旨を ICMP で応答する\r
217                 buf = ZeroMalloc(icmp_packet_total_size);\r
218                 ipv4 = (IPV4_HEADER *)(buf + sizeof(MAC_HEADER));\r
219                 icmpv4 = (ICMP_HEADER *)(buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER));\r
220                 data = buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4;\r
221 \r
222                 IPV4_SET_VERSION(ipv4, 4);\r
223                 IPV4_SET_HEADER_LEN(ipv4, sizeof(IPV4_HEADER) / 4);\r
224                 ipv4->TotalLength = Endian16((USHORT)(icmp_packet_total_size - sizeof(MAC_HEADER)));\r
225                 ipv4->TimeToLive = 0xff;\r
226                 ipv4->Protocol = IP_PROTO_ICMPV4;\r
227                 ipv4->SrcIP = f->IpAddress;\r
228                 ipv4->DstIP = ip->SrcIP;\r
229                 ipv4->Checksum = IpChecksum(ipv4, sizeof(IPV4_HEADER));\r
230 \r
231                 icmpv4->Type = 3;\r
232                 Copy(data, ip, data_size);\r
233                 icmpv4->Checksum = IpChecksum(icmpv4, sizeof(ICMP_HEADER) + data_size + 4);\r
234 \r
235                 buf[12] = 0x08;\r
236                 buf[13] = 0x00;\r
237 \r
238                 pkt = ParsePacket(buf, icmp_packet_total_size);\r
239                 if (pkt == NULL)\r
240                 {\r
241                         Free(buf);\r
242                 }\r
243                 else\r
244                 {\r
245                         L3RecvIp(f, pkt, true);\r
246                 }\r
247 \r
248                 // ルートが見つからないパケット本体は破棄する\r
249                 goto FREE_PACKET;\r
250         }\r
251 \r
252         if (dst != NULL && ip->DstIP == dst->IpAddress)\r
253         {\r
254                 bool free_packet = true;\r
255                 // 自分宛の IP パケットが届いた\r
256                 if (p->TypeL4 == L4_ICMPV4)\r
257                 {\r
258                         ICMP_HEADER *icmp = p->L4.ICMPHeader;\r
259                         if (icmp->Type == ICMP_TYPE_ECHO_REQUEST)\r
260                         {\r
261                                 // この IP パケットの宛先と送信元を書き換えて返信する\r
262                                 UINT src_ip, dst_ip;\r
263                                 src_ip = p->L3.IPv4Header->DstIP;\r
264                                 dst_ip = p->L3.IPv4Header->SrcIP;\r
265 \r
266                                 p->L3.IPv4Header->DstIP = dst_ip;\r
267                                 p->L3.IPv4Header->SrcIP = src_ip;\r
268 \r
269                                 ip->TimeToLive = 0xff;\r
270 \r
271                                 // チェックサムを再計算する\r
272                                 ip->FlagsAndFlagmentOffset[0] = ip->FlagsAndFlagmentOffset[1] = 0;\r
273                                 icmp->Checksum = 0;\r
274                                 icmp->Type = ICMP_TYPE_ECHO_RESPONSE;\r
275                                 icmp->Checksum = IpChecksum(icmp, p->PacketSize - sizeof(MAC_HEADER) - header_size);\r
276 \r
277                                 dst = L3GetNextIf(f->Switch, ip->DstIP, &next_hop);\r
278 \r
279                                 free_packet = false;\r
280                         }\r
281                 }\r
282 \r
283                 if (free_packet)\r
284                 {\r
285                         goto FREE_PACKET;\r
286                 }\r
287         }\r
288 \r
289         if (dst == NULL)\r
290         {\r
291                 // 宛先が存在しない\r
292                 goto FREE_PACKET;\r
293         }\r
294 \r
295         // IP チェックサムの再計算\r
296         ip->Checksum = 0;\r
297         ip->Checksum = IpChecksum(ip, header_size);\r
298 \r
299         // Layer-3 パケットとして処理する\r
300         packet = ZeroMalloc(sizeof(L3PACKET));\r
301         packet->Expire = Tick64() + IP_WAIT_FOR_ARP_TIMEOUT;\r
302         packet->NextHopIp = next_hop;\r
303         packet->Packet = p;\r
304 \r
305         // 宛先セッションにストアする\r
306         L3StoreIpPacketToIf(f, dst, packet);\r
307 \r
308         return;\r
309 \r
310 FREE_PACKET:\r
311         // パケットの解放\r
312         Free(p->PacketData);\r
313         FreePacket(p);\r
314         return;\r
315 }\r
316 \r
317 // レイヤ 2 パケットの処理\r
318 void L3RecvL2(L3IF *f, PKT *p)\r
319 {\r
320         // 引数チェック\r
321         if (f == NULL || p == NULL)\r
322         {\r
323                 return;\r
324         }\r
325 \r
326         // 自分が送信したパケットか、ユニキャストパケットで自分宛で無いパケット\r
327         // はすべて無視する\r
328         if (Cmp(p->MacAddressSrc, f->MacAddress, 6) == 0 ||\r
329                 (p->BroadcastPacket == false && Cmp(p->MacAddressDest, f->MacAddress, 6) != 0))\r
330         {\r
331                 // パケット解放\r
332                 Free(p->PacketData);\r
333                 FreePacket(p);\r
334                 return;\r
335         }\r
336 \r
337         if (p->TypeL3 == L3_ARPV4)\r
338         {\r
339                 // ARP パケットを受信した\r
340                 L3RecvArp(f, p);\r
341 \r
342                 // パケット解放\r
343                 Free(p->PacketData);\r
344                 FreePacket(p);\r
345         }\r
346         else if (p->TypeL3 == L3_IPV4)\r
347         {\r
348                 // IP パケットを受信した\r
349                 L3RecvIp(f, p, false);\r
350         }\r
351         else\r
352         {\r
353                 // パケット解放\r
354                 Free(p->PacketData);\r
355                 FreePacket(p);\r
356         }\r
357 }\r
358 \r
359 // IP パケットを別のインターフェイスにストアする\r
360 void L3StoreIpPacketToIf(L3IF *src_if, L3IF *dst_if, L3PACKET *p)\r
361 {\r
362         // 引数チェック\r
363         if (src_if == NULL || p == NULL || dst_if == NULL)\r
364         {\r
365                 return;\r
366         }\r
367 \r
368         // ストア先セッションのキューに追加する\r
369         InsertQueue(dst_if->IpPacketQueue, p);\r
370 \r
371         // ストア先セッションの Cancel オブジェクトを叩くことにする\r
372         AddCancelList(src_if->CancelList, dst_if->Session->Cancel1);\r
373 }\r
374 \r
375 // パケットを書き込む (新しいパケットが届いたので処理する)\r
376 void L3PutPacket(L3IF *f, void *data, UINT size)\r
377 {\r
378         PKT *p;\r
379         L3SW *s;\r
380         if (f == NULL)\r
381         {\r
382                 return;\r
383         }\r
384 \r
385         s = f->Switch;\r
386 \r
387         if (data != NULL)\r
388         {\r
389                 // 次のパケットを処理する\r
390                 if (f->CancelList == NULL)\r
391                 {\r
392                         f->CancelList = NewCancelList();\r
393                 }\r
394 \r
395                 // パケット解析\r
396                 p = ParsePacket(data, size);\r
397 \r
398                 if (p == NULL)\r
399                 {\r
400                         // パケット解析失敗\r
401                         Free(data);\r
402                 }\r
403                 else\r
404                 {\r
405                         // パケット解析成功\r
406                         Lock(s->lock);\r
407                         {\r
408                                 L3RecvL2(f, p);\r
409                         }\r
410                         Unlock(s->lock);\r
411                 }\r
412         }\r
413         else\r
414         {\r
415                 // すべてのパケットの処理が終わったらキャンセルリストをキャンセル処理する\r
416                 if (f->CancelList != NULL)\r
417                 {\r
418                         CancelList(f->CancelList);\r
419                         ReleaseCancelList(f->CancelList);\r
420                         f->CancelList = NULL;\r
421                 }\r
422         }\r
423 }\r
424 \r
425 // 待機している IP パケットのうち送信先 MAC アドレスが解決したものを送信する\r
426 void L3SendWaitingIp(L3IF *f, UCHAR *mac, UINT ip, L3ARPENTRY *a)\r
427 {\r
428         UINT i;\r
429         LIST *o = NULL;\r
430         // 引数チェック\r
431         if (f == NULL || mac == NULL || a == NULL)\r
432         {\r
433                 return;\r
434         }\r
435 \r
436         for (i = 0;i < LIST_NUM(f->IpWaitList);i++)\r
437         {\r
438                 L3PACKET *p = LIST_DATA(f->IpWaitList, i);\r
439 \r
440                 if (p->NextHopIp == ip)\r
441                 {\r
442                         if (o == NULL)\r
443                         {\r
444                                 o = NewListFast(NULL);\r
445                         }\r
446                         Add(o, p);\r
447                 }\r
448         }\r
449 \r
450         if (o != NULL)\r
451         {\r
452                 for (i = 0;i < LIST_NUM(o);i++)\r
453                 {\r
454                         L3PACKET *p = LIST_DATA(o, i);\r
455 \r
456                         // 送信\r
457                         L3SendIpNow(f, a, p);\r
458 \r
459                         Delete(f->IpWaitList, p);\r
460                         Free(p->Packet->PacketData);\r
461                         FreePacket(p->Packet);\r
462                         Free(p);\r
463                 }\r
464 \r
465                 ReleaseList(o);\r
466         }\r
467 }\r
468 \r
469 // ARP テーブルに登録する\r
470 void L3InsertArpTable(L3IF *f, UINT ip, UCHAR *mac)\r
471 {\r
472         L3ARPENTRY *a, t;\r
473         // 引数チェック\r
474         if (f == NULL || ip == 0 || ip == 0xffffffff || mac == NULL)\r
475         {\r
476                 return;\r
477         }\r
478 \r
479         Zero(&t, sizeof(t));\r
480         t.IpAddress = ip;\r
481 \r
482         a = Search(f->ArpTable, &t);\r
483 \r
484         if (a == NULL)\r
485         {\r
486                 // リストに登録されていないので登録する\r
487                 a = ZeroMalloc(sizeof(L3ARPENTRY));\r
488                 a->IpAddress = ip;\r
489                 Copy(a->MacAddress, mac, 6);\r
490                 Insert(f->ArpTable, a);\r
491         }\r
492 \r
493         // 有効期限を延長する\r
494         a->Expire = Tick64() + ARP_ENTRY_EXPIRES;\r
495 \r
496         // 待機している IP パケットを送信させる\r
497         L3SendWaitingIp(f, mac, ip, a);\r
498 }\r
499 \r
500 // ARP テーブルを知ったときに呼ばれる関数\r
501 void L3KnownArp(L3IF *f, UINT ip, UCHAR *mac)\r
502 {\r
503         L3ARPWAIT t, *w;\r
504         // 引数チェック\r
505         if (f == NULL || ip == 0 || ip == 0xffffffff || mac == NULL)\r
506         {\r
507                 return;\r
508         }\r
509 \r
510         // この IP アドレスへの ARP 問い合わせテーブルを削除する\r
511         Zero(&t, sizeof(t));\r
512         t.IpAddress = ip;\r
513         w = Search(f->IpWaitList, &t);\r
514         if (w != NULL)\r
515         {\r
516                 Delete(f->IpWaitList, w);\r
517                 Free(w);\r
518         }\r
519 \r
520         // ARP テーブルに登録する\r
521         L3InsertArpTable(f, ip, mac);\r
522 }\r
523 \r
524 // ARP を発行する\r
525 void L3SendArp(L3IF *f, UINT ip)\r
526 {\r
527         L3ARPWAIT t, *w;\r
528         // 引数チェック\r
529         if (f == NULL || ip == 0 || ip == 0xffffffff)\r
530         {\r
531                 return;\r
532         }\r
533 \r
534         // すでに登録されていないかどうか調べる\r
535         Zero(&t, sizeof(t));\r
536         t.IpAddress = ip;\r
537         w = Search(f->ArpWaitTable, &t);\r
538 \r
539         if (w != NULL)\r
540         {\r
541                 // すでに待機リストに登録されているので何もしない\r
542                 return;\r
543         }\r
544         else\r
545         {\r
546                 // 新しくリストに登録する\r
547                 w = ZeroMalloc(sizeof(L3ARPWAIT));\r
548                 w->Expire = Tick64() + ARP_REQUEST_GIVEUP;\r
549                 w->IpAddress = ip;\r
550                 Insert(f->ArpWaitTable, w);\r
551         }\r
552 }\r
553 \r
554 // ARP 要求を受信した\r
555 void L3RecvArpRequest(L3IF *f, PKT *p)\r
556 {\r
557         ARPV4_HEADER *a;\r
558         // 引数チェック\r
559         if (f == NULL || p == NULL)\r
560         {\r
561                 return;\r
562         }\r
563 \r
564         a = p->L3.ARPv4Header;\r
565 \r
566         L3KnownArp(f, a->SrcIP, a->SrcAddress);\r
567 \r
568         if (a->TargetIP == f->IpAddress)\r
569         {\r
570                 // 自分宛の ARP パケットの場合のみ応答する\r
571                 L3SendArpResponseNow(f, a->SrcAddress, a->SrcIP, f->IpAddress);\r
572         }\r
573 }\r
574 \r
575 // ARP 応答を受信した\r
576 void L3RecvArpResponse(L3IF *f, PKT *p)\r
577 {\r
578         ARPV4_HEADER *a;\r
579         // 引数チェック\r
580         if (f == NULL || p == NULL)\r
581         {\r
582                 return;\r
583         }\r
584 \r
585         a = p->L3.ARPv4Header;\r
586 \r
587         L3KnownArp(f, a->SrcIP, a->SrcAddress);\r
588 }\r
589 \r
590 // ARP パケットを受信した\r
591 void L3RecvArp(L3IF *f, PKT *p)\r
592 {\r
593         ARPV4_HEADER *a;\r
594         // 引数チェック\r
595         if (f == NULL || p == NULL)\r
596         {\r
597                 return;\r
598         }\r
599 \r
600         a = p->L3.ARPv4Header;\r
601 \r
602         if (Endian16(a->HardwareType) != ARP_HARDWARE_TYPE_ETHERNET ||\r
603                 Endian16(a->ProtocolType) != MAC_PROTO_IPV4 ||\r
604                 a->HardwareSize != 6 || a->ProtocolSize != 4)\r
605         {\r
606                 return;\r
607         }\r
608         if (Cmp(a->SrcAddress, p->MacAddressSrc, 6) != 0)\r
609         {\r
610                 return;\r
611         }\r
612 \r
613         switch (Endian16(a->Operation))\r
614         {\r
615         case ARP_OPERATION_REQUEST:\r
616                 // ARP 要求が届いた\r
617                 L3RecvArpRequest(f, p);\r
618                 break;\r
619 \r
620         case ARP_OPERATION_RESPONSE:\r
621                 // ARP 応答が届いた\r
622                 L3RecvArpResponse(f, p);\r
623                 break;\r
624         }\r
625 }\r
626 \r
627 // IP パケットを送信する\r
628 void L3SendIp(L3IF *f, L3PACKET *p)\r
629 {\r
630         L3ARPENTRY *a = NULL;\r
631         bool broadcast = false;\r
632         IPV4_HEADER *ip;\r
633         bool for_me = false;\r
634         // 引数チェック\r
635         if (f == NULL || p == NULL)\r
636         {\r
637                 return;\r
638         }\r
639         if (p->Packet->TypeL3 != L3_IPV4)\r
640         {\r
641                 return;\r
642         }\r
643 \r
644         ip = p->Packet->L3.IPv4Header;\r
645 \r
646         // ブロードキャストかどうか判定\r
647         if (p->NextHopIp == 0xffffffff ||\r
648                 ((p->NextHopIp & f->SubnetMask) == (f->IpAddress & f->SubnetMask)) &&\r
649                 ((p->NextHopIp & (~f->SubnetMask)) == (~f->SubnetMask)))\r
650         {\r
651                 broadcast = true;\r
652         }\r
653 \r
654         if (broadcast == false && ip->DstIP == f->IpAddress)\r
655         {\r
656                 // me?\r
657         }\r
658         else if (broadcast == false)\r
659         {\r
660                 // ユニキャストの場合 ARP エントリに入っているかどうか調べる\r
661                 a = L3SearchArpTable(f, p->NextHopIp);\r
662 \r
663                 if (a == NULL)\r
664                 {\r
665                         // ARP エントリに入っていないので、すぐに送信せずに\r
666                         // IP 待ちリストに挿入する\r
667                         p->Expire = Tick64() + IP_WAIT_FOR_ARP_TIMEOUT;\r
668 \r
669                         Insert(f->IpWaitList, p);\r
670 \r
671                         // ARP を発行しておく\r
672                         L3SendArp(f, p->NextHopIp);\r
673                         return;\r
674                 }\r
675         }\r
676 \r
677         if (for_me == false)\r
678         {\r
679                 // IP パケットを送信する\r
680                 L3SendIpNow(f, a, p);\r
681         }\r
682 \r
683         // パケットを解放する\r
684         Free(p->Packet->PacketData);\r
685         FreePacket(p->Packet);\r
686         Free(p);\r
687 }\r
688 \r
689 // IP パケットをすぐに送信する\r
690 void L3SendIpNow(L3IF *f, L3ARPENTRY *a, L3PACKET *p)\r
691 {\r
692         // 引数チェック\r
693         if (f == NULL || p == NULL)\r
694         {\r
695                 return;\r
696         }\r
697 \r
698         L3SendL2Now(f, a != NULL ? a->MacAddress : broadcast, f->MacAddress, Endian16(p->Packet->MacHeader->Protocol),\r
699                 p->Packet->L3.PointerL3, p->Packet->PacketSize - sizeof(MAC_HEADER));\r
700 }\r
701 \r
702 // ARP テーブルを検索する\r
703 L3ARPENTRY *L3SearchArpTable(L3IF *f, UINT ip)\r
704 {\r
705         L3ARPENTRY *e, t;\r
706         // 引数チェック\r
707         if (f == NULL || ip == 0 || ip == 0xffffffff)\r
708         {\r
709                 return NULL;\r
710         }\r
711 \r
712         Zero(&t, sizeof(t));\r
713         t.IpAddress = ip;\r
714 \r
715         e = Search(f->ArpTable, &t);\r
716 \r
717         return e;\r
718 }\r
719 \r
720 // ARP 要求パケットを送信する\r
721 void L3SendArpRequestNow(L3IF *f, UINT dest_ip)\r
722 {\r
723         ARPV4_HEADER arp;\r
724         // 引数チェック\r
725         if (f == NULL)\r
726         {\r
727                 return;\r
728         }\r
729 \r
730         // ARP ヘッダを構築\r
731         arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);\r
732         arp.ProtocolType = Endian16(MAC_PROTO_IPV4);\r
733         arp.HardwareSize = 6;\r
734         arp.ProtocolSize = 4;\r
735         arp.Operation = Endian16(ARP_OPERATION_REQUEST);\r
736         Copy(arp.SrcAddress, f->MacAddress, 6);\r
737         arp.SrcIP = f->IpAddress;\r
738         Zero(&arp.TargetAddress, 6);\r
739         arp.TargetIP = dest_ip;\r
740 \r
741         // 送信\r
742         L3SendL2Now(f, broadcast, f->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));\r
743 }\r
744 \r
745 // ARP 応答パケットを送信する\r
746 void L3SendArpResponseNow(L3IF *f, UCHAR *dest_mac, UINT dest_ip, UINT src_ip)\r
747 {\r
748         ARPV4_HEADER arp;\r
749         // 引数チェック\r
750         if (f == NULL || dest_mac == NULL)\r
751         {\r
752                 return;\r
753         }\r
754 \r
755         // ヘッダ構築\r
756         arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);\r
757         arp.ProtocolType = Endian16(MAC_PROTO_IPV4);\r
758         arp.HardwareSize = 6;\r
759         arp.ProtocolSize = 4;\r
760         arp.Operation = Endian16(ARP_OPERATION_RESPONSE);\r
761         Copy(arp.SrcAddress, f->MacAddress, 6);\r
762         Copy(arp.TargetAddress, dest_mac, 6);\r
763         arp.SrcIP = src_ip;\r
764         arp.TargetIP = dest_ip;\r
765 \r
766         // 送信\r
767         L3SendL2Now(f, dest_mac, f->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));\r
768 }\r
769 \r
770 // インターフェイスの MAC アドレスの生成\r
771 void L3GenerateMacAddress(L3IF *f)\r
772 {\r
773         BUF *b;\r
774         UCHAR hash[SHA1_SIZE];\r
775         // 引数チェック\r
776         if (f == NULL)\r
777         {\r
778                 return;\r
779         }\r
780 \r
781         b = NewBuf();\r
782         WriteBuf(b, f->Switch->Name, StrLen(f->Switch->Name));\r
783         WriteBuf(b, f->HubName, StrLen(f->HubName));\r
784         WriteBuf(b, &f->IpAddress, sizeof(f->IpAddress));\r
785 \r
786         GenMacAddress(f->MacAddress);\r
787         Hash(hash, b->Buf, b->Size, true);\r
788         Copy(f->MacAddress + 2, hash, 4);\r
789         f->MacAddress[1] = 0xA3;\r
790         FreeBuf(b);\r
791 }\r
792 \r
793 // L2 パケットをすぐに送信する\r
794 void L3SendL2Now(L3IF *f, UCHAR *dest_mac, UCHAR *src_mac, USHORT protocol, void *data, UINT size)\r
795 {\r
796         UCHAR *buf;\r
797         MAC_HEADER *mac_header;\r
798         PKT *p;\r
799         // 引数チェック\r
800         if (f == NULL || dest_mac == NULL || src_mac == NULL || data == NULL)\r
801         {\r
802                 return;\r
803         }\r
804 \r
805         // バッファ生成\r
806         buf = Malloc(MAC_HEADER_SIZE + size);\r
807 \r
808         // MAC ヘッダ\r
809         mac_header = (MAC_HEADER *)&buf[0];\r
810         Copy(mac_header->DestAddress, dest_mac, 6);\r
811         Copy(mac_header->SrcAddress, src_mac, 6);\r
812         mac_header->Protocol = Endian16(protocol);\r
813 \r
814         // データのコピー\r
815         Copy(&buf[sizeof(MAC_HEADER)], data, size);\r
816 \r
817         // サイズ\r
818         size += sizeof(MAC_HEADER);\r
819 \r
820         // パケット生成\r
821         p = ZeroMalloc(sizeof(PKT));\r
822         p->PacketData = buf;\r
823         p->PacketSize = size;\r
824 \r
825         // キューに追加する\r
826         InsertQueue(f->SendQueue, p);\r
827 }\r
828 \r
829 // ARP 解決待ちリストのポーリング\r
830 void L3PollingArpWaitTable(L3IF *f)\r
831 {\r
832         UINT i;\r
833         LIST *o = NULL;\r
834         // 引数チェック\r
835         if (f == NULL)\r
836         {\r
837                 return;\r
838         }\r
839 \r
840         for (i = 0;i < LIST_NUM(f->ArpWaitTable);i++)\r
841         {\r
842                 L3ARPWAIT *w = LIST_DATA(f->ArpWaitTable, i);\r
843 \r
844                 if (w->Expire <= Tick64())\r
845                 {\r
846                         // ARP 要求テーブルが期限切れである\r
847                         if (o == NULL)\r
848                         {\r
849                                 o = NewListFast(NULL);\r
850                         }\r
851 \r
852                         Insert(o, w);\r
853                 }\r
854                 else if ((w->LastSentTime + ARP_REQUEST_TIMEOUT) <= Tick64())\r
855                 {\r
856                         // 次の ARP 要求パケットを送信する\r
857                         w->LastSentTime = Tick64();\r
858 \r
859                         L3SendArpRequestNow(f, w->IpAddress);\r
860                 }\r
861         }\r
862 \r
863         if (o != NULL)\r
864         {\r
865                 for (i = 0;i < LIST_NUM(o);i++)\r
866                 {\r
867                         L3ARPWAIT *w = LIST_DATA(o, i);\r
868 \r
869                         Delete(f->ArpWaitTable, w);\r
870                         Free(w);\r
871                 }\r
872 \r
873                 ReleaseList(o);\r
874         }\r
875 }\r
876 \r
877 // 古い ARP テーブルの清掃\r
878 void L3DeleteOldArpTable(L3IF *f)\r
879 {\r
880         UINT i;\r
881         LIST *o = NULL;\r
882         // 引数チェック\r
883         if (f == NULL)\r
884         {\r
885                 return;\r
886         }\r
887 \r
888         if ((f->LastDeleteOldArpTable + ARP_ENTRY_POLLING_TIME) > Tick64())\r
889         {\r
890                 return;\r
891         }\r
892         f->LastDeleteOldArpTable = Tick64();\r
893 \r
894         for (i = 0;i < LIST_NUM(f->ArpTable);i++)\r
895         {\r
896                 L3ARPENTRY *a = LIST_DATA(f->ArpTable, i);\r
897 \r
898                 if (a->Expire <= Tick64())\r
899                 {\r
900                         // 有効期限切れ\r
901                         if (o == NULL)\r
902                         {\r
903                                 o = NewListFast(NULL);\r
904                         }\r
905 \r
906                         Insert(o, a);\r
907                 }\r
908         }\r
909 \r
910         if (o != NULL)\r
911         {\r
912                 for (i = 0;i < LIST_NUM(o);i++)\r
913                 {\r
914                         L3ARPENTRY *a = LIST_DATA(o, i);\r
915 \r
916                         Delete(f->ArpTable, a);\r
917                         Free(a);\r
918                 }\r
919 \r
920                 ReleaseList(o);\r
921         }\r
922 }\r
923 \r
924 // IP 待ちリストの清掃\r
925 void L3DeleteOldIpWaitList(L3IF *f)\r
926 {\r
927         UINT i;\r
928         LIST *o = NULL;\r
929         // 引数チェック\r
930         if (f == NULL)\r
931         {\r
932                 return;\r
933         }\r
934 \r
935         for (i = 0;i < LIST_NUM(f->IpWaitList);i++)\r
936         {\r
937                 L3PACKET *p = LIST_DATA(f->IpWaitList, i);\r
938 \r
939                 if (p->Expire <= Tick64())\r
940                 {\r
941                         if (o == NULL)\r
942                         {\r
943                                 o = NewListFast(NULL);\r
944                         }\r
945 \r
946                         Insert(o, p);\r
947                 }\r
948         }\r
949 \r
950         if (o != NULL)\r
951         {\r
952                 for (i = 0;i < LIST_NUM(o);i++)\r
953                 {\r
954                         L3PACKET *p = LIST_DATA(o, i);\r
955 \r
956                         Delete(f->IpWaitList, p);\r
957 \r
958                         Free(p->Packet->PacketData);\r
959                         FreePacket(p->Packet);\r
960                         Free(p);\r
961                 }\r
962 \r
963                 ReleaseList(o);\r
964         }\r
965 }\r
966 \r
967 // ビーコン送信\r
968 void L3PollingBeacon(L3IF *f)\r
969 {\r
970         // 引数チェック\r
971         if (f == NULL)\r
972         {\r
973                 return;\r
974         }\r
975 \r
976         if (f->LastBeaconSent == 0 ||\r
977                 (f->LastBeaconSent + BEACON_SEND_INTERVAL) <= Tick64())\r
978         {\r
979                 UINT dest_ip;\r
980                 UCHAR *udp_buf;\r
981                 UINT udp_buf_size;\r
982                 ARPV4_HEADER arp;\r
983                 IPV4_HEADER *ip;\r
984                 UDP_HEADER *udp;\r
985                 static char beacon_str[] =\r
986                         "SoftEther UT-VPN Virtual Layer-3 Switch Beacon";\r
987 \r
988                 // UDP を送信\r
989                 dest_ip = (f->IpAddress & f->SubnetMask) | (~f->SubnetMask);\r
990                 udp_buf_size = sizeof(IPV4_HEADER) + sizeof(UDP_HEADER) + sizeof(beacon_str);\r
991                 udp_buf = ZeroMalloc(udp_buf_size);\r
992 \r
993                 ip = (IPV4_HEADER *)udp_buf;\r
994                 udp = (UDP_HEADER *)(udp_buf + sizeof(IPV4_HEADER));\r
995                 udp->DstPort = Endian16(7);\r
996                 udp->SrcPort = Endian16(7);\r
997                 udp->PacketLength = Endian16(sizeof(UDP_HEADER) + sizeof(beacon_str));\r
998 \r
999                 Copy(udp_buf + sizeof(IPV4_HEADER) + sizeof(UDP_HEADER), beacon_str, sizeof(beacon_str));\r
1000 \r
1001                 udp->Checksum = IpChecksum(udp, sizeof(UDP_HEADER) + sizeof(beacon_str));\r
1002 \r
1003                 ip->DstIP = dest_ip;\r
1004                 IPV4_SET_VERSION(ip, 4);\r
1005                 IPV4_SET_HEADER_LEN(ip, (IP_HEADER_SIZE / 4));\r
1006                 ip->TypeOfService = DEFAULT_IP_TOS;\r
1007                 ip->TotalLength = Endian16((USHORT)(udp_buf_size));\r
1008                 ip->TimeToLive = DEFAULT_IP_TTL;\r
1009                 ip->Protocol = IP_PROTO_UDP;\r
1010                 ip->SrcIP = f->IpAddress;\r
1011                 ip->Checksum = IpChecksum(ip, IP_HEADER_SIZE);\r
1012 \r
1013                 L3SendL2Now(f, broadcast, f->MacAddress, MAC_PROTO_IPV4, udp_buf, udp_buf_size);\r
1014 \r
1015                 Free(udp_buf);\r
1016 \r
1017                 // ARP ヘッダを構築\r
1018                 arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);\r
1019                 arp.ProtocolType = Endian16(MAC_PROTO_IPV4);\r
1020                 arp.HardwareSize = 6;\r
1021                 arp.ProtocolSize = 4;\r
1022                 arp.Operation = Endian16(ARP_OPERATION_RESPONSE);\r
1023                 Copy(arp.SrcAddress, f->MacAddress, 6);\r
1024                 arp.SrcIP = f->IpAddress;\r
1025                 arp.TargetAddress[0] =\r
1026                         arp.TargetAddress[1] =\r
1027                         arp.TargetAddress[2] =\r
1028                         arp.TargetAddress[3] =\r
1029                         arp.TargetAddress[4] =\r
1030                         arp.TargetAddress[5] = 0xff;\r
1031                 arp.TargetIP = dest_ip;\r
1032 \r
1033                 // 送信\r
1034                 L3SendL2Now(f, broadcast, f->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));\r
1035 \r
1036                 f->LastBeaconSent = Tick64();\r
1037         }\r
1038 }\r
1039 \r
1040 // ポーリング処理\r
1041 void L3Polling(L3IF *f)\r
1042 {\r
1043         L3SW *s;\r
1044         // 引数チェック\r
1045         if (f == NULL)\r
1046         {\r
1047                 return;\r
1048         }\r
1049 \r
1050         s = f->Switch;\r
1051 \r
1052         // ポーリング処理の途中ではスイッチ全体にロックをかける\r
1053         Lock(s->lock);\r
1054         {\r
1055                 // ビーコン送信\r
1056                 L3PollingBeacon(f);\r
1057 \r
1058                 // IP キューの処理\r
1059                 L3PollingIpQueue(f);\r
1060 \r
1061                 // 古い ARP テーブルの清掃\r
1062                 L3DeleteOldArpTable(f);\r
1063 \r
1064                 // ARP 解決待ちリストのポーリング\r
1065                 L3PollingArpWaitTable(f);\r
1066 \r
1067                 // IP 待ちリストの清掃\r
1068                 L3DeleteOldIpWaitList(f);\r
1069         }\r
1070         Unlock(s->lock);\r
1071 }\r
1072 \r
1073 // 次のパケットを取得する\r
1074 UINT L3GetNextPacket(L3IF *f, void **data)\r
1075 {\r
1076         UINT ret = 0;\r
1077         // 引数チェック\r
1078         if (f == NULL || data == NULL)\r
1079         {\r
1080                 return 0;\r
1081         }\r
1082 \r
1083 START:\r
1084         // 送信キューを調べる\r
1085         LockQueue(f->SendQueue);\r
1086         {\r
1087                 PKT *p = GetNext(f->SendQueue);\r
1088 \r
1089                 if (p != NULL)\r
1090                 {\r
1091                         // パケットがあった\r
1092                         ret = p->PacketSize;\r
1093                         *data = p->PacketData;\r
1094                         // パケット構造体は破棄して良い\r
1095                         Free(p);\r
1096                 }\r
1097         }\r
1098         UnlockQueue(f->SendQueue);\r
1099 \r
1100         if (ret == 0)\r
1101         {\r
1102                 // ポーリング処理\r
1103                 L3Polling(f);\r
1104 \r
1105         // ポーリング処理の結果、新たにパケットがキューに入っていないか\r
1106                 // どうか調べる\r
1107                 if (f->SendQueue->num_item != 0)\r
1108                 {\r
1109                         // キューに入っていたら早速そのパケットを取得させる\r
1110                         goto START;\r
1111                 }\r
1112         }\r
1113 \r
1114         return ret;\r
1115 }\r
1116 \r
1117 // 指定した IP アドレス宛のパケットをどのインターフェイスに投げれば良いか決める\r
1118 L3IF *L3GetNextIf(L3SW *s, UINT ip, UINT *next_hop)\r
1119 {\r
1120         UINT i;\r
1121         L3IF *f;\r
1122         UINT next_hop_ip = 0;\r
1123         // 引数チェック\r
1124         if (s == NULL || ip == 0 || ip == 0xffffffff)\r
1125         {\r
1126                 return NULL;\r
1127         }\r
1128 \r
1129         f = NULL;\r
1130 \r
1131         // まず各インターフェイスの所属しているネットワークに指定した IP アドレスが\r
1132         // 含まれるものが無いかどうか調べる\r
1133         for (i = 0;i < LIST_NUM(s->IfList);i++)\r
1134         {\r
1135                 L3IF *ff = LIST_DATA(s->IfList, i);\r
1136 \r
1137                 if ((ff->IpAddress & ff->SubnetMask) == (ip & ff->SubnetMask))\r
1138                 {\r
1139                         f = ff;\r
1140                         next_hop_ip = ip;\r
1141                         break;\r
1142                 }\r
1143         }\r
1144 \r
1145         if (f == NULL)\r
1146         {\r
1147                 // 見つからなかったらルーティングテーブルを探す\r
1148                 L3TABLE *t = L3GetBestRoute(s, ip);\r
1149 \r
1150                 if (t == NULL)\r
1151                 {\r
1152                         // それでも見つからなかった\r
1153                         return NULL;\r
1154                 }\r
1155                 else\r
1156                 {\r
1157                         // 見つかったルートの NextHop のルータの IP アドレスを持つ\r
1158                         // インターフェイスを探す\r
1159                         for (i = 0;i < LIST_NUM(s->IfList);i++)\r
1160                         {\r
1161                                 L3IF *ff = LIST_DATA(s->IfList, i);\r
1162 \r
1163                                 if ((ff->IpAddress & ff->SubnetMask) == (t->GatewayAddress & ff->SubnetMask))\r
1164                                 {\r
1165                                         f = ff;\r
1166                                         next_hop_ip = t->GatewayAddress;\r
1167                                         break;\r
1168                                 }\r
1169                         }\r
1170                 }\r
1171         }\r
1172 \r
1173         if (f == NULL)\r
1174         {\r
1175                 // 結局宛先インターフェイスが不明であった\r
1176                 return NULL;\r
1177         }\r
1178 \r
1179         if (next_hop != NULL)\r
1180         {\r
1181                 *next_hop = next_hop_ip;\r
1182         }\r
1183 \r
1184         return f;\r
1185 }\r
1186 \r
1187 // 指定した IP アドレス宛の最適なルーティングテーブルエントリを取得する\r
1188 L3TABLE *L3GetBestRoute(L3SW *s, UINT ip)\r
1189 {\r
1190         UINT i;\r
1191         UINT max_mask = 0;\r
1192         UINT min_metric = INFINITE;\r
1193         L3TABLE *ret = NULL;\r
1194         // 引数チェック\r
1195         if (s == NULL || ip == 0)\r
1196         {\r
1197                 return NULL;\r
1198         }\r
1199 \r
1200         // 第一条件: サブネットマスクが最も大きいものを選択\r
1201         // 第二条件: メトリックが最も小さいものを選択\r
1202         for (i = 0;i < LIST_NUM(s->TableList);i++)\r
1203         {\r
1204                 L3TABLE *t = LIST_DATA(s->TableList, i);\r
1205 \r
1206                 if ((t->NetworkAddress & t->SubnetMask) == (ip & t->SubnetMask))\r
1207                 {\r
1208                         if (t->SubnetMask >= max_mask)\r
1209                         {\r
1210                                 max_mask = t->SubnetMask;\r
1211                                 if (min_metric >= t->Metric)\r
1212                                 {\r
1213                                         min_metric = t->Metric;\r
1214                                         ret = t;\r
1215                                 }\r
1216                         }\r
1217                 }\r
1218         }\r
1219 \r
1220         return ret;\r
1221 }\r
1222 \r
1223 // Layer-3 インターフェイスの初期化\r
1224 void L3InitInterface(L3IF *f)\r
1225 {\r
1226         // 引数チェック\r
1227         if (f == NULL)\r
1228         {\r
1229                 return;\r
1230         }\r
1231 \r
1232         // MAC アドレス生成\r
1233         L3GenerateMacAddress(f);\r
1234 \r
1235         // リスト生成\r
1236         f->ArpTable = NewList(CmpL3ArpEntry);\r
1237         f->ArpWaitTable = NewList(CmpL3ArpWaitTable);\r
1238         f->IpPacketQueue = NewQueue();\r
1239         f->IpWaitList = NewList(NULL);\r
1240         f->SendQueue = NewQueue();\r
1241 }\r
1242 \r
1243 // Layer-3 インターフェイスの解放\r
1244 void L3FreeInterface(L3IF *f)\r
1245 {\r
1246         UINT i;\r
1247         L3PACKET *p;\r
1248         PKT *pkt;\r
1249         // 引数チェック\r
1250         if (f == NULL)\r
1251         {\r
1252                 return;\r
1253         }\r
1254 \r
1255         for (i = 0;i < LIST_NUM(f->ArpTable);i++)\r
1256         {\r
1257                 L3ARPENTRY *a = LIST_DATA(f->ArpTable, i);\r
1258                 Free(a);\r
1259         }\r
1260         ReleaseList(f->ArpTable);\r
1261         f->ArpTable = NULL;\r
1262 \r
1263         for (i = 0;i < LIST_NUM(f->ArpWaitTable);i++)\r
1264         {\r
1265                 L3ARPWAIT *w = LIST_DATA(f->ArpWaitTable, i);\r
1266                 Free(w);\r
1267         }\r
1268         ReleaseList(f->ArpWaitTable);\r
1269         f->ArpWaitTable = NULL;\r
1270 \r
1271         while (p = GetNext(f->IpPacketQueue))\r
1272         {\r
1273                 Free(p->Packet->PacketData);\r
1274                 FreePacket(p->Packet);\r
1275                 Free(p);\r
1276         }\r
1277         ReleaseQueue(f->IpPacketQueue);\r
1278         f->IpPacketQueue = NULL;\r
1279 \r
1280         for (i = 0;i < LIST_NUM(f->IpWaitList);i++)\r
1281         {\r
1282                 L3PACKET *p = LIST_DATA(f->IpWaitList, i);\r
1283                 Free(p->Packet->PacketData);\r
1284                 FreePacket(p->Packet);\r
1285                 Free(p);\r
1286         }\r
1287         ReleaseList(f->IpWaitList);\r
1288         f->IpWaitList = NULL;\r
1289 \r
1290         while (pkt = GetNext(f->SendQueue))\r
1291         {\r
1292                 Free(pkt->PacketData);\r
1293                 FreePacket(pkt);\r
1294         }\r
1295         ReleaseQueue(f->SendQueue);\r
1296         f->SendQueue = NULL;\r
1297 }\r
1298 \r
1299 // Layer-3 インターフェイスのスレッド\r
1300 void L3IfThread(THREAD *t, void *param)\r
1301 {\r
1302         L3IF *f;\r
1303         CONNECTION *c;\r
1304         SESSION *s;\r
1305         POLICY *policy;\r
1306         char tmp[MAX_SIZE];\r
1307         char name[MAX_SIZE];\r
1308         char username[MAX_SIZE];\r
1309         // 引数チェック\r
1310         if (t == NULL || param == NULL)\r
1311         {\r
1312                 return;\r
1313         }\r
1314 \r
1315         f = (L3IF *)param;\r
1316 \r
1317         StrCpy(username, sizeof(username), L3_USERNAME);\r
1318         if (f->Switch != NULL)\r
1319         {\r
1320                 StrCat(username, sizeof(username), f->Switch->Name);\r
1321         }\r
1322 \r
1323         // コネクションの作成\r
1324         c = NewServerConnection(f->Switch->Cedar, NULL, t);\r
1325         c->Protocol = CONNECTION_HUB_LAYER3;\r
1326 \r
1327         // セッションの作成\r
1328         policy = ClonePolicy(GetDefaultPolicy());\r
1329         // ポリシーではブロードキャスト数を制限しない\r
1330         policy->NoBroadcastLimiter = true;\r
1331         s = NewServerSession(f->Switch->Cedar, c, f->Hub, username, policy);\r
1332         c->Session = s;\r
1333 \r
1334         ReleaseConnection(c);\r
1335 \r
1336         // セッション名を決定する\r
1337         GetMachineHostName(tmp, sizeof(tmp));\r
1338         if (f->Switch->Cedar->Server->ServerType == SERVER_TYPE_STANDALONE)\r
1339         {\r
1340                 Format(name, sizeof(name), "SID-L3-%s-%u", f->Switch->Name, Inc(f->Hub->SessionCounter));\r
1341         }\r
1342         else\r
1343         {\r
1344                 Format(name, sizeof(name), "SID-L3-%s-%s-%u", tmp, f->Switch->Name, Inc(f->Hub->SessionCounter));\r
1345         }\r
1346         ConvertSafeFileName(name, sizeof(name), name);\r
1347         StrUpper(name);\r
1348 \r
1349         Free(s->Name);\r
1350         s->Name = CopyStr(name);\r
1351 \r
1352         s->L3SwitchMode = true;\r
1353         s->L3If = f;\r
1354 \r
1355         if (s->Username != NULL)\r
1356         {\r
1357                 Free(s->Username);\r
1358         }\r
1359         s->Username = CopyStr(username);\r
1360 \r
1361         StrCpy(s->UserNameReal, sizeof(s->UserNameReal), username);\r
1362 \r
1363         f->Session = s;\r
1364         AddRef(s->ref);\r
1365 \r
1366         // 初期化完了を通知\r
1367         NoticeThreadInit(t);\r
1368 \r
1369         // セッションメイン処理\r
1370         SessionMain(s);\r
1371 \r
1372         // セッションの解放\r
1373         ReleaseSession(s);\r
1374 }\r
1375 \r
1376 // すべての Layer-3 インターフェイスの初期化をする\r
1377 void L3InitAllInterfaces(L3SW *s)\r
1378 {\r
1379         UINT i;\r
1380         // 引数チェック\r
1381         if (s == NULL)\r
1382         {\r
1383                 return;\r
1384         }\r
1385 \r
1386         for (i = 0;i < LIST_NUM(s->IfList);i++)\r
1387         {\r
1388                 L3IF *f = LIST_DATA(s->IfList, i);\r
1389                 THREAD *t;\r
1390 \r
1391                 L3InitInterface(f);\r
1392 \r
1393                 f->Hub = GetHub(s->Cedar, f->HubName);\r
1394                 t = NewThread(L3IfThread, f);\r
1395                 WaitThreadInit(t);\r
1396                 ReleaseThread(t);\r
1397         }\r
1398 }\r
1399 \r
1400 // すべての Layer-3 インターフェイスの解放をする\r
1401 void L3FreeAllInterfaces(L3SW *s)\r
1402 {\r
1403         UINT i;\r
1404         // 引数チェック\r
1405         if (s == NULL)\r
1406         {\r
1407                 return;\r
1408         }\r
1409 \r
1410         for (i = 0;i < LIST_NUM(s->IfList);i++)\r
1411         {\r
1412                 L3IF *f = LIST_DATA(s->IfList, i);\r
1413 \r
1414                 ReleaseHub(f->Hub);\r
1415                 f->Hub = NULL;\r
1416                 ReleaseSession(f->Session);\r
1417                 f->Session = NULL;\r
1418 \r
1419                 L3FreeInterface(f);\r
1420         }\r
1421 }\r
1422 \r
1423 // Layer-3 テスト\r
1424 void L3Test(SERVER *s)\r
1425 {\r
1426         L3SW *ss = L3AddSw(s->Cedar, "TEST");\r
1427         L3AddIf(ss, "DEFAULT", 0x0101a8c0, 0x00ffffff);\r
1428         L3AddIf(ss, "DEFAULT2", 0x0102a8c0, 0x00ffffff);\r
1429         L3SwStart(ss);\r
1430         ReleaseL3Sw(ss);\r
1431 }\r
1432 \r
1433 // Layer-3 スイッチスレッド\r
1434 void L3SwThread(THREAD *t, void *param)\r
1435 {\r
1436         L3SW *s;\r
1437         bool shutdown_now = false;\r
1438         // 引数チェック\r
1439         if (t == NULL || param == NULL)\r
1440         {\r
1441                 return;\r
1442         }\r
1443 \r
1444         s = (L3SW *)param;\r
1445 \r
1446         s->Active = true;\r
1447 \r
1448         NoticeThreadInit(t);\r
1449 \r
1450         // 動作開始\r
1451         SLog(s->Cedar, "L3_SWITCH_START", s->Name);\r
1452 \r
1453         while (s->Halt == false)\r
1454         {\r
1455                 if (s->Online == false)\r
1456                 {\r
1457                         // 現在 L3 スイッチはオフラインなので、一定時間ごとにオンライン化\r
1458                         // を試みる\r
1459                         LockList(s->Cedar->HubList);\r
1460                         {\r
1461                                 Lock(s->lock);\r
1462                                 {\r
1463                                         UINT i;\r
1464                                         UINT n = 0;\r
1465                                         bool all_exists = true;\r
1466                                         if (LIST_NUM(s->IfList) == 0)\r
1467                                         {\r
1468                                                 // 1 つもインターフェイスが無い場合は動作しない\r
1469                                                 all_exists = false;\r
1470                                         }\r
1471                                         for (i = 0;i < LIST_NUM(s->IfList);i++)\r
1472                                         {\r
1473                                                 L3IF *f = LIST_DATA(s->IfList, i);\r
1474                                                 HUB *h = GetHub(s->Cedar, f->HubName);\r
1475 \r
1476                                                 if (h != NULL)\r
1477                                                 {\r
1478                                                         if (h->Offline || h->Type == HUB_TYPE_FARM_DYNAMIC)\r
1479                                                         {\r
1480                                                                 all_exists = false;\r
1481                                                         }\r
1482                                                         else\r
1483                                                         {\r
1484                                                                 n++;\r
1485                                                         }\r
1486                                                         ReleaseHub(h);\r
1487                                                 }\r
1488                                                 else\r
1489                                                 {\r
1490                                                         all_exists = false;\r
1491                                                 }\r
1492                                         }\r
1493 \r
1494                                         if (all_exists && n >= 1)\r
1495                                         {\r
1496                                                 // すべてのインターフェイスの仮想 HUB が有効になったので\r
1497                                                 // 動作を開始する\r
1498                                                 SLog(s->Cedar, "L3_SWITCH_ONLINE", s->Name);\r
1499                                                 L3InitAllInterfaces(s);\r
1500                                                 s->Online = true;\r
1501                                         }\r
1502                                 }\r
1503                                 Unlock(s->lock);\r
1504                         }\r
1505                         UnlockList(s->Cedar->HubList);\r
1506                 }\r
1507                 else\r
1508                 {\r
1509                         // 一定時間ごとにすべてのセッションが終了していないかどうか調査する\r
1510                         UINT i;\r
1511                         bool any_halted = false;\r
1512                         LIST *o = NULL;\r
1513 \r
1514 SHUTDOWN:\r
1515 \r
1516                         Lock(s->lock);\r
1517                         {\r
1518                                 for (i = 0;i < LIST_NUM(s->IfList);i++)\r
1519                                 {\r
1520                                         L3IF *f = LIST_DATA(s->IfList, i);\r
1521                                         if (f->Session->Halt || f->Hub->Offline != false)\r
1522                                         {\r
1523                                                 any_halted = true;\r
1524                                                 break;\r
1525                                         }\r
1526                                 }\r
1527 \r
1528                                 if (shutdown_now)\r
1529                                 {\r
1530                                         any_halted = true;\r
1531                                 }\r
1532 \r
1533                                 if (any_halted)\r
1534                                 {\r
1535                                         SLog(s->Cedar, "L3_SWITCH_OFFLINE", s->Name);\r
1536                                         o = NewListFast(NULL);\r
1537                                         // 1 つでも終了したセッションがあれば、すべてのセッションを終了する\r
1538                                         for (i = 0;i < LIST_NUM(s->IfList);i++)\r
1539                                         {\r
1540                                                 L3IF *f = LIST_DATA(s->IfList, i);\r
1541                                                 Insert(o, f->Session);\r
1542                                         }\r
1543 \r
1544                                         // オフラインに戻す\r
1545                                         s->Online = false;\r
1546                                 }\r
1547                         }\r
1548                         Unlock(s->lock);\r
1549 \r
1550                         if (o != NULL)\r
1551                         {\r
1552                                 UINT i;\r
1553                                 for (i = 0;i < LIST_NUM(o);i++)\r
1554                                 {\r
1555                                         SESSION *s = LIST_DATA(o, i);\r
1556                                         StopSession(s);\r
1557                                 }\r
1558                                 L3FreeAllInterfaces(s);\r
1559                                 ReleaseList(o);\r
1560                                 o = NULL;\r
1561                         }\r
1562                 }\r
1563 \r
1564                 SleepThread(50);\r
1565         }\r
1566 \r
1567         if (s->Online != false)\r
1568         {\r
1569                 shutdown_now = true;\r
1570                 goto SHUTDOWN;\r
1571         }\r
1572 \r
1573         // 動作停止\r
1574         SLog(s->Cedar, "L3_SWITCH_STOP", s->Name);\r
1575 }\r
1576 \r
1577 // Layer-3 スイッチを開始する\r
1578 void L3SwStart(L3SW *s)\r
1579 {\r
1580         // 引数チェック\r
1581         if (s == NULL)\r
1582         {\r
1583                 return;\r
1584         }\r
1585 \r
1586         Lock(s->lock);\r
1587         {\r
1588                 if (s->Active == false)\r
1589                 {\r
1590                         // 登録されている IF 数が 1 以上でないと開始しない\r
1591                         if (LIST_NUM(s->IfList) >= 1)\r
1592                         {\r
1593                                 s->Halt = false;\r
1594 \r
1595                                 // スレッド作成\r
1596                                 s->Thread = NewThread(L3SwThread, s);\r
1597                                 WaitThreadInit(s->Thread);\r
1598                         }\r
1599                 }\r
1600         }\r
1601         Unlock(s->lock);\r
1602 }\r
1603 \r
1604 // Layer-3 スイッチを停止する\r
1605 void L3SwStop(L3SW *s)\r
1606 {\r
1607         THREAD *t = NULL;\r
1608         // 引数チェック\r
1609         if (s == NULL)\r
1610         {\r
1611                 return;\r
1612         }\r
1613 \r
1614         Lock(s->lock);\r
1615         {\r
1616                 if (s->Active == false)\r
1617                 {\r
1618                         Unlock(s->lock);\r
1619                         return;\r
1620                 }\r
1621 \r
1622                 s->Halt = true;\r
1623 \r
1624                 t = s->Thread;\r
1625 \r
1626                 s->Active = false;\r
1627         }\r
1628         Unlock(s->lock);\r
1629 \r
1630         WaitThread(t, INFINITE);\r
1631         ReleaseThread(t);\r
1632 }\r
1633 \r
1634 // Layer-3 スイッチを追加する\r
1635 L3SW *L3AddSw(CEDAR *c, char *name)\r
1636 {\r
1637         L3SW *s = NULL;\r
1638         // 引数チェック\r
1639         if (c == NULL || name == NULL)\r
1640         {\r
1641                 return NULL;\r
1642         }\r
1643 \r
1644         LockList(c->L3SwList);\r
1645         {\r
1646                 s = L3GetSw(c, name);\r
1647 \r
1648                 if (s == NULL)\r
1649                 {\r
1650                         s = NewL3Sw(c, name);\r
1651 \r
1652                         Insert(c->L3SwList, s);\r
1653 \r
1654                         AddRef(s->ref);\r
1655                 }\r
1656                 else\r
1657                 {\r
1658                         ReleaseL3Sw(s);\r
1659                         s = NULL;\r
1660                 }\r
1661         }\r
1662         UnlockList(c->L3SwList);\r
1663 \r
1664         return s;\r
1665 }\r
1666 \r
1667 // Layer-3 スイッチを削除する\r
1668 bool L3DelSw(CEDAR *c, char *name)\r
1669 {\r
1670         L3SW *s;\r
1671         bool ret = false;\r
1672         // 引数チェック\r
1673         if (c == NULL || name == NULL)\r
1674         {\r
1675                 return false;\r
1676         }\r
1677 \r
1678         LockList(c->L3SwList);\r
1679         {\r
1680                 s = L3GetSw(c, name);\r
1681 \r
1682                 if (s != NULL)\r
1683                 {\r
1684                         // 停止して削除\r
1685                         L3SwStop(s);\r
1686                         Delete(c->L3SwList, s);\r
1687                         ReleaseL3Sw(s);\r
1688                         ReleaseL3Sw(s);\r
1689 \r
1690                         ret = true;\r
1691                 }\r
1692         }\r
1693         UnlockList(c->L3SwList);\r
1694 \r
1695         return ret;\r
1696 }\r
1697 \r
1698 \r
1699 // ルーティングテーブルの削除\r
1700 bool L3DelTable(L3SW *s, L3TABLE *tbl)\r
1701 {\r
1702         bool ret = false;\r
1703         // 引数チェック\r
1704         if (s == NULL || tbl == NULL)\r
1705         {\r
1706                 return false;\r
1707         }\r
1708 \r
1709         Lock(s->lock);\r
1710         {\r
1711                 if (s->Active == false)\r
1712                 {\r
1713                         L3TABLE *t = Search(s->TableList, tbl);\r
1714 \r
1715                         if (t != NULL)\r
1716                         {\r
1717                                 Delete(s->TableList, t);\r
1718                                 Free(t);\r
1719 \r
1720                                 ret = true;\r
1721                         }\r
1722                 }\r
1723         }\r
1724         Unlock(s->lock);\r
1725 \r
1726         return ret;\r
1727 }\r
1728 \r
1729 // ルーティングテーブルの追加\r
1730 bool L3AddTable(L3SW *s, L3TABLE *tbl)\r
1731 {\r
1732         bool ret = false;\r
1733         // 引数チェック\r
1734         if (s == NULL || tbl == NULL)\r
1735         {\r
1736                 return false;\r
1737         }\r
1738 \r
1739         if (tbl->Metric == 0 || tbl->GatewayAddress == 0 || tbl->GatewayAddress == 0xffffffff)\r
1740         {\r
1741                 return false;\r
1742         }\r
1743 \r
1744         Lock(s->lock);\r
1745         {\r
1746                 if (LIST_NUM(s->TableList) >= GetServerCapsInt(s->Cedar->Server, "i_max_l3_table"))\r
1747                 {\r
1748                         // 数が多すぎる\r
1749                 }\r
1750                 else\r
1751                 {\r
1752                         // 作成\r
1753                         if (s->Active == false)\r
1754                         {\r
1755                                 if (Search(s->TableList, tbl) == NULL)\r
1756                                 {\r
1757                                         L3TABLE *t = ZeroMalloc(sizeof(L3TABLE));\r
1758 \r
1759                                         Copy(t, tbl, sizeof(L3TABLE));\r
1760 \r
1761                                         Insert(s->TableList, t);\r
1762 \r
1763                                         ret = true;\r
1764                                 }\r
1765                         }\r
1766                 }\r
1767         }\r
1768         Unlock(s->lock);\r
1769 \r
1770         return ret;\r
1771 }\r
1772 \r
1773 // L3 スイッチを取得する\r
1774 L3SW *L3GetSw(CEDAR *c, char *name)\r
1775 {\r
1776         L3SW t, *s;\r
1777         // 引数チェック\r
1778         if (c == NULL || name == NULL)\r
1779         {\r
1780                 return NULL;\r
1781         }\r
1782 \r
1783         Zero(&t, sizeof(t));\r
1784         StrCpy(t.Name, sizeof(t.Name), name);\r
1785 \r
1786         LockList(c->L3SwList);\r
1787         {\r
1788                 s = Search(c->L3SwList, &t);\r
1789         }\r
1790         UnlockList(c->L3SwList);\r
1791 \r
1792         if (s != NULL)\r
1793         {\r
1794                 AddRef(s->ref);\r
1795         }\r
1796 \r
1797         return s;\r
1798 }\r
1799 \r
1800 // L3 スイッチから指定した仮想 HUB に接続されているインターフェイスを取得する\r
1801 L3IF *L3SearchIf(L3SW *s, char *hubname)\r
1802 {\r
1803         L3IF t, *f;\r
1804         // 引数チェック\r
1805         if (s == NULL || hubname == NULL)\r
1806         {\r
1807                 return NULL;\r
1808         }\r
1809 \r
1810         Zero(&t, sizeof(t));\r
1811         StrCpy(t.HubName, sizeof(t.HubName), hubname);\r
1812 \r
1813         f = Search(s->IfList, &t);\r
1814 \r
1815         return f;\r
1816 }\r
1817 \r
1818 // インターフェイスの削除\r
1819 bool L3DelIf(L3SW *s, char *hubname)\r
1820 {\r
1821         L3IF *f;\r
1822         bool ret = false;\r
1823         // 引数チェック\r
1824         if (s == NULL || hubname == NULL)\r
1825         {\r
1826                 return false;\r
1827         }\r
1828 \r
1829         Lock(s->lock);\r
1830         {\r
1831                 if (s->Active == false)\r
1832                 {\r
1833                         f = L3SearchIf(s, hubname);\r
1834 \r
1835                         if (f != NULL)\r
1836                         {\r
1837                                 // 削除する\r
1838                                 Delete(s->IfList, f);\r
1839                                 Free(f);\r
1840 \r
1841                                 ret = true;\r
1842                         }\r
1843                 }\r
1844         }\r
1845         Unlock(s->lock);\r
1846 \r
1847         return ret;\r
1848 }\r
1849 \r
1850 // インターフェイスの追加\r
1851 bool L3AddIf(L3SW *s, char *hubname, UINT ip, UINT subnet)\r
1852 {\r
1853         L3IF *f;\r
1854         bool ret = false;\r
1855         // 引数チェック\r
1856         if (s == NULL || hubname == NULL || IsSafeStr(hubname) == false ||\r
1857                 ip == 0 || ip == 0xffffffff)\r
1858         {\r
1859                 return false;\r
1860         }\r
1861 \r
1862         Lock(s->lock);\r
1863         {\r
1864                 if (LIST_NUM(s->TableList) >= GetServerCapsInt(s->Cedar->Server, "i_max_l3_if"))\r
1865                 {\r
1866                         // 数が多すぎる\r
1867                 }\r
1868                 else\r
1869                 {\r
1870                         if (s->Active == false)\r
1871                         {\r
1872                                 // 同じ仮想 HUB にすでにインターフェイスが入っていないかどうか調べる\r
1873                                 if (L3SearchIf(s, hubname) == NULL)\r
1874                                 {\r
1875                                         // 追加\r
1876                                         f = ZeroMalloc(sizeof(L3IF));\r
1877 \r
1878                                         f->Switch = s;\r
1879                                         StrCpy(f->HubName, sizeof(f->HubName), hubname);\r
1880                                         f->IpAddress = ip;\r
1881                                         f->SubnetMask = subnet;\r
1882 \r
1883                                         Insert(s->IfList, f);\r
1884 \r
1885                                         ret = true;\r
1886                                 }\r
1887                         }\r
1888                 }\r
1889         }\r
1890         Unlock(s->lock);\r
1891 \r
1892         return ret;\r
1893 }\r
1894 \r
1895 // L3 スイッチのクリーンアップ\r
1896 void CleanupL3Sw(L3SW *s)\r
1897 {\r
1898         UINT i;\r
1899         // 引数チェック\r
1900         if (s == NULL)\r
1901         {\r
1902                 return;\r
1903         }\r
1904 \r
1905         for (i = 0;i < LIST_NUM(s->IfList);i++)\r
1906         {\r
1907                 L3IF *f = LIST_DATA(s->IfList, i);\r
1908                 Free(f);\r
1909         }\r
1910         ReleaseList(s->IfList);\r
1911 \r
1912         for (i = 0;i < LIST_NUM(s->TableList);i++)\r
1913         {\r
1914                 L3TABLE *t = LIST_DATA(s->TableList, i);\r
1915                 Free(t);\r
1916         }\r
1917         ReleaseList(s->TableList);\r
1918 \r
1919         DeleteLock(s->lock);\r
1920         Free(s);\r
1921 }\r
1922 \r
1923 // L3 スイッチの解放\r
1924 void ReleaseL3Sw(L3SW *s)\r
1925 {\r
1926         // 引数チェック\r
1927         if (s == NULL)\r
1928         {\r
1929                 return;\r
1930         }\r
1931 \r
1932         if (Release(s->ref) == 0)\r
1933         {\r
1934                 CleanupL3Sw(s);\r
1935         }\r
1936 }\r
1937 \r
1938 // 新しい L3 スイッチを作成する\r
1939 L3SW *NewL3Sw(CEDAR *c, char *name)\r
1940 {\r
1941         L3SW *o;\r
1942         // 引数チェック\r
1943         if (c == NULL || name == NULL)\r
1944         {\r
1945                 return NULL;\r
1946         }\r
1947 \r
1948         o = ZeroMalloc(sizeof(L3SW));\r
1949 \r
1950         StrCpy(o->Name, sizeof(o->Name), name);\r
1951 \r
1952         o->lock = NewLock();\r
1953         o->ref = NewRef();\r
1954         o->Cedar = c;\r
1955         o->Active = false;\r
1956 \r
1957         o->IfList = NewList(CmpL3If);\r
1958         o->TableList = NewList(CmpL3Table);\r
1959 \r
1960         return o;\r
1961 }\r
1962 \r
1963 // Cedar にあるすべての L3 スイッチを停止する\r
1964 void L3FreeAllSw(CEDAR *c)\r
1965 {\r
1966         LIST *o;\r
1967         UINT i;\r
1968         // 引数チェック\r
1969         if (c == NULL)\r
1970         {\r
1971                 return;\r
1972         }\r
1973 \r
1974         o = NewListFast(NULL);\r
1975 \r
1976         LockList(c->L3SwList);\r
1977         {\r
1978                 for (i = 0;i < LIST_NUM(c->L3SwList);i++)\r
1979                 {\r
1980                         L3SW *s = LIST_DATA(c->L3SwList, i);\r
1981                         Insert(o, CopyStr(s->Name));\r
1982                 }\r
1983 \r
1984                 for (i = 0;i < LIST_NUM(o);i++)\r
1985                 {\r
1986                         char *name = LIST_DATA(o, i);\r
1987 \r
1988                         L3DelSw(c, name);\r
1989 \r
1990                         Free(name);\r
1991                 }\r
1992 \r
1993                 ReleaseList(o);\r
1994         }\r
1995         UnlockList(c->L3SwList);\r
1996 }\r
1997 \r
1998 // Cedar の L3 スイッチ機能を停止する\r
1999 void FreeCedarLayer3(CEDAR *c)\r
2000 {\r
2001         // 引数チェック\r
2002         if (c == NULL)\r
2003         {\r
2004                 return;\r
2005         }\r
2006 \r
2007         ReleaseList(c->L3SwList);\r
2008         c->L3SwList = NULL;\r
2009 }\r
2010 \r
2011 // Cedar の L3 スイッチ機能を開始する\r
2012 void InitCedarLayer3(CEDAR *c)\r
2013 {\r
2014         // 引数チェック\r
2015         if (c == NULL)\r
2016         {\r
2017                 return;\r
2018         }\r
2019 \r
2020         c->L3SwList = NewList(CmpL3Sw);\r
2021 }\r
2022 \r
2023 // インターフェイス比較関数\r
2024 int CmpL3If(void *p1, void *p2)\r
2025 {\r
2026         L3IF *f1, *f2;\r
2027         if (p1 == NULL || p2 == NULL)\r
2028         {\r
2029                 return 0;\r
2030         }\r
2031         f1 = *(L3IF **)p1;\r
2032         f2 = *(L3IF **)p2;\r
2033         if (f1 == NULL || f2 == NULL)\r
2034         {\r
2035                 return 0;\r
2036         }\r
2037 \r
2038         return StrCmpi(f1->HubName, f2->HubName);\r
2039 }\r
2040 \r
2041 // ルーティングテーブル比較関数\r
2042 int CmpL3Table(void *p1, void *p2)\r
2043 {\r
2044         L3TABLE *t1, *t2;\r
2045         if (p1 == NULL || p2 == NULL)\r
2046         {\r
2047                 return 0;\r
2048         }\r
2049         t1 = *(L3TABLE **)p1;\r
2050         t2 = *(L3TABLE **)p2;\r
2051         if (t1 == NULL || t2 == NULL)\r
2052         {\r
2053                 return 0;\r
2054         }\r
2055 \r
2056         if (t1->NetworkAddress > t2->NetworkAddress)\r
2057         {\r
2058                 return 1;\r
2059         }\r
2060         else if (t1->NetworkAddress < t2->NetworkAddress)\r
2061         {\r
2062                 return -1;\r
2063         }\r
2064         else if (t1->SubnetMask > t2->SubnetMask)\r
2065         {\r
2066                 return 1;\r
2067         }\r
2068         else if (t1->SubnetMask < t2->SubnetMask)\r
2069         {\r
2070                 return -1;\r
2071         }\r
2072         else if (t1->GatewayAddress > t2->GatewayAddress)\r
2073         {\r
2074                 return 1;\r
2075         }\r
2076         else if (t1->GatewayAddress < t2->GatewayAddress)\r
2077         {\r
2078                 return -1;\r
2079         }\r
2080         else if (t1->Metric > t2->Metric)\r
2081         {\r
2082                 return 1;\r
2083         }\r
2084         else if (t1->Metric < t2->Metric)\r
2085         {\r
2086                 return -1;\r
2087         }\r
2088         else\r
2089         {\r
2090                 return 0;\r
2091         }\r
2092 }\r
2093 \r
2094 // L3SW 比較関数\r
2095 int CmpL3Sw(void *p1, void *p2)\r
2096 {\r
2097         L3SW *s1, *s2;\r
2098         if (p1 == NULL || p2 == NULL)\r
2099         {\r
2100                 return 0;\r
2101         }\r
2102         s1 = *(L3SW **)p1;\r
2103         s2 = *(L3SW **)p2;\r
2104         if (s1 == NULL || s2 == NULL)\r
2105         {\r
2106                 return 0;\r
2107         }\r
2108 \r
2109         return StrCmpi(s1->Name, s2->Name);\r
2110 }\r
2111 \r
2112 // ARP 待機エントリ比較関数\r
2113 int CmpL3ArpWaitTable(void *p1, void *p2)\r
2114 {\r
2115         L3ARPWAIT *w1, *w2;\r
2116         if (p1 == NULL || p2 == NULL)\r
2117         {\r
2118                 return 0;\r
2119         }\r
2120         w1 = *(L3ARPWAIT **)p1;\r
2121         w2 = *(L3ARPWAIT **)p2;\r
2122         if (w1 == NULL || w2 == NULL)\r
2123         {\r
2124                 return 0;\r
2125         }\r
2126         if (w1->IpAddress > w2->IpAddress)\r
2127         {\r
2128                 return 1;\r
2129         }\r
2130         else if (w1->IpAddress < w2->IpAddress)\r
2131         {\r
2132                 return -1;\r
2133         }\r
2134         else\r
2135         {\r
2136                 return 0;\r
2137         }\r
2138 }\r
2139 \r
2140 // ARP エントリ比較関数\r
2141 int CmpL3ArpEntry(void *p1, void *p2)\r
2142 {\r
2143         L3ARPENTRY *e1, *e2;\r
2144         if (p1 == NULL || p2 == NULL)\r
2145         {\r
2146                 return 0;\r
2147         }\r
2148         e1 = *(L3ARPENTRY **)p1;\r
2149         e2 = *(L3ARPENTRY **)p2;\r
2150         if (e1 == NULL || e2 == NULL)\r
2151         {\r
2152                 return 0;\r
2153         }\r
2154         if (e1->IpAddress > e2->IpAddress)\r
2155         {\r
2156                 return 1;\r
2157         }\r
2158         else if (e1->IpAddress < e2->IpAddress)\r
2159         {\r
2160                 return -1;\r
2161         }\r
2162         else\r
2163         {\r
2164                 return 0;\r
2165         }\r
2166 }\r
2167 \r