source: EcnlProtoTool/trunk/asp3_dcre/tinet/netapp/dhcp6_cli.c@ 331

Last change on this file since 331 was 331, checked in by coas-nagasima, 6 years ago

prototoolに関連するプロジェクトをnewlibからmuslを使うよう変更・更新
ntshellをnewlibの下位の実装から、muslのsyscallの実装に変更・更新
以下のOSSをアップデート
・mruby-1.3.0
・musl-1.1.18
・onigmo-6.1.3
・tcc-0.9.27
以下のOSSを追加
・openssl-1.1.0e
・curl-7.57.0
・zlib-1.2.11
以下のmrbgemsを追加
・iij/mruby-digest
・iij/mruby-env
・iij/mruby-errno
・iij/mruby-iijson
・iij/mruby-ipaddr
・iij/mruby-mock
・iij/mruby-require
・iij/mruby-tls-openssl

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc
File size: 87.2 KB
Line 
1/*
2 * Copyright (c) 2004-2011 by Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (c) 1995-2003 by Internet Software Consortium
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 *
17 * Internet Systems Consortium, Inc.
18 * 950 Charter Street
19 * Redwood City, CA 94063
20 * <info@isc.org>
21 * https://www.isc.org/
22 *
23 * This code is based on the original client state machine that was
24 * written by Elliot Poger. The code has been extensively hacked on
25 * by Ted Lemon since then, so any mistakes you find are probably his
26 * fault and not Elliot's.
27 */
28/*
29 * WIDE Project DHCP Implementation
30 * Copyright (c) 1995-1997 Akihiro Tominaga
31 * Copyright (c) 1995-1997 WIDE Project
32 * All rights reserved.
33 *
34 * Permission to use, copy, modify and distribute this software and its
35 * documentation is hereby granted, provided the following conditions
36 * are satisfied,
37 *
38 * 1. Both the copyright notice and this permission notice appear in
39 * all copies of the software, derivative works or modified versions,
40 * and any portions thereof, and that both notices appear in
41 * supporting documentation.
42 * 2. All advertising materials mentioning features or use of this software
43 * must display the following acknowledgement:
44 * This product includes software developed by WIDE Project and
45 * its contributors.
46 * 3. Neither the name of WIDE Project nor the names of its contributors
47 * may be used to endorse or promote products derived from this software
48 * without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND WIDE
51 * PROJECT DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
52 * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ALSO, THERE
53 * IS NO WARRANTY IMPLIED OR OTHERWISE, NOR IS SUPPORT PROVIDED.
54 *
55 * Feedback of the results generated from any improvements or
56 * extensions made to this software would be much appreciated.
57 * Any such feedback should be sent to:
58 *
59 * Akihiro Tominaga
60 * WIDE Project
61 * Keio University, Endo 5322, Kanagawa, Japan
62 * (E-mail: dhcp-dist@wide.ad.jp)
63 *
64 * WIDE project has the rights to redistribute these changes.
65 */
66/*
67 * TINET (TCP/IP Protocol Stack)
68 *
69 * Copyright (C) 2011 by Dep. of Computer Science and Engineering
70 * Tomakomai National College of Technology, JAPAN
71 *
72 * 上記著作権者
73は,以下の (1)~(4) の条件か,Free Software Foundation
74 * によってå…
75¬è¡¨ã•ã‚Œã¦ã„ã‚‹ GNU General Public License の Version 2 に記
76 * 述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア
77 * を改変したものを含む.以下同じ)を使用・複製・改変・再é…
78å¸ƒï¼ˆä»¥ä¸‹ï¼Œ
79 * 利用と呼ぶ)することを無償で許諾する.
80 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
81 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
82 * スコード中に含まれていること.
83 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
84 * 用できる形で再é…
85å¸ƒã™ã‚‹å ´åˆã«ã¯ï¼Œå†é…
86å¸ƒã«ä¼´ã†ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆï¼ˆåˆ©ç”¨
87 * 者
88マニュアルなど)に,上記の著作権表示,この利用条件および下記
89 * の無保証規定を掲載すること.
90 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
91 * 用できない形で再é…
92å¸ƒã™ã‚‹å ´åˆã«ã¯ï¼Œæ¬¡ã®ã„ずれかの条件を満たすこ
93 * と.
94 * (a) 再é…
95å¸ƒã«ä¼´ã†ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆï¼ˆåˆ©ç”¨è€…
96マニュアルなど)に,上記の著
97 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
98 * (b) 再é…
99å¸ƒã®å½¢æ…
100‹ã‚’,別に定める方法によって,TOPPERSプロジェクトに
101 * 報告すること.
102 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
103 * 害からも,上記著作権者
104およびTOPPERSプロジェクトをå…
105è²¬ã™ã‚‹ã“と.
106 *
107 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者
108お
109 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も
110 * 含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直
111 * 接的または間接的に生じたいかなる損害に関しても,その責任を負わない.
112 *
113 * @(#) $Id$
114 */
115
116#include <string.h>
117
118#ifdef TARGET_KERNEL_ASP
119
120#include <kernel.h>
121#include <sil.h>
122#include <t_syslog.h>
123#include "kernel_cfg.h"
124
125#endif /* of #ifdef TARGET_KERNEL_ASP */
126
127#ifdef TARGET_KERNEL_JSP
128
129#include <s_services.h>
130#include <t_services.h>
131#include "kernel_id.h"
132
133#endif /* of #ifdef TARGET_KERNEL_JSP */
134
135#include <tinet_defs.h>
136#include <tinet_config.h>
137
138#include <net/if.h>
139#include <net/ethernet.h>
140#include <net/net.h>
141#include <net/net_endian.h>
142#include <net/net_var.h>
143#include <net/net_timer.h>
144
145#include <netinet/in.h>
146#include <netinet/in_var.h>
147#include <netinet/in_itron.h>
148
149#include <net/if_var.h>
150
151#include <netapp/netapp.h>
152#include <netapp/netapp_var.h>
153#include <netapp/dhcp6_cli.h>
154#include <netapp/dhcp6_cli_var.h>
155#include <netapp/resolver.h>
156
157/*
158 * DHCPv6 クライアントタスク
159 */
160
161#ifdef DHCP6_CLI_CFG
162
163/*
164 * DHCP 動作モード
165 *
166 * #define DHCP6_CLI_CFG_MODE で指定する。
167 *
168 */
169
170#if !defined(DHCP6_CLI_CFG_MODE)
171#define DHCP6_CLI_CFG_MODE DHCP6_CLI_CFG_MODE_DEFAULT
172#endif
173
174/*
175 * 変数
176 */
177
178static const T_IN6_ADDR in6_addr_all_DHCP_relay_servers =
179 IPV6_ADDR_ALL_DHCP_RELAY_SERVERS_INIT; /* リレー・サーバの IPv6 アドレス */
180static T_DHCP6_CLI_CONTEXT context; /* クライアントコンテキスト */
181
182#ifdef DHCP6_CLI_CFG_REQUIRED_OLIST
183static uint8_t required_plist[] = DHCP6_CLI_CFG_REQUIRED_OLIST; /* 必
184須オプションリスト */
185#endif
186
187#ifdef DHCP6_CLI_CFG_REQUEST_OLIST
188static uint8_t request_plist[] = DHCP6_CLI_CFG_REQUEST_OLIST; /* 要求オプションリスト */
189#endif
190
191/*
192 * dhcp6_rand -- RFC3315 に規定された乱数を発生する。
193 */
194
195static int32_t
196dhcp6_rand (SYSTIM base)
197{
198 SYSTIM range, split;
199 uint32_t rval;
200
201 split = (base - 1) / 10;
202 if (split == 0)
203 return 0;
204 range = (split * 2) + 10;
205 rval = netapp_rand() % range - split;
206
207 return rval;
208 }
209
210/*
211 * init_duid -- クライアントの DUID を設定する。
212 */
213
214static void
215init_duid (T_DHCP6_CLI_CONTEXT *ct)
216{
217
218#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS
219
220 /* 動作モードに STATELESS が指定された時は LL 形式にする。*/
221
222 T_DHCP6_DUID_LL_HDR *ll;
223
224 ll = (T_DHCP6_DUID_LL_HDR*)&ct->duid[0];
225 HOST2MSG16(ll->code, DUID_LL);
226 HOST2MSG16(ll->type, DHCP6_HWA_TYPE_ETHER);
227 memcpy(&ct->duid[sizeof(*ll)], &ct->sc->ifaddr.lladdr, sizeof(ct->sc->ifaddr.lladdr));
228 ct->duid_len = sizeof(*ll) + sizeof(ct->sc->ifaddr.lladdr); /* DIUD 長を記録する。*/
229
230#elif DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL
231
232 /*
233 * 動作モードに DHCP6_CLI_CFG_STATEFULL が指定された時は LLT 形式にする。
234 * time メンバーには現在の時間[s]を設定する。
235 * 注意: 暫定的に get_tim() の値を使うが、要検討
236 */
237
238 T_DHCP6_DUID_LLT_HDR *llt;
239 SYSTIM time;
240
241 get_tim(&time);
242 time = SYSTIM2SEC(time) - DUID_TIME_EPOCH;
243 llt = (T_DHCP6_DUID_LLT_HDR*)&ct->duid[0];
244 HOST2MSG16(llt->code, DUID_LLT);
245 HOST2MSG16(llt->type, DHCP6_HWA_TYPE_ETHER);
246 HOST2MSG32(llt->time, time);
247 memcpy(&ct->duid[sizeof(*llt)], &ct->sc->ifaddr.lladdr, sizeof(ct->sc->ifaddr.lladdr));
248 ct->duid_len = sizeof(*llt) + sizeof(ct->sc->ifaddr.lladdr); /* DIUD 長を記録する。*/
249
250#else /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS */
251
252#endif /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS */
253
254 }
255
256/*
257 * cancel_all_timers -- å…
258¨ã¦ã® TIMER をキャンセルする。
259 */
260
261static void
262cancel_all_timers (T_DHCP6_CLI_CONTEXT *ct)
263{
264 int ix;
265
266 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
267 for (ix = NUM_DHCP6C_TIMERS; ix -- > 0; )
268 ct->timers[ix] = 0;
269 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
270 }
271
272/*
273 * dhcpc_timer -- TIMER 管理
274 */
275
276static void
277dhcpc_timer (T_DHCP6_CLI_CONTEXT *ct)
278{
279 int ix;
280
281 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
282 for (ix = NUM_DHCP6C_TIMERS; ix -- > 0; ) {
283 if (ct->timers[ix] != 0) {
284 ct->timers[ix] --;
285 if (ct->timers[ix] == 0) {
286 ct->flags = (ct->flags & ~DHCP6C_FLAG_TMOUT_MASK) | DHCP6C_FLAG_TMOUT_TIMER | ix;
287 syscall(sig_sem(SEM_DHCP6_CLI_READY));
288 }
289 }
290 }
291 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
292
293 /* 1秒毎にタイムアウトする。*/
294 timeout((callout_func)dhcpc_timer, ct, NET_TIMER_HZ / DHCP6C_TIMER_HZ);
295 }
296
297/*
298 * find_option -- 指定したオプションを探索する。
299 *
300 * 注意: 引数 len が 0 の時はオプションサイズを検証しない。
301 * 引数 len にはオプションå…
302¨ä½“のサイズを指定すること。
303 */
304
305static uint8_t *
306find_option (uint8_t *msg, uint_t msg_len, uint_t code, uint_t len)
307{
308 T_DHCP6_OPTION *hdr;
309 uint8_t *last;
310
311 last = msg + msg_len;
312 while (msg < last) {
313 hdr = (T_DHCP6_OPTION*)msg;
314 if (MSG2HOST16(hdr->code) == code && (len == 0 || (MSG2HOST16(hdr->len) + sizeof(*hdr)) == len))
315 return msg;
316 else
317 msg += MSG2HOST16(hdr->len) + sizeof(*hdr);
318 }
319 return NULL;
320 }
321
322/*
323 * find_msg_option -- 指定したオプションを探索する。
324 *
325 * 注意: 引数 len が 0 の時はオプションサイズを検証しない。
326 * 引数 len にはオプションå…
327¨ä½“のサイズを指定すること。
328 */
329
330static uint8_t *
331find_msg_option (T_DHCP6_CLI_MSG *cli_msg, uint_t code, uint_t len)
332{
333 return find_option(cli_msg->msg.options, cli_msg->len, code, len);
334 }
335
336/*
337 * is_equal_sid -- メッセージ内
338の SERVER ID を比較する。
339 */
340
341static bool_t
342is_equal_sid (T_DHCP6_CLI_MSG *msg1, T_DHCP6_CLI_MSG *msg2)
343{
344 T_DHCP6_OPT_SERVERID *sid1;
345 T_DHCP6_OPT_SERVERID *sid2;
346
347 if ((sid1 = (T_DHCP6_OPT_SERVERID*)find_msg_option(msg1, DHCP6_OPT_SERVERID, 0)) == NULL)
348 return false;
349 if ((sid2 = (T_DHCP6_OPT_SERVERID*)find_msg_option(msg2, DHCP6_OPT_SERVERID, 0)) == NULL)
350 return false;
351 if (MSG2HOST16(sid1->len) != MSG2HOST16(sid2->len))
352 return false;
353
354 return memcmp((uint8_t*)sid1 + sizeof(*sid1),
355 (uint8_t*)sid2 + sizeof(*sid2), MSG2HOST16(sid1->len)) == 0;
356 }
357
358/*
359 * validate_iaaddrs -- アドレス情
360報(IAADDR)を検証する。
361 */
362
363static ER
364validate_iaaddrs (uint8_t *opt, uint_t len)
365{
366 T_DHCP6_OPT_IAADDR *iaa;
367
368 /* オプションが IAADDR であることを検証する。*/
369 iaa = (T_DHCP6_OPT_IAADDR*)opt;
370 if (MSG2HOST16(iaa->code) != DHCP6_OPT_IAADDR)
371 return E_PAR;
372
373 while (len > 0) {
374 /* オプション長を検証する。*/
375 if (len < sizeof(*iaa))
376 return E_PAR;
377
378 /* オプション長が T_DHCP6_OPT_IAADDR のサイズと一致していなければエラー */
379 iaa = (T_DHCP6_OPT_IAADDR*)opt;
380 if ((MSG2HOST16(iaa->len) & ~DHCP6C_IAA_FLAG_MASK) < (sizeof(*iaa) - sizeof(T_DHCP6_OPTION)))
381 return E_PAR;
382
383 /*
384 * perferred-lifetime と valid-lifetime の値が矛盾しているときはエラー
385 * 【RFC3315 (22.6) 参ç…
386§ã€‘
387 */
388 if (MSG2HOST32(iaa->prefer) > MSG2HOST32(iaa->valid))
389 return E_PAR;
390
391 len -= (MSG2HOST16(iaa->len) & ~DHCP6C_IAA_FLAG_MASK) + sizeof(T_DHCP6_OPTION);
392 opt += (MSG2HOST16(iaa->len) & ~DHCP6C_IAA_FLAG_MASK) + sizeof(T_DHCP6_OPTION);
393 }
394
395 return E_OK;
396 }
397
398/*
399 * validate_ia_na_pd -- IA_NA/IA_PD オプションを検証する。
400 */
401
402static ER
403validate_ia_na_pd (T_DHCP6_CLI_MSG *msg, uint16_t code)
404{
405 T_DHCP6_OPT_IA_NA_PD *na;
406 uint8_t *opt;
407
408 /* IA_NA/IA_PD が無ければ検証しない。*/
409 if ((opt = find_msg_option(msg, code, 0)) == NULL)
410 return E_OK;
411
412 /* オプション長を検証する。*/
413 na = (T_DHCP6_OPT_IA_NA_PD*)opt;
414 if (!(msg->len >= (opt - (uint8_t*)&msg->msg) + sizeof(*na) &&
415 (MSG2HOST16(na->len) & ~DHCP6C_IAA_FLAG_MASK) >= sizeof(*na)))
416 return E_PAR;
417
418 /*
419 * T1 と T2 の値が矛盾している時、またはアドレス情
420報が誤っている時はエラー
421 * 【RFC3315 (22.4) 参ç…
422§ã€‘
423 */
424 if (MSG2HOST32(na->renew) > 0 && MSG2HOST32(na->rebind) > 0 &&
425 MSG2HOST32(na->renew) > MSG2HOST32(na->rebind))
426 return E_PAR;
427
428 if (validate_iaaddrs(opt + sizeof(*na), (MSG2HOST16(na->len) & ~DHCP6C_IAA_FLAG_MASK) - (sizeof(*na) - sizeof(T_DHCP6_OPTION))) != E_OK)
429 return E_PAR;
430
431 return E_OK;
432 }
433
434/*
435 * validate_ia_ta -- IA_TA オプションを検証する。
436 */
437
438static ER
439validate_ia_ta (T_DHCP6_CLI_MSG *msg)
440{
441 T_DHCP6_OPT_IA_TA *ta;
442 uint8_t *opt;
443
444 /* IA_TA が無ければ検証しない。*/
445 if ((opt = find_msg_option(msg, DHCP6_OPT_IA_TA, 0)) == NULL)
446 return E_OK;
447
448 /* オプション長を検証する。*/
449 ta = (T_DHCP6_OPT_IA_TA *)opt;
450 if (!(msg->len >= (opt - (uint8_t*)&msg->msg) + sizeof(*ta) &&
451 (MSG2HOST16(ta->len) & ~DHCP6C_IAA_FLAG_MASK) >= sizeof(*ta)))
452 return E_PAR;
453
454 /*
455 * アドレス情
456報が誤っている時はエラー【RFC3315 (22.4) 参ç…
457§ã€‘
458 */
459 if (validate_iaaddrs(opt + sizeof(*ta), (MSG2HOST16(ta->len) & ~DHCP6C_IAA_FLAG_MASK) - (sizeof(*ta) - sizeof(T_DHCP6_OPTION))) != E_OK)
460 return E_PAR;
461
462 return E_OK;
463 }
464/*
465 * classify_reply -- 応答メッセージを分類する。
466 */
467
468static ER
469classify_reply (T_DHCP6_CLI_MSG *msg)
470{
471 ER error;
472
473 /* IA_NA オプションを検証する。*/
474 if ((error = validate_ia_na_pd(msg, DHCP6_OPT_IA_NA)) != E_OK)
475 return error;
476
477 /* IA_TA オプションを検証する。*/
478 if ((error = validate_ia_ta(msg)) != E_OK)
479 return error;
480
481 /* IA_PD オプションを検証する。*/
482 if ((error = validate_ia_na_pd(msg, DHCP6_OPT_IA_PD)) != E_OK)
483 return error;
484
485 /* サーバ DUID があることを検証する。*/
486 if (find_msg_option(msg, DHCP6_OPT_SERVERID, 0) == NULL)
487 return E_PAR;
488
489 return E_OK;
490 }
491
492/*
493 * validate_reply -- 応答メッセージを検証する。
494 */
495
496static ER
497validate_reply (T_DHCP6_CLI_CONTEXT *ct, T_DHCP6_CLI_MSG *msg)
498{
499 T_DHCP6_OPT_CLIENTID *cid;
500 uint8_t *opt;
501
502 /* サーバ DUID があることを検証する。*/
503 if (find_msg_option(msg, DHCP6_OPT_SERVERID, 0) == NULL)
504 return E_PAR;
505
506 /* クライアント DUID があり、自分のクライアント DUID と同じことを検証する。*/
507 if ((opt = find_msg_option(msg, DHCP6_OPT_CLIENTID, 0)) == NULL)
508 return E_PAR;
509
510 cid = (T_DHCP6_OPT_CLIENTID*)opt;
511 if (MSG2HOST16(cid->len) != ct->duid_len)
512 return E_PAR;
513 if (memcmp(opt + sizeof(*cid), ct->duid, ct->duid_len) != 0)
514 return E_PAR;
515
516 return E_OK;
517 }
518
519/*
520 * get_status_code -- STATUS オプションの結果コードを獲得する。
521 */
522
523static ER_UINT
524get_status_code (uint8_t *msg, uint_t msg_len)
525{
526 T_DHCP6_OPT_STATUS_CODE *status;
527 uint8_t *opt;
528
529 /* STATUS オプションが無ければ検証しない。*/
530 if ((opt = find_option(msg, msg_len, DHCP6_OPT_STATUS_CODE, 0)) == NULL)
531 return DHCP6_STAT_SUCCESS;
532
533 /* オプション長を検証する。*/
534 status = (T_DHCP6_OPT_STATUS_CODE*)opt;
535 if (msg_len < sizeof(*status))
536 return E_PAR;
537 if (MSG2HOST16(status->len) < sizeof(*status) - sizeof(T_DHCP6_OPTION))
538 return E_PAR;
539
540 return MSG2HOST16(status->status);
541 }
542
543/*
544 * get_msg_status_code -- STATUS オプションの結果コードを獲得する。
545 */
546
547static ER_UINT
548get_msg_status_code (T_DHCP6_CLI_MSG *cli_msg, uint_t *code)
549{
550 T_DHCP6_OPTION *opt;
551 T_DHCP6_OPT_IA_NA_PD *ia;
552 T_DHCP6_OPT_IA_TA *ta;
553 ER_UINT status;
554 uint8_t *msg, *last;
555
556 *code = 0;
557 cli_msg->status = DHCP6_CLI_STAT_UNDEFINED;
558 if ((status = get_status_code(cli_msg->msg.options, cli_msg->len)) == DHCP6_STAT_SUCCESS) {
559
560 msg = cli_msg->msg.options;
561 last = msg + (cli_msg->len - sizeof(T_DHCP6_MSG_HDR));
562 while (msg < last) {
563
564 opt = (T_DHCP6_OPTION*)msg;
565 status = get_status_code(msg + sizeof(*opt), MSG2HOST16(opt->len));
566 if (status != DHCP6_STAT_SUCCESS) {
567 *code = MSG2HOST16(opt->code);
568 break;
569 }
570
571 if (MSG2HOST16(opt->code) == DHCP6_OPT_IA_NA || MSG2HOST16(opt->code) == DHCP6_OPT_IA_PD) {
572
573 ia = (T_DHCP6_OPT_IA_NA_PD*)opt;
574 status = get_status_code(msg + sizeof(*opt), MSG2HOST16(ia->len));
575 if (status != DHCP6_STAT_SUCCESS) {
576 *code = MSG2HOST16(((T_DHCP6_OPTION*)((uint8_t*)opt + sizeof(*opt)))->code);
577 break;
578 }
579 }
580
581 else if (MSG2HOST16(opt->code) == DHCP6_OPT_IA_TA) {
582
583 ta = (T_DHCP6_OPT_IA_TA*)opt;
584 status = get_status_code(msg + sizeof(*opt), MSG2HOST16(ta->len));
585 if (status != DHCP6_STAT_SUCCESS) {
586 *code = MSG2HOST16(((T_DHCP6_OPTION*)((uint8_t*)opt + sizeof(*opt)))->code);
587 break;
588 }
589 }
590
591 msg += MSG2HOST16(opt->len) + sizeof(*opt);
592 }
593 cli_msg->status = status;
594 }
595
596 return status;
597 }
598
599/*
600 * validate_rcv_msg -- 受信メッセージを検証する。
601 */
602
603static ER
604validate_rcv_msg (T_DHCP6_CLI_CONTEXT *ct, T_DHCP6_CLI_MSG *msg)
605{
606 ER error;
607 uint_t code;
608
609 /* メッセージのタイプが一致していることを検証する。*/
610 switch (ct->fsm) {
611
612#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS || DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_RA
613
614 case DHCP6_FSM_SELECT:
615 if (msg->msg.hdr.type != DHCP6_REPLY)
616 return E_PAR;
617 break;
618 case DHCP6_FSM_INFORMED:
619 return E_PAR;
620 break;
621
622#endif /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS || DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_RA */
623
624#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL || DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_RA
625
626 case DHCP6_FSM_INIT:
627 if (msg->msg.hdr.type != DHCP6_ADVERTISE)
628 return E_PAR;
629 break;
630
631 case DHCP6_FSM_SELECT:
632 case DHCP6_FSM_RENEW:
633 case DHCP6_FSM_REBIND:
634 case DHCP6_FSM_REL_INFO:
635 if (msg->msg.hdr.type != DHCP6_REPLY)
636 return E_PAR;
637 break;
638
639 case DHCP6_FSM_BOUND:
640 return E_PAR;
641 break;
642
643#endif /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL || DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_RA */
644
645 default:
646 syslog(LOG_NOTICE, "[DHCP6C] error, unknown state: %d.", ct->fsm);
647 return E_PAR;
648 break;
649 }
650
651 /* 受信メッセージを検証する。*/
652 if ((error = validate_reply(ct, msg)) != E_OK)
653 return error;
654
655 /* 受信メッセージを分類する。*/
656 if ((error = classify_reply(msg)) != E_OK)
657 return error;
658
659 /* 受信したメッセージ内
660の STATUS CODE オプションを検証する。*/
661 error = get_msg_status_code(msg, &code);
662 if (error != E_OK)
663 return error > 0 ? E_PAR : error;
664
665 return E_OK;
666 }
667
668/*
669 * eval_ia_prefer -- IA_NA/IA_TA/IA_PD の推奨度を評価する。
670 */
671
672static void
673eval_ia_prefer (T_DHCP6_CLI_MSG *cli_msg)
674{
675 T_DHCP6_OPTION *opt;
676 T_DHCP6_OPT_IA_NA_PD *ia;
677 T_DHCP6_OPT_IA_TA *ta;
678 T_DHCP6_OPT_IAADDR *iaa;
679 uint8_t *msg, *last;
680 uint_t aoff, asize;
681
682 /* 無効の場合は終了する。*/
683 if (cli_msg == NULL)
684 return;
685
686 msg = cli_msg->msg.options;
687 last = msg + (cli_msg->len - sizeof(T_DHCP6_MSG_HDR));
688 while (msg < last) {
689 opt = (T_DHCP6_OPTION*)msg;
690
691 if (MSG2HOST16(opt->code) == DHCP6_OPT_IA_NA || MSG2HOST16(opt->code) == DHCP6_OPT_IA_PD) {
692
693 ia = (T_DHCP6_OPT_IA_NA_PD*)opt;
694 aoff = sizeof(*ia);
695 asize = MSG2HOST16(ia->len) + sizeof(*opt);
696 while (aoff < asize) {
697 cli_msg->prefer += DHCP6_CLI_CFG_PREFER_IAADDR;
698 iaa = (T_DHCP6_OPT_IAADDR*)((uint8_t*)opt + aoff);
699 aoff += (MSG2HOST16(iaa->len) & ~DHCP6C_IAA_FLAG_MASK) + sizeof(*iaa);
700 }
701 cli_msg->prefer = (cli_msg->prefer + DHCP6_CLI_CFG_PREFER_IA) | DHCP6_ClI_MSG_PREFER_ADDR;
702 }
703
704 else if (MSG2HOST16(opt->code) == DHCP6_OPT_IA_TA) {
705
706 ta = (T_DHCP6_OPT_IA_TA*)opt;
707 aoff = sizeof(*ta);
708 asize = MSG2HOST16(ta->len) + sizeof(*opt);
709 while (aoff < asize) {
710 cli_msg->prefer += DHCP6_CLI_CFG_PREFER_IAADDR;
711 iaa = (T_DHCP6_OPT_IAADDR*)((uint8_t*)opt + aoff);
712 aoff += (MSG2HOST16(iaa->len) & ~DHCP6C_IAA_FLAG_MASK) + sizeof(*iaa);
713 }
714 cli_msg->prefer = (cli_msg->prefer + DHCP6_CLI_CFG_PREFER_IA) | DHCP6_ClI_MSG_PREFER_ADDR;
715 }
716
717 msg += MSG2HOST16(opt->len) + sizeof(*opt);
718 }
719
720 }
721
722/*
723 * eval_prefer -- 受信メッセージの推奨度を評価する。
724 */
725
726static void
727eval_prefer (T_DHCP6_CLI_MSG *msg)
728{
729 uint8_t *opt;
730 int ix;
731
732 /* 無効の場合は終了する。*/
733 if (msg == NULL)
734 return;
735
736 /* PREFERENCE オプションを評価する。*/
737 if ((opt = find_msg_option(msg, DHCP6_OPT_PREFERENCE, sizeof(T_DHCP6_OPT_PREFERENCE))) != NULL)
738 msg->prefer = MSG2HOST16(((T_DHCP6_OPT_PREFERENCE*)opt)->prefer) | DHCP6_ClI_MSG_PREFER_OPTION;
739 else
740 msg->prefer = 1;
741
742#if defined(DHCP6_CLI_CFG_REQUIRED_OLIST)
743
744 /* 必
745須オプションを検証する。*/
746 for (ix = sizeof(required_plist); ix -- > 0; ) {
747 if (find_msg_option(msg, required_plist[ix], 0) == NULL)
748 msg->prefer = 0;
749 }
750 msg->prefer |= DHCP6_ClI_MSG_PREFER_REQUIRED;
751
752#endif /* of #if defined(DHCP6_CLI_CFG_REQUIRED_OLIST) */
753
754#if defined(DHCP6_CLI_CFG_REQUEST_OLIST)
755
756 /* 要求オプションを検証する。*/
757 for (ix = sizeof(request_plist); ix -- > 0; ) {
758 if (find_msg_option(msg, request_plist[ix], 0) != NULL)
759 msg->prefer = (msg->prefer + 1) | DHCP6_ClI_MSG_PREFER_REQUEST;
760 }
761
762#endif /* of #if defined(DHCP6_CLI_CFG_REQUEST_OLIST) */
763 }
764
765/*
766 * eval_rcv_msg -- 受信メッセージを評価する。
767 */
768
769static ER
770eval_rcv_msg (T_DHCP6_CLI_CONTEXT *ct)
771{
772 T_DHCP6_CLI_MSG *evl, *msg;
773 SYSTIM time;
774
775 /* メッセージを受信していなければ中止する。*/
776 syscall(wai_sem(SEM_DHCP6_CLI_LOCK));
777 if (ct->val_lst == NULL) {
778 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
779 return E_OK;
780 }
781
782 /* 検証メッセージリストから評価メッセージを取り出す。*/
783 evl = ct->val_lst;
784 ct->val_lst = ct->val_lst->next;
785 evl->next = NULL;
786 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
787
788 /* 受信時間を設定する。*/
789 get_tim(&time);
790 evl->rcv_time = time;
791
792 /* 評価メッセージを検証する。*/
793 if (validate_rcv_msg(ct, evl) != E_OK) {
794
795 /* エラーが発生した評価メッセージを受信メッセージ構造体リストに戻す。*/
796 goto rcv_ret;
797 }
798
799 /* REL_INFO 状æ…
800‹ã®æ™‚の処理 */
801 if (ct->fsm == DHCP6_FSM_REL_INFO) {
802 syscall(wai_sem(SEM_DHCP6_CLI_LOCK));
803 if (evl->status == DHCP6_STAT_SUCCESS) {
804 /*
805 * STATUS CODE が DHCP6_STAT_SUCCESS なら、
806 * 評価メッセージを推奨メッセージリストに設定して終了する。
807 */
808 evl->next = ct->prf_lst;
809 ct->prf_lst = evl;
810 }
811 else {
812 /* 評価メッセージを受信メッセージ構造体リストに戻して終了する。*/
813 evl->next = ct->rcv_lst;
814 ct->rcv_lst = evl;
815 }
816 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
817 return E_OK;
818 }
819
820 /* 評価メッセージの推奨度を評価する。*/
821 eval_prefer(evl);
822 eval_ia_prefer(evl);
823
824 /* 推奨メッセージリストが空なら評価メッセージを移して終了する。*/
825 if (ct->prf_lst == NULL) {
826 ct->max_prefer = evl->prefer & DHCP6_ClI_MSG_PREFER_VALUE_MASK;
827 ct->prf_lst = evl;
828 return E_OK;
829 }
830
831 /* 評価メッセージの推奨度と推奨メッセージリストの最大推奨度を比較する。*/
832 if ((evl->prefer & DHCP6_ClI_MSG_PREFER_VALUE_MASK) > ct->max_prefer) {
833
834 /*
835 * 評価メッセージの推奨度が推奨メッセージリストの最大推奨度より高ければ、
836 * 推奨メッセージリストを受信メッセージ構造体リストに戻し、
837 * 評価メッセージを推奨メッセージリストに移す。
838 */
839 ct->max_prefer = evl->prefer & DHCP6_ClI_MSG_PREFER_VALUE_MASK;
840 syscall(wai_sem(SEM_DHCP6_CLI_LOCK));
841 if (ct->rcv_lst == NULL)
842 ct->rcv_lst = ct->prf_lst;
843 else {
844 for (msg = ct->rcv_lst; msg->next != NULL; msg = msg->next)
845 ;
846 msg->next = ct->prf_lst;
847 }
848 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
849 ct->prf_lst = evl;
850 return E_OK;
851 }
852
853 else if ((evl->prefer & DHCP6_ClI_MSG_PREFER_VALUE_MASK) == ct->max_prefer) {
854 for (msg = ct->prf_lst; msg != NULL; msg = msg->next) {
855 if (is_equal_sid(evl, msg)) {
856
857 /*
858 * 推奨メッセージリストに同じ DHCP6_OPT_SERVERID のメッセージがあれば、
859 * 評価メッセージを受信メッセージ構造体リストに戻す。
860 */
861 goto rcv_ret;
862 }
863 }
864
865 /*
866 * 評価メッセージを推奨メッセージリストに移す。
867 */
868 evl->next = ct->prf_lst;
869 ct->prf_lst = evl;
870 return E_OK;
871 }
872
873 /*else */
874 /*
875 * 評価メッセージの推奨度が推奨メッセージリストの最大推奨度より低ければ、
876 * 評価メッセージを受信メッセージ構造体リストに戻す。
877 */
878
879rcv_ret:
880 syscall(wai_sem(SEM_DHCP6_CLI_LOCK));
881 evl->next = ct->rcv_lst;
882 ct->rcv_lst = evl;
883 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
884 return E_OK;
885 }
886
887/*
888 * select_msg -- 推奨メッセージリストのå…
889ˆé ­ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’選択する。
890 */
891
892static T_DHCP6_CLI_MSG*
893select_msg (T_DHCP6_CLI_CONTEXT *ct)
894{
895 T_DHCP6_CLI_MSG *msg, *select;
896
897 syscall(wai_sem(SEM_DHCP6_CLI_LOCK));
898 if (ct->prf_lst == NULL) {
899 /* メッセージを受信していなければ中止する。*/
900 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
901 return NULL;
902 }
903
904 select = ct->prf_lst;
905
906#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS
907
908 if ((select->prefer & DHCP6_ClI_MSG_PREFER_REQUIRED) == 0) {
909 /* 必
910須オプションが無ければ選択しない。*/
911 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
912 return NULL;
913 }
914
915#elif DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL
916
917 if (((select->prefer & DHCP6_ClI_MSG_PREFER_REQUIRED) == 0) ||
918 ((select->prefer & DHCP6_ClI_MSG_PREFER_ADDR) == 0)) {
919 /* 必
920須オプションとアドレスが無ければ選択しない。*/
921 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
922 return NULL;
923 }
924
925#else /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS */
926
927#endif /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS */
928
929 /* 推奨メッセージリストのå…
930ˆé ­ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’選択する。*/
931 ct->prf_lst = ct->prf_lst->next;
932 select->next = NULL;
933
934 /* 選択されなかった検証メッセージを受信メッセージ構造体リストに戻す。*/
935 if (ct->rcv_lst == NULL)
936 ct->rcv_lst = ct->prf_lst;
937 else {
938 for (msg = ct->rcv_lst; msg->next != NULL; msg = msg->next)
939 ;
940 msg->next = ct->prf_lst;
941 }
942 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
943 return select;
944 }
945
946/*
947 * advance_retrans -- 再送信タイムアウトを更新する。
948 */
949
950static void
951advance_retrans (T_DHCP6_CLI_CONTEXT *ct)
952{
953 /*
954 * 再送信間隔(RT)を更新する。
955 * 再送信毎に約 2倍するが、
956 * 最大送信間隔(MRT)を超
957えないようにする。
958 */
959 ct->RT += ct->RT + dhcp6_rand(ct->RT);
960 if ((ct->MRT != 0) && (ct->RT > ct->MRT))
961 ct->RT = ct->MRT + dhcp6_rand(ct->MRT);
962
963 /* 再送信回数を更新する。*/
964 ct->txcount ++;
965 }
966
967/*
968 * init_retrans -- 再送信回数、トランザクション ID、その他を設定する。
969 */
970
971static void
972init_retrans (T_DHCP6_CLI_CONTEXT *ct)
973{
974 /* 送信回数をリセットする。*/
975 ct->txcount = 0;
976
977 /* 再送信間隔を設定する。*/
978 ct->RT = ct->IRT + dhcp6_rand(ct->IRT);
979
980 /* トランザクション ID を設定する。*/
981 ct->xid = netapp_rand() % 0x00ffffff;
982
983 /* 受信メッセージの最大推奨度をリセットする。*/
984 ct->max_prefer = 0;
985 }
986
987/*
988 * setup_msg_header -- メッセージのヘッダ部分を作成する。
989 */
990
991static uint8_t *
992setup_msg_header (T_DHCP6_CLI_CONTEXT *ct, uint_t type)
993{
994 memset((void*)&ct->snd_msg->msg, sizeof(ct->snd_msg->msg), 0);
995 ct->snd_msg->len = sizeof(ct->snd_msg->msg);
996
997 /* ヘッダ部を設定する。*/
998 ct->snd_msg->msg.hdr.type = type;
999 ct->snd_msg->msg.hdr.xid[0] = (ct->xid >> 16) & 0xff;
1000 ct->snd_msg->msg.hdr.xid[1] = (ct->xid >> 8) & 0xff;
1001 ct->snd_msg->msg.hdr.xid[2] = ct->xid & 0xff;
1002
1003 return (uint8_t*)&ct->snd_msg->msg + sizeof(ct->snd_msg->msg.hdr);
1004 }
1005
1006/*
1007 * common_options -- 標準オプションを追加する。
1008 */
1009
1010static uint8_t *
1011common_options (T_DHCP6_CLI_CONTEXT *ct, uint8_t *msg, uint_t type, T_DHCP6_CLI_MSG *lease)
1012{
1013 T_DHCP6_OPT_CLIENTID *cid;
1014 T_DHCP6_OPT_SERVERID *sid;
1015
1016#if defined(DHCP6_CLI_CFG_REQUIRED_OLIST) || defined(DHCP6_CLI_CFG_REQUEST_OLIST)
1017 T_DHCP6_OPT_ORO *oro;
1018#endif
1019
1020 uint8_t *opt;
1021 uint_t opt_len;
1022 int_t ix;
1023
1024#if defined(DHCP6_CLI_CFG_RAPID_COMMIT)
1025
1026 /* Rapid-commit の指定 */
1027 if (type == DHCP6_SOLICIT)
1028 ;
1029
1030#endif /* of #if defined(DHCP6_CLI_CFG_RAPID_COMMIT) */
1031
1032 /* クライアント DUID を追加する。*/
1033 cid = (T_DHCP6_OPT_CLIENTID*)msg;
1034 HOST2MSG16(cid->code, DHCP6_OPT_CLIENTID);
1035 HOST2MSG16(cid->len, ct->duid_len);
1036 memcpy(msg + sizeof(T_DHCP6_OPT_CLIENTID), ct->duid, ct->duid_len);
1037 msg += ct->duid_len + sizeof(T_DHCP6_OPT_CLIENTID);
1038
1039 /* サーバ DUID を追加する。*/
1040 if (lease == NULL) {
1041 if (!(type == DHCP6_SOLICIT || type == DHCP6_INFO_REQ))
1042 return NULL;
1043 }
1044 else if (!(type == DHCP6_CONFIRM || type == DHCP6_REBIND)) {
1045 if ((opt = find_msg_option(lease, DHCP6_OPT_SERVERID, 0)) != NULL) {
1046 sid = (T_DHCP6_OPT_SERVERID*)opt;
1047 opt_len = MSG2HOST16(sid->len);
1048 memcpy(msg, opt, opt_len + sizeof(*sid));
1049 msg += opt_len + sizeof(*sid);
1050 }
1051 }
1052
1053#if defined(DHCP6_CLI_CFG_REQUIRED_OLIST) || defined(DHCP6_CLI_CFG_REQUEST_OLIST)
1054
1055 /* 必
1056須・要求オプションを追加する。*/
1057 oro = (T_DHCP6_OPT_ORO*)msg;
1058 HOST2MSG16(oro->code, DHCP6_OPT_ORO);
1059 HOST2MSG16(oro->len, 0);
1060 msg += sizeof(oro->code) + sizeof(oro->len);
1061
1062#if defined(DHCP6_CLI_CFG_REQUIRED_OLIST)
1063
1064 /* 必
1065須オプションを追加する。*/
1066 HOST2MSG16(oro->len, MSG2HOST16(oro->len) + sizeof(required_plist) * 2);
1067 for (ix = sizeof(required_plist); ix -- > 0; ) {
1068 host2msg16(msg, required_plist[ix]);
1069 msg += sizeof(uint16_t);
1070 }
1071
1072#endif /* of #if defined(DHCP6_CLI_CFG_REQUIRED_OLIST) */
1073
1074#if defined(DHCP6_CLI_CFG_REQUEST_OLIST)
1075
1076 /* 要求オプションを追加する。*/
1077 HOST2MSG16(oro->len, MSG2HOST16(oro->len) + sizeof(request_plist) * 2);
1078 for (ix = sizeof(request_plist); ix -- > 0; ) {
1079 host2msg16(msg, request_plist[ix]);
1080 msg += sizeof(uint16_t);
1081 }
1082
1083#endif /* of #if defined(DHCP6_CLI_CFG_REQUEST_OLIST) */
1084
1085#endif /* of #if defined(DHCP6_CLI_CFG_REQUIRED_OLIST) || defined(DHCP6_CLI_CFG_REQUEST_OLIST) */
1086
1087 return msg;
1088 }
1089
1090/*
1091 * rel_lease -- リースされたオプションを解析して値を解放する。
1092 */
1093
1094static void
1095rel_lease (T_DHCP6_CLI_CONTEXT *ct)
1096{
1097 T_DHCP6_OPTION *hdr;
1098
1099#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL
1100
1101 T_DHCP6_OPT_IA_NA_PD *ia;
1102 T_DHCP6_OPT_IAADDR *iaa;
1103
1104#endif /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL */
1105
1106 uint8_t *opt, *last;
1107
1108 /* 有効なリース・メッセージ構造体が無ければ何もしない。*/
1109 if (ct->act_msg == NULL)
1110 return;
1111
1112 opt = ct->act_msg->msg.options;
1113 last = opt + (ct->act_msg->len - sizeof(T_DHCP6_MSG_HDR));
1114 while (opt < last) {
1115 hdr = (T_DHCP6_OPTION*)opt;
1116 switch (MSG2HOST16(hdr->code)) {
1117
1118 case DHCP6_OPT_NAME_SERVERS:
1119 dns_in6_set_addr(NULL);
1120
1121#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS
1122 syslog(LOG_NOTICE, "[DHCP6C] release DNS server addr.");
1123#endif
1124 break;
1125
1126 case DHCP6_OPT_DOMAIN_SEARCH:
1127 dns_in6_set_dname(NULL, 0);
1128 break;
1129
1130#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL
1131
1132 case DHCP6_OPT_IA_NA:
1133 ia = (T_DHCP6_OPT_IA_NA_PD*)opt;
1134 if (MSG2HOST16(ia->len) > sizeof(*iaa)) {
1135 iaa = (T_DHCP6_OPT_IAADDR*)(opt + sizeof(*ia));
1136 in6_del_ifaddr(&iaa->addr);
1137 }
1138 break;
1139
1140 case DHCP6_OPT_IA_TA:
1141 break;
1142
1143 case DHCP6_OPT_IA_PD:
1144 break;
1145
1146#endif /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL */
1147
1148 default:
1149 break;
1150 }
1151 opt += MSG2HOST16(hdr->len) + sizeof(*hdr);
1152 }
1153 }
1154
1155/*
1156 * set_lease -- リースされたオプションを解析して値を設定する。
1157 */
1158
1159static void
1160set_lease (T_DHCP6_CLI_CONTEXT *ct)
1161{
1162 T_DHCP6_OPTION *hdr;
1163 T_DHCP6_OPT_NAME_SERVERS *ns;
1164 T_DHCP6_OPT_DOMAIN_SEARCH *ds;
1165 const uint8_t *dname;
1166
1167#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL
1168
1169 T_DHCP6_OPT_IA_NA_PD *ia;
1170 T_DHCP6_OPT_IAADDR *iaa;
1171 SYSTIM time, delay;
1172 ER error;
1173
1174#endif /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL */
1175
1176 uint8_t *opt, *last;
1177
1178 opt = ct->act_msg->msg.options;
1179 last = opt + (ct->act_msg->len - sizeof(T_DHCP6_MSG_HDR));
1180 while (opt < last) {
1181 hdr = (T_DHCP6_OPTION*)opt;
1182 switch (MSG2HOST16(hdr->code)) {
1183
1184 case DHCP6_OPT_NAME_SERVERS:
1185 ns = (T_DHCP6_OPT_NAME_SERVERS*)opt;
1186 dns_in6_set_addr(&ns->addrs[0]);
1187
1188#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS
1189 syslog(LOG_NOTICE, "[DHCP6C] set DNS server addr: %s.", ipv62str(NULL, &ns->addrs[0]));
1190#endif
1191 break;
1192
1193 case DHCP6_OPT_DOMAIN_SEARCH:
1194 ds = (T_DHCP6_OPT_DOMAIN_SEARCH*)opt;
1195 dname = dns_in6_set_dname(ds->name, MSG2HOST16(ds->len));
1196 break;
1197
1198#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL
1199
1200 case DHCP6_OPT_IA_NA:
1201 ia = (T_DHCP6_OPT_IA_NA_PD*)opt;
1202 if (MSG2HOST16(ia->len) > sizeof(*iaa)) {
1203 get_tim(&time);
1204 delay = time - ct->act_msg->rcv_time;
1205 iaa = (T_DHCP6_OPT_IAADDR*)(opt + sizeof(*ia));
1206 error = in6_upd_ifaddr(&iaa->addr, 64, MSG2HOST32(iaa->valid) - SYSTIM2SEC(delay),
1207 MSG2HOST32(iaa->prefer) - SYSTIM2SEC(delay));
1208 if (error == E_OK)
1209 syslog(LOG_NOTICE, "[DHCP6C] set IPv6 addr: %s.", ipv62str(NULL, &iaa->addr));
1210 else
1211 syslog(LOG_NOTICE, "[DHCP6C] set IPv6 addr, error: %s.", itron_strerror(error));
1212 }
1213 break;
1214
1215 case DHCP6_OPT_IA_TA:
1216 break;
1217
1218 case DHCP6_OPT_IA_PD:
1219 break;
1220
1221#endif /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL */
1222
1223 default:
1224 break;
1225 }
1226 opt += MSG2HOST16(hdr->len) + sizeof(*hdr);
1227 }
1228 }
1229
1230#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS || DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_RA
1231
1232/*
1233 * start_req_info -- INFO-REQUEST を開始する。
1234 *
1235 * 注意: DHCPv6 の RFC3315 には無い
1236 */
1237
1238static void
1239start_req_info (T_DHCP6_CLI_CONTEXT *ct)
1240{
1241 /* タイムアウトを設定する。【RFC3315 (18.1.5) 参ç…
1242§ã€‘*/
1243 ct->IRT = TMO_INF_TIMEOUT;
1244 ct->MRT = TMO_INF_MAX_RT;
1245 ct->MRC = 0;
1246
1247 /* DHCP6_CLI_CFG_ONE_TRYが指定されていなければ標準タイムアウトまで再送する。*/
1248#if defined(DHCP6_CLI_CFG_ONE_TRY)
1249 ct->MRD = 0;
1250#else
1251 ct->MRD = TMO_DHCP6C_NORMAL;
1252#endif
1253
1254 /* 再送回数とトランザクション ID を設定する。*/
1255 init_retrans(ct);
1256
1257 /* REPLY メッセージの受信タイムアウトを設定する。*/
1258 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
1259 ct->timers[DHCP6C_TIMER_RCV_REPLY] = SYSTIM2TIMER(ct->MRD);
1260 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
1261
1262 /*
1263 * INFO-REQUEST メッセージ送信遅
1264延時間を設定する。
1265 * ただし、TMO_INF_MAX_DELAY が 1[s]なので、dly_tsk()を使用する。
1266 */
1267 dly_tsk(netapp_rand() % TMO_INF_MAX_DELAY);
1268
1269 /* SELECT 状æ…
1270‹ã«é·ç§»ã™ã‚‹ã€‚*/
1271 ct->fsm = DHCP6_FSM_SELECT;
1272
1273 /* INFO-REQUEST メッセージを送信する。*/
1274 ct->flags |= DHCP6C_FLAG_TMOUT_SND_IREQ;
1275 syscall(sig_sem(SEM_DHCP6_CLI_READY));
1276 }
1277
1278/*
1279 * start_informed -- INFORMED 状æ…
1280‹ã«é·ç§»ã™ã‚‹ã€‚
1281 *
1282 * 注意: DHCPv6 の RFC3315 には無い
1283 */
1284
1285static void
1286start_informed (T_DHCP6_CLI_CONTEXT *ct)
1287{
1288 /* 有効なリース情
1289報が無ければ SLEEP に遷移する。*/
1290 if (ct->act_msg == NULL) {
1291 ct->fsm = DHCP6_FSM_SLEEP;
1292 return;
1293 }
1294
1295 /* リース情
1296報を設定する。*/
1297 set_lease(ct);
1298
1299 /* INFORMED 状æ…
1300‹ã«é·ç§»ã™ã‚‹ã€‚*/
1301 ct->fsm = DHCP6_FSM_INFORMED;
1302
1303 //ct->flags |= DHCP6C_FLAG_STAY_STATE;
1304 }
1305
1306/*
1307 * start_rel_info -- アドレス情
1308報を解放する。
1309 *
1310 * 注意: DHCPv6 の RFC3315 には無い
1311 */
1312
1313static void
1314start_rel_info (T_DHCP6_CLI_CONTEXT *ct)
1315{
1316 /* リース情
1317報を解放する。*/
1318 rel_lease(ct);
1319
1320 /* SLEEP に遷移する。*/
1321 ct->fsm = DHCP6_FSM_SLEEP;
1322 syscall(sig_sem(SEM_DHCP6_CLI_READY));
1323 }
1324
1325/*
1326 * select_info_reply -- 最適な REPLY (INFO-REQUEST への応答) メッセージを選択する。
1327 */
1328
1329static bool_t
1330select_info_reply (T_DHCP6_CLI_CONTEXT *ct)
1331{
1332 T_DHCP6_CLI_MSG *msg;
1333
1334 /* 最適な REPLY メッセージを選択する。*/
1335 if ((msg = select_msg(ct)) == NULL)
1336 return false;
1337
1338 ct->act_msg = msg;
1339 return true;
1340 }
1341
1342/*
1343 * setup_info_req_msg -- INFO-REQUEST メッセージを作成する。
1344 */
1345
1346static ER
1347setup_info_req_msg (T_DHCP6_CLI_CONTEXT *ct)
1348{
1349 uint8_t *msg;
1350
1351 /* メッセージのヘッダ部分を作成する。*/
1352 if ((msg = setup_msg_header(ct, DHCP6_INFO_REQ)) == NULL)
1353 return E_PAR;
1354
1355 if ((msg = common_options(ct, msg, DHCP6_INFO_REQ, NULL)) == NULL)
1356 return E_PAR;
1357
1358 /* メッセージ構造体長を設定する。*/
1359 ct->snd_msg->len = msg - (uint8_t*)&ct->snd_msg->msg;
1360
1361 /* 送信å…
1362ˆã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’設定する。*/
1363 ct->dst.ipaddr = in6_addr_all_DHCP_relay_servers;
1364 return E_OK;
1365 }
1366
1367/*
1368 * send_info_req_msg -- INFO-REQUEST メッセージを送信する。
1369 */
1370
1371static void
1372send_info_req_msg (T_DHCP6_CLI_CONTEXT *ct)
1373{
1374 ER error;
1375
1376
1377 /* REPLY メッセージの選択が終了していれば、BOUND 状æ…
1378‹ã«é·ç§»ã™ã‚‹ã€‚*/
1379 ct->flags &= ~DHCP6C_FLAG_TMOUT_MASK;
1380 if (select_info_reply(ct)) {
1381
1382 /* REPLY メッセージ受信タイマーを停止する。*/
1383 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
1384 ct->timers[DHCP6C_TIMER_RCV_REPLY] = 0;
1385 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
1386
1387 /* INFORMED 状æ…
1388‹ã«é·ç§»ã™ã‚‹ã€‚*/
1389 start_informed(ct);
1390 return;
1391 }
1392
1393 /* 再送信回数を確認する。*/
1394 if ((ct->MRC != 0) && (ct->txcount > ct->MRC)) {
1395 ct->error = E_TMOUT;
1396 return;
1397 }
1398
1399 /* INFO-REQUEST メッセージを作成する。*/
1400 if ((error = setup_info_req_msg(ct)) != E_OK) {
1401 syslog(LOG_NOTICE, "[DHCP6C] error, setup request message: %s.", itron_strerror(error));
1402 ct->error = error;
1403 return;
1404 }
1405
1406 /* INFO-REQUEST メッセージを送信する。*/
1407 error = UDP_SND_DAT(ct->cepid, &ct->dst, &ct->snd_msg->msg, ct->snd_msg->len, TMO_NBLK);
1408 if (error != E_WBLK) {
1409 syslog(LOG_NOTICE, "[DHCP6C] error, send info-request message: %s.", itron_strerror(error));
1410 ct->error = error;
1411 return;
1412 }
1413
1414 /* 再送信タイムアウトを設定する。*/
1415 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
1416 ct->timers[DHCP6C_TIMER_SND_IREQ] = SYSTIM2TIMER(ct->RT);
1417 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
1418
1419 /* 再送信タイムアウトを更新する。*/
1420 advance_retrans(ct);
1421 }
1422
1423#endif /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS || DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_RA */
1424
1425#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL || DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_RA
1426
1427/*
1428 * select_reply -- 最適な REPLY メッセージを選択する。
1429 */
1430
1431static bool_t
1432select_reply (T_DHCP6_CLI_CONTEXT *ct)
1433{
1434 T_DHCP6_CLI_MSG *msg;
1435
1436 /* 最適な REPLY メッセージを選択する。*/
1437 if ((msg = select_msg(ct)) == NULL)
1438 return false;
1439
1440 if (ct->adv_msg != NULL) {
1441 eval_prefer(ct->adv_msg);
1442 eval_ia_prefer(ct->adv_msg);
1443 }
1444
1445 /*
1446 * 最適な REPLY メッセージの推奨度が ADVERTISE メッセージ推奨度の
1447 * 1/2 以下の時は受信メッセージ構造体リストに戻す。
1448 */
1449 if ((ct->adv_msg != NULL) && (ct->max_prefer < (ct->adv_msg->prefer & DHCP6_ClI_MSG_PREFER_VALUE_MASK) / 2)) {
1450 syscall(wai_sem(SEM_DHCP6_CLI_LOCK));
1451 msg->next = ct->rcv_lst;
1452 ct->rcv_lst = msg;
1453 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
1454 }
1455 else {
1456
1457 /*
1458 * ct->act_msg にある有効なå…
1459ƒ REPLY メッセージを
1460 * 受信メッセージ構造体リストに戻して、
1461 * 最適な REPLY メッセージを act に移す。
1462 */
1463 if (ct->act_msg != NULL) {
1464 syscall(wai_sem(SEM_DHCP6_CLI_LOCK));
1465 ct->act_msg->next = ct->rcv_lst;
1466 ct->rcv_lst = ct->act_msg;
1467 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
1468 }
1469 ct->act_msg = msg;
1470 }
1471
1472 return ct->act_msg != NULL;
1473 }
1474
1475/*
1476 * select_adv -- 最適な ADVERTISE メッセージを選択する。
1477 */
1478
1479static bool_t
1480select_adv (T_DHCP6_CLI_CONTEXT *ct)
1481{
1482 /* 最適な ADVERTISE メッセージを adv に移す。*/
1483 if ((ct->adv_msg = select_msg(ct)) != NULL) {
1484
1485 /*
1486 * 最適な ADVERTISE メッセージのサーバの IPv6 アドレスを
1487 * 次から送信するアドレスに設定する。
1488 */
1489 ct->dst = ct->adv_msg->srv;
1490 return true;
1491 }
1492 else
1493 return false;
1494 }
1495
1496/*
1497 * eval_expire -- 推奨有効時間と有効時間を決定する。
1498 */
1499
1500static void
1501eval_expire (T_DHCP6_CLI_CONTEXT *ct)
1502{
1503 T_DHCP6_OPTION *opt;
1504 T_DHCP6_OPT_IA_NA_PD *ia;
1505 T_DHCP6_OPT_IAADDR *iaa;
1506 SYSTIM time;
1507 uint32_t depref, expire,
1508 high, low, renew, rebind,
1509 tval, iaa_high, iaa_low;
1510 uint8_t *msg, *last;
1511 uint_t aoff, asize, addrs;
1512
1513 /* タイマーを停止する。*/
1514 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
1515 ct->timers[DHCP6C_TIMER_RENEW] = 0;
1516 ct->timers[DHCP6C_TIMER_REBIND] = 0;
1517 ct->timers[DHCP6C_TIMER_DEPREF] = 0;
1518 ct->timers[DHCP6C_TIMER_EXPIRE] = 0;
1519 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
1520
1521 addrs = high = expire = 0;
1522 low = renew = rebind = depref = DHCP6_MAX_TIME;
1523
1524 msg = ct->act_msg->msg.options;
1525 last = msg + (ct->act_msg->len - sizeof(T_DHCP6_MSG_HDR));
1526 get_tim(&time);
1527 while (msg < last) {
1528 opt = (T_DHCP6_OPTION*)msg;
1529
1530 /* IA_NA/IA_PD オプションであれば、有効時間を更新する。*/
1531 if (MSG2HOST16(opt->code) == DHCP6_OPT_IA_NA || MSG2HOST16(opt->code) == DHCP6_OPT_IA_PD) {
1532
1533 //dump_msg_option("evl_expire1", msg);
1534 iaa_high = 0;
1535 iaa_low = DHCP6_MAX_TIME;
1536
1537 ia = (T_DHCP6_OPT_IA_NA_PD*)opt;
1538 aoff = sizeof(*ia);
1539 asize = MSG2HOST16(ia->len) + sizeof(*opt);
1540 while (aoff < asize) {
1541
1542 /* 最短の推奨有効時間を更新する。*/
1543 iaa = (T_DHCP6_OPT_IAADDR*)((uint8_t*)opt + aoff);
1544 //dump_msg_option("evl_depref1", (uint8_t*)iaa);
1545 if (!(MSG2HOST16(iaa->len) & DHCP6C_IAA_FLAG_DEPREFERD)) {
1546 if (MSG2HOST32(iaa->prefer) == DHCP6_MAX_TIME)
1547 tval = DHCP6_MAX_TIME;
1548 else
1549 tval = MSG2HOST32(iaa->prefer) + SYSTIM2SEC(ct->act_msg->rcv_time);
1550 if (tval < depref)
1551 depref = tval;
1552 }
1553
1554 /* IAADDR の有効時間を更新する。*/
1555 iaa = (T_DHCP6_OPT_IAADDR*)((uint8_t*)opt + aoff);
1556 if (!(MSG2HOST16(iaa->len) & DHCP6C_IAA_FLAG_EXPIRED)) {
1557 if (MSG2HOST32(iaa->valid) == DHCP6_MAX_TIME)
1558 tval = DHCP6_MAX_TIME;
1559 else
1560 tval = MSG2HOST32(iaa->valid) + SYSTIM2SEC(ct->act_msg->rcv_time);
1561 tval -= SYSTIM2SEC(ct->act_msg->rcv_time);
1562 if (tval > iaa_high)
1563 iaa_high = tval;
1564 if (tval < iaa_low)
1565 iaa_low = tval;
1566 addrs ++;
1567 }
1568
1569 aoff += (MSG2HOST16(iaa->len) & ~DHCP6C_IAA_FLAG_MASK) + sizeof(*iaa);
1570 }
1571
1572 /* iaa_low と iaa_high/2 の最長の方を有効時間として選択する。*/
1573 if (iaa_low <= (iaa_high / 2))
1574 expire = iaa_high;
1575 else
1576 expire = iaa_low;
1577
1578 /* expire が 最大値(無制限)か 1 以下なら既定値に設定する。*/
1579 if ((expire == DHCP6_MAX_TIME) || (expire <= 1))
1580 expire = SYSTIM2SEC(TMO_DHCP6C_REQ_LEASE) / 2;
1581 else
1582 expire /= 2;
1583
1584 /* renew を決定する。*/
1585 if (MSG2HOST32(ia->renew) == 0)
1586 tval = expire + SYSTIM2SEC(ct->act_msg->rcv_time);
1587 else if (MSG2HOST32(ia->renew) == DHCP6_MAX_TIME)
1588 tval = DHCP6_MAX_TIME;
1589 else
1590 tval = MSG2HOST32(ia->renew) + SYSTIM2SEC(ct->act_msg->rcv_time);
1591 if (tval < renew)
1592 renew = tval;
1593
1594 /* rebind を決定する。*/
1595 if (MSG2HOST32(ia->rebind) == 0)
1596 tval = (expire + expire / 2) + SYSTIM2SEC(ct->act_msg->rcv_time);
1597 else if (MSG2HOST32(ia->rebind) == DHCP6_MAX_TIME)
1598 tval = DHCP6_MAX_TIME;
1599 else
1600 tval = MSG2HOST32(ia->rebind) + SYSTIM2SEC(ct->act_msg->rcv_time);
1601 if (tval < rebind)
1602 rebind = tval;
1603
1604 /* 最短有効時間と最長有効時間を更新する。*/
1605 iaa_low += SYSTIM2SEC(ct->act_msg->rcv_time);
1606 iaa_high += SYSTIM2SEC(ct->act_msg->rcv_time);
1607 if (iaa_low < low)
1608 low = iaa_low;
1609 if (iaa_high > high)
1610 high = iaa_high;
1611 }
1612
1613 msg += MSG2HOST16(opt->len) + sizeof(*opt);
1614 }
1615
1616 /* アドレスが送られていなければ、SLEEP 状æ…
1617‹ã«é·ç§»ã™ã‚‹ã€‚*/
1618 if (addrs == 0) {
1619 ct->fsm = DHCP6_FSM_SLEEP;
1620 }
1621
1622 /* 状æ…
1623‹ã«ä¾å­˜ã™ã‚‹å‡¦ç† */
1624 switch (ct->fsm) {
1625
1626 case DHCP6_FSM_BOUND:
1627
1628 /* RENEW タイムアウトの設定 */
1629 if ((rebind > SYSTIM2SEC(time)) && (renew < rebind)) {
1630 ct->next_MRD = SEC2SYSTIM(rebind) - time;
1631 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
1632 ct->timers[DHCP6C_TIMER_RENEW] = SEC2TIMER(renew) - SYSTIM2TIMER(time);
1633 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
1634 break;
1635 }
1636 /* break; */ /* 下に抜ける。*/
1637
1638 case DHCP6_FSM_RENEW:
1639
1640 /* REBIND タイムアウトの設定 */
1641 ct->MRD = SEC2SYSTIM(rebind);
1642 if (rebind != DHCP6_MAX_TIME) {
1643 ct->next_MRD = SEC2SYSTIM(high) - time;
1644 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
1645 ct->timers[DHCP6C_TIMER_REBIND] = SEC2TIMER(rebind) - SYSTIM2TIMER(time);
1646 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
1647 }
1648 break;
1649
1650 case DHCP6_FSM_REBIND:
1651
1652 ct->next_MRD = (SEC2TIMER(high) - time) - time;
1653 break;
1654
1655 default:
1656 break;
1657 }
1658
1659 /* DEPREF タイムアウトの設定 */
1660 if (depref != DHCP6_MAX_TIME) {
1661 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
1662 ct->timers[DHCP6C_TIMER_DEPREF] = SEC2TIMER(depref) - SYSTIM2TIMER(time);
1663 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
1664 }
1665
1666 /* EXPIRE タイムアウトの設定 */
1667 if (low != DHCP6_MAX_TIME) {
1668 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
1669 ct->timers[DHCP6C_TIMER_EXPIRE] = SEC2TIMER(low) - SYSTIM2TIMER(time);
1670 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
1671 }
1672 }
1673
1674/*
1675 * start_init -- INIT 状æ…
1676‹ã«é·ç§»ã™ã‚‹ã€‚
1677 */
1678
1679static void
1680start_init (T_DHCP6_CLI_CONTEXT *ct)
1681{
1682 /* タイムアウトを設定する。【RFC3315 (17.1.2) 参ç…
1683§ã€‘*/
1684 ct->IRT = TMO_SOL_TIMEOUT;
1685 ct->MRT = TMO_SOL_MAX_RT;
1686 ct->MRC = 0;
1687
1688 /* DHCP6_CLI_CFG_ONE_TRYが指定されていなければ標準タイムアウトまで再送する。*/
1689#if defined(DHCP6_CLI_CFG_ONE_TRY)
1690 ct->MRD = 0;
1691#else
1692 ct->MRD = TMO_DHCP6C_NORMAL;
1693#endif
1694
1695 /* 再送回数とトランザクション ID を設定する。*/
1696 init_retrans(ct);
1697
1698 /* RFC3315 (17.1.2) の規定に従ってタイムアウトを調整する。*/
1699 if (ct->RT <= ct->IRT)
1700 ct->RT = ct->IRT + (ct->IRT - ct->RT);
1701 if (ct->RT <= ct->IRT)
1702 ct->RT = ct->IRT + SEC2SYSTIM(1);
1703
1704 /* ADVERTISE メッセージの受信タイムアウトを設定する。*/
1705 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
1706 ct->timers[DHCP6C_TIMER_RCV_ADV] = SYSTIM2TIMER(ct->MRD);
1707 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
1708
1709 /*
1710 * SOLICIT メッセージ送信遅
1711延時間を設定する。
1712 * ただし、TMO_SOL_MAX_DELAY が 1[s]なので、dly_tsk()を使用する。
1713 */
1714 dly_tsk(netapp_rand() % TMO_SOL_MAX_DELAY);
1715
1716 /* INIT 状æ…
1717‹ã«é·ç§»ã™ã‚‹ã€‚*/
1718 ct->fsm = DHCP6_FSM_INIT;
1719
1720 /* SOLICIT メッセージを送信する。*/
1721 ct->flags |= DHCP6C_FLAG_TMOUT_SND_SOL;
1722 syscall(sig_sem(SEM_DHCP6_CLI_READY));
1723 }
1724
1725/*
1726 * start_select -- REQUEST メッセージを送信して SELECT 状æ…
1727‹ã«é·ç§»ã™ã‚‹ã€‚
1728 */
1729
1730static void
1731start_select (T_DHCP6_CLI_CONTEXT *ct)
1732{
1733 /* 有効な ADVERTISE メッセージを受信していなければ SLEEP 状æ…
1734‹ã«é·ç§»ã™ã‚‹ã€‚*/
1735 if (ct->adv_msg == NULL) {
1736 ct->fsm = DHCP6_FSM_SLEEP;
1737 return;
1738 }
1739
1740 /* タイムアウトを設定する。【RFC3315 (18.1.1) 参ç…
1741§ã€‘*/
1742 ct->IRT = TMO_REQ_TIMEOUT;
1743 ct->MRT = TMO_REQ_MAX_RT;
1744 ct->MRC = TMO_REQ_MAX_RC;
1745 ct->MRD = 0;
1746
1747 /* 再送回数とトランザクション ID を設定する。*/
1748 init_retrans(ct);
1749
1750 /* REPLY メッセージの受信タイムアウトを設定する。*/
1751 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
1752 ct->timers[DHCP6C_TIMER_RCV_REPLY] = SYSTIM2TIMER(ct->MRD);
1753 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
1754
1755 /* SELECT 状æ…
1756‹ã«é·ç§»ã™ã‚‹ã€‚*/
1757 ct->fsm = DHCP6_FSM_SELECT;
1758
1759 /* REQUEST メッセージを送信する。*/
1760 ct->flags |= DHCP6C_FLAG_TMOUT_SND_REQ;
1761 syscall(sig_sem(SEM_DHCP6_CLI_READY));
1762 }
1763
1764/*
1765 * start_bound -- BOUND 状æ…
1766‹ã«é·ç§»ã™ã‚‹ã€‚
1767 */
1768
1769static void
1770start_bound (T_DHCP6_CLI_CONTEXT *ct)
1771{
1772 /* 有効なリース情
1773報が無ければ SLEEP に遷移する。*/
1774 if (ct->act_msg == NULL)
1775 ct->fsm = DHCP6_FSM_SLEEP;
1776
1777 /* BOUND 状æ…
1778‹ã«é·ç§»ã™ã‚‹ã€‚*/
1779 ct->fsm = DHCP6_FSM_BOUND;
1780
1781 /* リース情
1782報を設定する。*/
1783 set_lease(ct);
1784
1785 /* 有効時間を決定する。*/
1786 eval_expire(ct);
1787
1788 }
1789/*
1790 * start_renew -- RENEW 状æ…
1791‹ã«é·ç§»ã™ã‚‹ã€‚
1792 */
1793
1794static void
1795start_renew (T_DHCP6_CLI_CONTEXT *ct)
1796{
1797 /* 有効なリース情
1798報が無ければ SLEEP に遷移する。*/
1799 if (ct->act_msg == NULL) {
1800 ct->fsm = DHCP6_FSM_SLEEP;
1801 return;
1802 }
1803
1804 /* タイムアウトを設定する。【RFC3315 (18.1.3) 参ç…
1805§ã€‘*/
1806 ct->IRT = TMO_REN_TIMEOUT;
1807 ct->MRT = TMO_REN_MAX_RT;
1808 ct->MRC = 0;
1809 ct->MRD = ct->next_MRD;
1810
1811 /* 再送回数とトランザクション ID を設定する。*/
1812 init_retrans(ct);
1813
1814 /* REFRESH メッセージタイプを設定する。*/
1815 ct->refresh_type = DHCP6_RENEW;
1816
1817 /* REPLY メッセージの受信タイムアウトを設定する。*/
1818 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
1819 ct->timers[DHCP6C_TIMER_RCV_REPLY] = SYSTIM2TIMER(ct->MRD);
1820 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
1821
1822 /* RENEW 状æ…
1823‹ã«é·ç§»ã™ã‚‹ã€‚*/
1824 ct->fsm = DHCP6_FSM_RENEW;
1825
1826 /* REFRESH メッセージを送信する。*/
1827 ct->flags |= DHCP6C_FLAG_TMOUT_SND_REF;
1828 syscall(sig_sem(SEM_DHCP6_CLI_READY));
1829 }
1830
1831/*
1832 * start_rebind -- REBIND 状æ…
1833‹ã«é·ç§»ã™ã‚‹ã€‚
1834 */
1835
1836static void
1837start_rebind (T_DHCP6_CLI_CONTEXT *ct)
1838{
1839 /* 有効なリース情
1840報が無ければ SLEEP に遷移する。*/
1841 if (ct->act_msg == NULL) {
1842 ct->fsm = DHCP6_FSM_SLEEP;
1843 return;
1844 }
1845
1846 /* タイムアウトを設定する。【RFC3315 (18.1.4) 参ç…
1847§ã€‘*/
1848 ct->IRT = TMO_REB_TIMEOUT;
1849 ct->MRT = TMO_REB_MAX_RT;
1850 ct->MRC = 0;
1851 ct->MRD = ct->next_MRD;
1852
1853 /* 再送回数とトランザクション ID を設定する。*/
1854 init_retrans(ct);
1855
1856 /* REFRESH メッセージタイプを設定する。*/
1857 ct->refresh_type = DHCP6_REBIND;
1858
1859 /* REPLY メッセージの受信タイムアウトを設定する。*/
1860 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
1861 ct->timers[DHCP6C_TIMER_RCV_REPLY] = SYSTIM2TIMER(ct->MRD);
1862 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
1863
1864 /* 送信å…
1865ˆã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’設定する。*/
1866 ct->dst.ipaddr = in6_addr_all_DHCP_relay_servers;
1867
1868 /* REBIND 状æ…
1869‹ã«é·ç§»ã™ã‚‹ã€‚*/
1870 ct->fsm = DHCP6_FSM_REBIND;
1871
1872 /* REFRESH メッセージを送信する。*/
1873 ct->flags |= DHCP6C_FLAG_TMOUT_SND_REF;
1874 syscall(sig_sem(SEM_DHCP6_CLI_READY));
1875 }
1876
1877/*
1878 * start_rel_info -- アドレス情
1879報を解放する。
1880 *
1881 * 注意: DHCPv6 の RFC3315 には無い
1882 */
1883
1884static void
1885start_rel_info (T_DHCP6_CLI_CONTEXT *ct)
1886{
1887 /* å…
1888¨ã¦ã® TIMER をキャンセルする。*/
1889 cancel_all_timers(ct);
1890
1891 /* リース情
1892報を解放する。*/
1893 rel_lease(ct);
1894
1895 /* 有効なリース情
1896報が無ければ SLEEP に遷移する。*/
1897 if (ct->act_msg == NULL) {
1898 ct->fsm = DHCP6_FSM_SLEEP;
1899 return;
1900 }
1901
1902 /* タイムアウトを設定する。【RFC3315 (18.1.1) 参ç…
1903§ã€‘*/
1904 ct->IRT = TMO_REL_TIMEOUT;
1905 ct->MRT = 0;
1906 ct->MRC = TMO_REL_MAX_RC;
1907 ct->MRD = 0;
1908
1909 /* 再送回数とトランザクション ID を設定する。*/
1910 init_retrans(ct);
1911
1912 /* REL_INFO 状æ…
1913‹ã«é·ç§»ã™ã‚‹ã€‚*/
1914 ct->fsm = DHCP6_FSM_REL_INFO;
1915
1916 /* RELEASE メッセージを送信する。*/
1917 ct->flags |= DHCP6C_FLAG_TMOUT_SND_REL;
1918 syscall(sig_sem(SEM_DHCP6_CLI_READY));
1919 }
1920
1921#if defined(DHCP6_CLI_CFG_IA_NA) || defined(DHCP6_CLI_CFG_IA_TA) || defined(DHCP6_CLI_CFG_IA_PD)
1922
1923/*
1924 * solicit_ia_option -- SOLICIT メッセージの IA_NA/IA_TA/IA_PD オプションのå…
1925±é€šéƒ¨åˆ†ã‚’追加する。
1926 */
1927
1928static void
1929solicit_ia_option (T_DHCP6_CLI_CONTEXT *ct, uint8_t *msg, uint_t code)
1930{
1931 T_DHCP6_OPT_IA_TA *ia;
1932 uint_t off, len;
1933
1934 /* オプションコードを設定する。*/
1935 ia = (T_DHCP6_OPT_IA_TA*)msg;
1936 HOST2MSG16(ia->code, code);
1937
1938 /* IAID を設定する。*/
1939 if (sizeof(ct->sc->ifaddr.lladdr) > sizeof(uint32_t)) {
1940 off = sizeof(ct->sc->ifaddr.lladdr) - 4;
1941 len = 4;
1942 }
1943 else {
1944 off = 0;
1945 len = sizeof(ct->sc->ifaddr.lladdr);
1946 }
1947 memcpy((uint8_t*)&ia->iaid, ((uint8_t*)ct->sc->ifaddr.lladdr) + off, len);
1948 }
1949
1950/*
1951 * solicit_iaaddr_option -- SOLICIT メッセージの IAADDR オプションを追加する。
1952 */
1953
1954static uint_t
1955solicit_iaaddr_option (T_DHCP6_CLI_CONTEXT *ct, uint8_t *msg, uint_t code)
1956{
1957 T_DHCP6_OPT_IAADDR *iaa;
1958 uint32_t t1, t2;
1959 uint8_t *opt;
1960 uint_t len;
1961
1962 /*
1963 * 有効なリース・メッセージが残っていて、
1964 * 指定されたオプション(IA_NA/IA_TA/IA_PD)がある場合は
1965 * 同じアドレスを要求する。
1966 */
1967 if ((ct->act_msg == NULL) || (opt = find_msg_option(ct->act_msg, code, 0)) == NULL)
1968 return 0;
1969
1970 /* オプションコードを設定する。*/
1971 iaa = (T_DHCP6_OPT_IAADDR*)msg;
1972 HOST2MSG16(iaa->code, DHCP6_OPT_IAADDR);
1973
1974 /* IAADDR オプションを除いたオプション長を設定する。*/
1975 HOST2MSG16(iaa->len, sizeof(*iaa) - sizeof(T_DHCP6_OPTION));
1976
1977 /* アドレスを設定する。*/
1978 len = code == DHCP6_OPT_IA_TA ? sizeof(T_DHCP6_OPT_IA_TA)
1979 : sizeof(T_DHCP6_OPT_IA_NA_PD);
1980 memcpy(&iaa->addr, opt + sizeof(T_DHCP6_OPTION) + len, sizeof(iaa->addr));
1981
1982 /* T1、T2 を設定する。*/
1983 t1 = TMO_DHCP6C_REQ_LEASE / 2;
1984 t2 = t1 + (t1 / 2);
1985 HOST2MSG32(iaa->prefer, t1);
1986 HOST2MSG32(iaa->valid, t2);
1987
1988 return sizeof(*iaa);
1989 }
1990
1991#endif /* of #if defined(DHCP6_CLI_CFG_IA_NA) || defined(DHCP6_CLI_CFG_IA_TA) || defined(DHCP6_CLI_CFG_IA_PD) */
1992
1993/*
1994 * solicit_ia_na_pd -- SOLICIT メッセージの IA_NA/IA_PD オプションを追加する。
1995 */
1996
1997#if defined(DHCP6_CLI_CFG_IA_NA) || defined(DHCP6_CLI_CFG_IA_PD)
1998
1999static uint8_t *
2000solicit_ia_na_pd (T_DHCP6_CLI_CONTEXT *ct, uint8_t *msg, uint_t code)
2001{
2002 T_DHCP6_OPT_IA_NA_PD *ia;
2003 uint32_t t1, t2;
2004 uint_t len;
2005
2006 /* IA_NA/IA_TA/IA_PD オプションのå…
2007±é€šéƒ¨åˆ†ã‚’追加する。*/
2008 solicit_ia_option(ct, msg, code);
2009 ia = (T_DHCP6_OPT_IA_NA_PD*)msg;
2010
2011 /* T1、T2 を設定する。*/
2012 t1 = TMO_DHCP6C_REQ_LEASE / 2;
2013 t2 = t1 + (t1 / 2);
2014 HOST2MSG32(ia->renew, SYSTIM2SEC(t1));
2015 HOST2MSG32(ia->rebind, SYSTIM2SEC(t2));
2016
2017 /*
2018 * 有効なリース・メッセージが残っていて、
2019 * 指定されたオプション(IA_NA/IA_PD)がある場合は
2020 * 同じアドレスを要求する。
2021 */
2022 msg += sizeof(*ia);
2023 len = solicit_iaaddr_option(ct, msg, code);
2024
2025 /* IA_NAIA_TA/IA_PD オプションを除いたオプション長を設定する。*/
2026 HOST2MSG16(ia->len, (sizeof(*ia) + len) - sizeof(T_DHCP6_OPTION));
2027
2028 return msg + len;
2029 }
2030
2031#endif /* of #if defined(DHCP6_CLI_CFG_IA_NA) || defined(DHCP6_CLI_CFG_IA_PD) */
2032
2033/*
2034 * solicit_ia_ta -- SOLICIT メッセージの IA_TA オプションを追加する。
2035 */
2036
2037#if defined(DHCP6_CLI_CFG_IA_TA)
2038
2039static uint8_t *
2040solicit_ia_ta (T_DHCP6_CLI_CONTEXT *ct, uint8_t *msg)
2041{
2042 T_DHCP6_OPT_IA_TA *ia;
2043
2044 /* IA_NA/IA_TA/IA_PD オプションのå…
2045±é€šéƒ¨åˆ†ã‚’追加する。*/
2046 solicit_ia_option(ct, msg, DHCP6_OPT_IA_TA);
2047
2048 /* IA_NAIA_TA/IA_PD オプションを除いたオプション長を設定する。*/
2049 ia = (T_DHCP6_OPT_IA_TA*)msg;
2050 HOST2MSG16(ia->len, sizeof(*ia) - sizeof(T_DHCP6_OPTION));
2051
2052 /*
2053 * 有効なリース・メッセージが残っていて、
2054 * 指定されたオプション(IA_TA)がある場合は
2055 * 同じアドレスを要求する。
2056 */
2057 msg += sizeof(*ia);
2058 return msg + solicit_iaaddr_option(ct, msg, code);
2059 }
2060
2061#endif /* of #if defined(DHCP6_CLI_CFG_IA_TA) */
2062
2063/*
2064 * setup_solicit_msg -- SOLICIT メッセージを作成する。
2065 */
2066
2067static ER
2068setup_solicit_msg (T_DHCP6_CLI_CONTEXT *ct, T_DHCP6_CLI_MSG *lease)
2069{
2070 uint8_t *head, *msg;
2071
2072 /* メッセージのヘッダ部分を作成する。*/
2073 if ((head = setup_msg_header(ct, DHCP6_SOLICIT)) == NULL)
2074 return E_PAR;
2075
2076 if ((msg = common_options(ct, head, DHCP6_SOLICIT, lease)) == NULL)
2077 return E_PAR;
2078
2079#if defined(DHCP6_CLI_CFG_IA_NA)
2080
2081 /* IA_NA を追加する。*/
2082 msg = solicit_ia_na_pd(ct, msg, DHCP6_OPT_IA_NA);
2083#endif
2084
2085#if defined(DHCP6_CLI_CFG_IA_TA)
2086
2087 /* IA_TA を追加する。*/
2088 msg = solicit_ia_ta(ct, msg);
2089#endif
2090
2091#if defined(DHCP6_CLI_CFG_IA_PD)
2092
2093 /* IA_PD を追加する。*/
2094 msg = solicit_ia_na_pd(ct, msg, DHCP6_OPT_IA_PD);
2095#endif
2096
2097 /* メッセージ構造体長を設定する。*/
2098 ct->snd_msg->len = msg - (uint8_t*)&ct->snd_msg->msg;
2099
2100 /* 送信å…
2101ˆã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’設定する。*/
2102 ct->dst.ipaddr = in6_addr_all_DHCP_relay_servers;
2103 return E_OK;
2104 }
2105
2106/*
2107 * send_solicit_msg -- SOLICIT メッセージを送信する。
2108 */
2109
2110static void
2111send_solicit_msg (T_DHCP6_CLI_CONTEXT *ct)
2112{
2113 ER error;
2114
2115 ct->flags &= ~DHCP6C_FLAG_TMOUT_MASK;
2116 ct->error = E_OK;
2117
2118 /* ADVERTISE メッセージの選択が終了していれば、SELECT 状æ…
2119‹ã«é·ç§»ã™ã‚‹ã€‚*/
2120 if (select_adv(ct)) {
2121
2122 /* ADVERTISE メッセージ受信タイマーを停止する。*/
2123 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
2124 ct->timers[DHCP6C_TIMER_RCV_ADV] = 0;
2125 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
2126
2127 /* REQUEST メッセージを送信して SELECT 状æ…
2128‹ã«é·ç§»ã™ã‚‹ã€‚*/
2129 start_select(ct);
2130 return;
2131 }
2132
2133 /* 再送信回数を確認する。*/
2134 if ((ct->MRC != 0) && (ct->txcount > ct->MRC)) {
2135 ct->error = E_TMOUT;
2136 return;
2137 }
2138
2139 /* SOLICIT メッセージを作成する。*/
2140 if ((error = setup_solicit_msg(ct, NULL)) != E_OK) {
2141 syslog(LOG_NOTICE, "[DHCP6C] error, setup solicit message: %s.", itron_strerror(error));
2142 ct->error = error;
2143 return;
2144 }
2145
2146 /* SOLICIT メッセージを送信する。*/
2147 error = UDP_SND_DAT(ct->cepid, &ct->dst, &ct->snd_msg->msg, ct->snd_msg->len, TMO_NBLK);
2148 if (error != E_WBLK) {
2149 syslog(LOG_NOTICE, "[DHCP6C] error, send solicit message: %s.", itron_strerror(error));
2150 ct->error = error;
2151 return;
2152 }
2153
2154 /* 再送信タイムアウトを設定する。*/
2155 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
2156 ct->timers[DHCP6C_TIMER_SND_SOL] = SYSTIM2TIMER(ct->RT);
2157 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
2158
2159 /* 再送信タイムアウトを更新する。*/
2160 advance_retrans(ct);
2161 }
2162
2163/*
2164 * request_ia_option -- REQUEST メッセージの IA_NA/IA_TA/IA_PD オプションのå…
2165±é€šéƒ¨åˆ†ã‚’追加する。
2166 */
2167
2168#if defined(DHCP6_CLI_CFG_IA_NA) || defined(DHCP6_CLI_CFG_IA_TA) || defined(DHCP6_CLI_CFG_IA_PD)
2169
2170static uint8_t *
2171request_ia_option (T_DHCP6_CLI_CONTEXT *ct, uint8_t *msg, uint_t code, uint8_t *lease)
2172{
2173 T_DHCP6_OPT_IA_NA_PD *dst, *src;
2174
2175 dst = (T_DHCP6_OPT_IA_NA_PD*)msg;
2176 src = (T_DHCP6_OPT_IA_NA_PD*)lease;
2177
2178 /* オプションコードを設定する。*/
2179 HOST2MSG16(dst->code, code);
2180
2181 /* IA_NAIA_TA/IA_PD オプションを除いたオプション長を設定する。*/
2182 HOST2MSG16(dst->len, sizeof(*dst) - (sizeof(dst->code) + sizeof(dst->len)));
2183
2184 /* ADVERTISE メッセージから IA ID をコピーする。*/
2185 memcpy(&dst->iaid, &src->iaid, sizeof(src->iaid));
2186
2187 return msg + sizeof(uint16_t) * 2 + sizeof(uint32_t);
2188 }
2189
2190#endif /* of #if defined(DHCP6_CLI_CFG_IA_NA) || defined(DHCP6_CLI_CFG_IA_TA) || defined(DHCP6_CLI_CFG_IA_PD) */
2191
2192/*
2193 * request_ia_na_pd -- REQUEST メッセージの IA_NA/IA_PD オプションを追加する。
2194 */
2195
2196#if defined(DHCP6_CLI_CFG_IA_NA) || defined(DHCP6_CLI_CFG_IA_PD)
2197
2198static uint8_t *
2199request_ia_na_pd (T_DHCP6_CLI_CONTEXT *ct, uint8_t *msg, uint_t msg_type, uint_t opt_code, T_DHCP6_CLI_MSG *lease)
2200{
2201 T_DHCP6_OPT_IA_NA_PD *dia, *sia;
2202 T_DHCP6_OPT_IAADDR *diaa, *siaa;
2203 uint8_t *opt;
2204 uint32_t t1, t2;
2205 uint_t ix, nsiaa;
2206
2207 /* ADVERTISE メッセージに指定されたオプションがあることを確認する。*/
2208 if ((opt = find_msg_option(lease, opt_code, 0)) == NULL)
2209 return msg;
2210
2211 /* IA_NA/IA_TA/IA_PD オプションのå…
2212±é€šéƒ¨åˆ†ã‚’追加する。*/
2213 dia = (T_DHCP6_OPT_IA_NA_PD*)msg;
2214 sia = (T_DHCP6_OPT_IA_NA_PD*)opt;
2215 msg = request_ia_option(ct, msg, opt_code, opt);
2216
2217 /* T1、T2 を決定する。*/
2218 switch (msg_type) {
2219 case DHCP6_REQUEST:
2220 case DHCP6_RENEW:
2221 case DHCP6_REBIND:
2222 t1 = SYSTIM2TIMER(TMO_DHCP6C_REQ_LEASE);
2223 t2 = t1 + (t1 / 2);
2224 break;
2225
2226 case DHCP6_CONFIRM:
2227 case DHCP6_RELEASE:
2228 case DHCP6_DECLINE:
2229 t1 = t2 = 0;
2230 break;
2231
2232 default:
2233 syslog(LOG_NOTICE, "[DHCP6C] unkown msg_type in setup IA_NA/IA_PD for request message: %d.", msg_type);
2234 return NULL;
2235 break;
2236 }
2237
2238 /* T1、T2 を設定する。*/
2239 HOST2MSG32(dia->renew, t1);
2240 HOST2MSG32(dia->rebind, t2);
2241 msg += sizeof(dia->renew) + sizeof(dia->rebind);
2242
2243 /* IAADDR オプションを設定する。*/
2244 nsiaa = ((MSG2HOST16(sia->len) & ~DHCP6C_IAA_FLAG_MASK) - (sizeof(*sia) - (sizeof(sia->code) + sizeof(sia->len)))) / sizeof(*siaa);
2245
2246 for (ix = 0; ix <nsiaa; ix++) {
2247 diaa = (T_DHCP6_OPT_IAADDR*)(msg + sizeof(*diaa) * ix);
2248 siaa = (T_DHCP6_OPT_IAADDR*)((opt + sizeof(*sia)) + sizeof(*siaa) * ix);
2249
2250 /* アドレスの有効期限が切れていればスキップする。*/
2251 if (MSG2HOST16(siaa->len) & DHCP6C_IAA_FLAG_EXPIRED)
2252 continue;
2253
2254 /* コードと長さを設定する。*/
2255 memcpy(&diaa->code, &siaa->code, sizeof(siaa->code));
2256 HOST2MSG16(diaa->len, MSG2HOST16(siaa->len) & ~DHCP6C_IAA_FLAG_MASK);
2257 msg += sizeof(dia->code) + sizeof(dia->len);
2258
2259 /* IPv6 アドレスをコピーする。*/
2260 memcpy(&diaa->addr, &siaa->addr, sizeof(siaa->addr));
2261 msg += sizeof(diaa->addr);
2262
2263 /* T1、T2 を決定する。*/
2264 switch (msg_type) {
2265 case DHCP6_REQUEST:
2266 case DHCP6_RENEW:
2267 case DHCP6_REBIND:
2268 t1 = SYSTIM2TIMER(TMO_DHCP6C_REQ_LEASE);
2269 t2 = t1 + 300;
2270 break;
2271
2272 case DHCP6_CONFIRM:
2273 case DHCP6_RELEASE:
2274 case DHCP6_DECLINE:
2275 t1 = t2 = 0;
2276 break;
2277
2278 default:
2279 syslog(LOG_NOTICE, "[DHCP6C] unknown msg_type in setup IA_NA/IA_PD for request: %d.", msg_type);
2280 return NULL;
2281 break;
2282 }
2283
2284 /* T1、T2 を設定する。*/
2285 HOST2MSG32(diaa->prefer, t1);
2286 HOST2MSG32(diaa->valid, t2);
2287 msg += sizeof(diaa->prefer) + sizeof(diaa->valid);
2288
2289 /* IAADDR に付加オプションを追加する【å…
2290ˆé€ã‚Šã€‘。*/
2291 }
2292
2293 HOST2MSG16(((T_DHCP6_OPTION*)dia)->len,
2294 MSG2HOST16(((T_DHCP6_OPTION*)dia)->len) + (msg - (uint8_t*)dia) - sizeof(*dia));
2295 return msg;
2296 }
2297
2298#endif /* of #if defined(DHCP6_CLI_CFG_IA_NA) || defined(DHCP6_CLI_CFG_IA_PD) */
2299
2300/*
2301 * request_ia_ta -- REQUEST メッセージの IA_TA オプションを追加する。
2302 */
2303
2304#if defined(DHCP6_CLI_CFG_IA_TA)
2305
2306static uint8_t *
2307request_ia_ta (T_DHCP6_CLI_CONTEXT *ct, uint8_t *msg, uint_t msg_type, T_DHCP6_CLI_MSG *lease)
2308{
2309 T_DHCP6_OPT_IA_TA *dia, *sia;
2310 T_DHCP6_OPT_IAADDR *diaa, *siaa;
2311 uint8_t *opt;
2312 uint32_t t1, t2;
2313 uint_t ix, nsiaa;
2314
2315 /* ADVERTISE メッセージに IA_TA オプションがあることを確認する。*/
2316 if ((opt = find_msg_option(lease, DHCP6_OPT_IA_TA, 0)) == NULL)
2317 return msg;
2318
2319 /* IA_NA/IA_TA/IA_PD オプションのå…
2320±é€šéƒ¨åˆ†ã‚’追加する。*/
2321 dia = (T_DHCP6_OPT_IA_TA*)msg;
2322 sia = (T_DHCP6_OPT_IA_TA*)opt;
2323 msg = request_ia_option(ct, msg, DHCP6_OPT_IA_TA, opt);
2324
2325 /* IAADDR オプションを設定する。*/
2326 nsiaa = ((MSG2HOST16(sia->len) & ~DHCP6C_IAA_FLAG_MASK) - (sizeof(*sia) - (sizeof(sia->code) + sizeof(sia->len)))) / sizeof(*siaa);
2327
2328 for (ix = 0; ix <nsiaa; ix++) {
2329 diaa = (T_DHCP6_OPT_IAADDR*)(msg + sizeof(*diaa) * ix);
2330 siaa = (T_DHCP6_OPT_IAADDR*)((opt + sizeof(*sia)) + sizeof(*siaa) * ix);
2331
2332 /* アドレスの有効期限が切れていればスキップする。*/
2333 if (MSG2HOST16(siaa->len) & DHCP6C_IAA_FLAG_EXPIRED)
2334 continue;
2335
2336 /* コードと長さを設定する。*/
2337 memcpy(diaa->code, siaa->code, sizeof(siaa->code));
2338 diaa->len = HOST2MSG16(MSG2HOST16(siaa->len) & ~DHCP6C_IAA_FLAG_MASK);
2339 msg += sizeof(dia->code) + sizeof(dia->len);
2340
2341 /* IPv6 アドレスをコピーする。*/
2342 memcpy(diaa->addr, siaa->addr, sizeof(siaa->addr));
2343 msg += sizeof(diaa->addr);
2344
2345 /* T1、T2 を決定する。*/
2346 switch (msg_type) {
2347 case DHCP6_REQUEST:
2348 case DHCP6_RENEW:
2349 case DHCP6_REBIND:
2350 t1 = SYSTIM2TIMER(TMO_DHCP6C_REQ_LEASE);
2351 t2 = t1 + 300;
2352 break;
2353
2354 case DHCP6_CONFIRM:
2355 case DHCP6_RELEASE:
2356 case DHCP6_DECLINE:
2357 t1 = t2 = 0;
2358 break;
2359
2360 default:
2361 syslog(LOG_NOTICE, "[DHCP6C] unknown msg_type in setup IA_TA for request message: %d.", msg_type);
2362 return NULL;
2363 break;
2364 }
2365
2366 /* T1、T2 を設定する。*/
2367 HOST2MSG32(diaa->prefer, t1);
2368 HOST2MSG32(diaa->valid, t2);
2369 msg += sizeof(diaa->prefer) + sizeof(diaa->valid);
2370
2371 /* IAADDR に付加オプションを追加する【å…
2372ˆé€ã‚Šã€‘。*/
2373 }
2374
2375 return msg;
2376 }
2377
2378#endif /* of #if defined(DHCP6_CLI_CFG_IA_TA) */
2379
2380/*
2381 * setup_request_msg -- REQUEST メッセージを作成する。
2382 */
2383
2384static ER
2385setup_request_msg (T_DHCP6_CLI_CONTEXT *ct, T_DHCP6_CLI_MSG *lease, uint_t type)
2386{
2387 uint8_t *msg;
2388
2389 /* メッセージのヘッダ部分を作成する。*/
2390 if ((msg = setup_msg_header(ct, type)) == NULL)
2391 return E_PAR;
2392
2393 if ((msg = common_options(ct, msg, type, lease)) == NULL)
2394 return E_PAR;
2395
2396#if defined(DHCP6_CLI_CFG_IA_NA)
2397
2398 /* IA_NA を追加する。*/
2399 msg = request_ia_na_pd(ct, msg, type, DHCP6_OPT_IA_NA, lease);
2400#endif
2401
2402#if defined(DHCP6_CLI_CFG_IA_TA)
2403
2404 /* IA_TA を追加する。*/
2405 msg = request_ia_ta(ct, msg, type, lease);
2406#endif
2407
2408#if defined(DHCP6_CLI_CFG_IA_PD)
2409
2410 /* IA_PD を追加する。*/
2411 msg = request_ia_na_pd(ct, msg, type, DHCP6_OPT_IA_PD, lease);
2412#endif
2413
2414 /* メッセージ構造体長を設定する。*/
2415 ct->snd_msg->len = msg - (uint8_t*)&ct->snd_msg->msg;
2416 return E_OK;
2417 }
2418
2419/*
2420 * send_request_msg -- REQUEST メッセージを送信する。
2421 */
2422
2423static void
2424send_request_msg (T_DHCP6_CLI_CONTEXT *ct)
2425{
2426 ER error;
2427
2428 ct->error = E_OK;
2429 ct->flags &= ~DHCP6C_FLAG_TMOUT_MASK;
2430
2431 /* ADVERTISE メッセージを受信していなければエラー */
2432 if (ct->adv_msg == NULL) {
2433 ct->error = E_OBJ;
2434 return;
2435 }
2436
2437 /* REPLY メッセージの選択が終了していれば、BOUND 状æ…
2438‹ã«é·ç§»ã™ã‚‹ã€‚*/
2439 if (select_reply(ct)) {
2440
2441 /* REPLY メッセージ受信タイマーを停止する。*/
2442 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
2443 ct->timers[DHCP6C_TIMER_RCV_REPLY] = 0;
2444 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
2445
2446 /* ADVERTISE メッセージを受信メッセージ構造体リストに戻す。*/
2447 syscall(wai_sem(SEM_DHCP6_CLI_LOCK));
2448 ct->adv_msg->next = ct->rcv_lst;
2449 ct->rcv_lst = ct->adv_msg;
2450 ct->adv_msg = NULL;
2451 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
2452
2453 /* BOUND 状æ…
2454‹ã«é·ç§»ã™ã‚‹ã€‚*/
2455 start_bound(ct);
2456 return;
2457 }
2458
2459 /* 再送信回数を確認する。*/
2460 if ((ct->MRC != 0) && (ct->txcount > ct->MRC)) {
2461 ct->error = E_TMOUT;
2462 return;
2463 }
2464
2465 /* REQUEST メッセージを作成する。*/
2466 if ((error = setup_request_msg(ct, ct->adv_msg, DHCP6_REQUEST)) != E_OK) {
2467 syslog(LOG_NOTICE, "[DHCP6C] error, setup request message: %s.", itron_strerror(error));
2468 ct->error = error;
2469 return;
2470 }
2471
2472 /* REQUEST メッセージを送信する。*/
2473 error = UDP_SND_DAT(ct->cepid, &ct->dst, &ct->snd_msg->msg, ct->snd_msg->len, TMO_NBLK);
2474 if (error != E_WBLK) {
2475 syslog(LOG_NOTICE, "[DHCP6C] error, send request message: %s.", itron_strerror(error));
2476 ct->error = error;
2477 return;
2478 }
2479
2480 /* 再送信タイムアウトを設定する。*/
2481 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
2482 ct->timers[DHCP6C_TIMER_SND_REQ] = SYSTIM2TIMER(ct->RT);
2483 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
2484
2485 /* 再送信タイムアウトを更新する。*/
2486 advance_retrans(ct);
2487 }
2488
2489/*
2490 * send_refresh_msg -- REFRESH メッセージを送信する。
2491 */
2492
2493static void
2494send_refresh_msg (T_DHCP6_CLI_CONTEXT *ct)
2495{
2496 T_DHCP6_OPT_UNICAST *uc;
2497 ER error;
2498 uint8_t *opt;
2499
2500 /* 有効なリース情
2501報がなければエラー */
2502 ct->flags &= ~DHCP6C_FLAG_TMOUT_MASK;
2503 if (ct->act_msg == NULL)
2504 ct->error = E_OBJ;
2505
2506 /* REFRESH タイプが RENEW または REBIND でなければエラー */
2507 if (!((ct->refresh_type == DHCP6_RENEW) || (ct->refresh_type == DHCP6_REBIND)))
2508 ct->error = E_PAR;
2509
2510 /* REPLY メッセージの選択が終了していれば、BOUND 状æ…
2511‹ã«é·ç§»ã™ã‚‹ã€‚*/
2512 if (select_reply(ct)) {
2513
2514 /* REPLY メッセージ受信タイマーを停止する。*/
2515 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
2516 ct->timers[DHCP6C_TIMER_RCV_REPLY] = 0;
2517 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
2518
2519 /* リース情
2520報を解放する。*/
2521 rel_lease(ct);
2522
2523 /* BOUND 状æ…
2524‹ã«é·ç§»ã™ã‚‹ã€‚*/
2525 start_bound(ct);
2526 return;
2527 }
2528
2529 /* 再送信回数を確認する。*/
2530 if ((ct->MRC != 0) && (ct->txcount > ct->MRC)) {
2531 eval_expire(ct);
2532 return;
2533 }
2534
2535 /*
2536 * サーバから UNICAST オプションを受信したときは
2537 * 指定したアドレスを送信å…
2538ˆã‚¢ãƒ‰ãƒ¬ã‚¹ã«è¨­å®šã™ã‚‹ã€‚
2539 */
2540 if ((opt = find_msg_option(ct->act_msg, DHCP6_OPT_UNICAST, sizeof(T_DHCP6_OPT_UNICAST))) != NULL) {
2541 uc = (T_DHCP6_OPT_UNICAST*)opt;
2542 ct->dst.ipaddr = uc->addr;
2543 }
2544
2545 /* REFRESH (REQUEST) メッセージを作成する。*/
2546 if ((error = setup_request_msg(ct, ct->act_msg, ct->refresh_type)) != E_OK) {
2547 syslog(LOG_NOTICE, "[DHCP6C] error, setup refresh message: %s.", itron_strerror(error));
2548 ct->error = error;
2549 return;
2550 }
2551
2552 /* REFRESH メッセージを送信する。*/
2553 error = UDP_SND_DAT(ct->cepid, &ct->dst, &ct->snd_msg->msg, ct->snd_msg->len, TMO_NBLK);
2554 if (error != E_WBLK) {
2555 syslog(LOG_NOTICE, "[DHCP6C] error, send refresh message: %s.", itron_strerror(error));
2556 ct->error = error;
2557 return;
2558 }
2559
2560 /* 再送信タイムアウトを設定する。*/
2561 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
2562 ct->timers[DHCP6C_TIMER_SND_REF] = SYSTIM2TIMER(ct->RT);
2563 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
2564
2565 /* 再送信タイムアウトを更新する。*/
2566 advance_retrans(ct);
2567 }
2568
2569/*
2570 * setup_release_msg -- RELEASE メッセージを作成する。
2571 */
2572
2573static ER
2574setup_release_msg (T_DHCP6_CLI_CONTEXT *ct, T_DHCP6_CLI_MSG *lease, uint_t type)
2575{
2576 uint8_t *msg;
2577
2578 /* メッセージのヘッダ部分を作成する。*/
2579 if ((msg = setup_msg_header(ct, type)) == NULL)
2580 return E_PAR;
2581
2582 if ((msg = common_options(ct, msg, type, lease)) == NULL)
2583 return E_PAR;
2584
2585#if defined(DHCP6_CLI_CFG_IA_NA)
2586
2587 /* IA_NA を追加する。*/
2588 msg = request_ia_na_pd(ct, msg, type, DHCP6_OPT_IA_NA, lease);
2589#endif
2590
2591#if defined(DHCP6_CLI_CFG_IA_PD)
2592
2593 /* IA_PD を追加する。*/
2594 msg = request_ia_na_pd(ct, msg, type, DHCP6_OPT_IA_PD, lease);
2595#endif
2596
2597 /* メッセージ構造体長を設定する。*/
2598 ct->snd_msg->len = msg - (uint8_t*)&ct->snd_msg->msg;
2599 return E_OK;
2600 }
2601
2602/*
2603 * send_release_msg -- RELEASE メッセージを送信する。
2604 */
2605
2606static void
2607send_release_msg (T_DHCP6_CLI_CONTEXT *ct)
2608{
2609 ER error;
2610
2611 /* 有効な REPLY メッセージを受信していなければエラー */
2612 ct->flags &= ~DHCP6C_FLAG_TMOUT_MASK;
2613 if (ct->act_msg == NULL)
2614 ct->error = E_OBJ;
2615
2616 /* 有効な REPLY メッセージを受信していれば、SLEEP 状æ…
2617‹ã«é·ç§»ã™ã‚‹ã€‚*/
2618 syscall(wai_sem(SEM_DHCP6_CLI_LOCK));
2619 if (ct->prf_lst != NULL) {
2620
2621 /* 再送信タイマーを停止する。*/
2622 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
2623 ct->timers[DHCP6C_TIMER_RCV_REPLY] = 0;
2624 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
2625
2626 /* 有効なリース・メッセージ構造体を解放する。*/
2627 if (ct->act_msg != NULL) {
2628 syscall(rel_mpf(MPF_DHCP6_CLI_MSG, (void*)ct->act_msg));
2629 ct->act_msg = NULL;
2630 }
2631
2632 /* SLEEP 状æ…
2633‹ã«é·ç§»ã™ã‚‹ã€‚*/
2634 ct->fsm = DHCP6_FSM_SLEEP;
2635 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
2636 return;
2637 }
2638 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
2639
2640 /* 再送信回数を確認する。*/
2641 if ((ct->MRC != 0) && (ct->txcount > ct->MRC)) {
2642 ct->error = E_TMOUT;
2643 return;
2644 }
2645
2646 /* RELEASE メッセージを作成する。*/
2647 if ((error = setup_release_msg(ct, ct->act_msg, DHCP6_RELEASE)) != E_OK) {
2648 syslog(LOG_NOTICE, "[DHCP6C] error, setup release message: %s.", itron_strerror(error));
2649 ct->error = error;
2650 return;
2651 }
2652
2653 /* RELEASE メッセージを送信する。*/
2654 error = UDP_SND_DAT(ct->cepid, &ct->dst, &ct->snd_msg->msg, ct->snd_msg->len, TMO_NBLK);
2655 if (error != E_WBLK) {
2656 syslog(LOG_NOTICE, "[DHCP6C] error, send release message: %s.", itron_strerror(error));
2657 ct->error = error;
2658 return;
2659 }
2660
2661 /* 再送信タイムアウトを設定する。*/
2662 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
2663 ct->timers[DHCP6C_TIMER_SND_REL] = SYSTIM2TIMER(ct->RT);
2664 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
2665
2666 /* 再送信タイムアウトを更新する。*/
2667 advance_retrans(ct);
2668 }
2669
2670/*
2671 * advertise_msg_timeout -- ADVERTISE メッセージのタイムアウト処理
2672 */
2673
2674static void
2675advertise_msg_timeout (T_DHCP6_CLI_CONTEXT *ct)
2676{
2677 /* SOLICIT メッセージ送信タイマーを停止する。*/
2678 ct->flags &= ~DHCP6C_FLAG_TMOUT_MASK;
2679 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
2680 ct->timers[DHCP6C_TIMER_SND_SOL] = 0;
2681 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
2682
2683 if (select_adv(ct)) {
2684 /*
2685 * ADVERTISE メッセージの選択が終了していれば、
2686 * REQUEST メッセージを送信して SELECT 状æ…
2687‹ã«é·ç§»ã™ã‚‹ã€‚
2688 */
2689 start_select(ct);
2690 }
2691 else
2692 ct->error = E_TMOUT;
2693 }
2694
2695/*
2696 * renew_timeout -- RENEW タイムアウト処理
2697 */
2698
2699static void
2700renew_timeout (T_DHCP6_CLI_CONTEXT *ct)
2701{
2702 /* RENEW 状æ…
2703‹ã«é·ç§»ã™ã‚‹ã€‚*/
2704 ct->flags &= ~DHCP6C_FLAG_TMOUT_MASK;
2705 start_renew(ct);
2706 }
2707
2708/*
2709 * rebind_timeout -- REBIND タイムアウト処理
2710 */
2711
2712static void
2713rebind_timeout (T_DHCP6_CLI_CONTEXT *ct)
2714{
2715 /* REBIND 状æ…
2716‹ã«é·ç§»ã™ã‚‹ã€‚*/
2717 ct->flags &= ~DHCP6C_FLAG_TMOUT_MASK;
2718 start_rebind(ct);
2719 }
2720
2721/*
2722 * depref_timeout -- DEPREF タイムアウト処理
2723 */
2724
2725static void
2726depref_timeout (T_DHCP6_CLI_CONTEXT *ct)
2727{
2728 T_DHCP6_OPTION *opt;
2729 T_DHCP6_OPT_IA_NA_PD *ia;
2730 T_DHCP6_OPT_IAADDR *iaa;
2731 SYSTIM time;
2732 uint8_t *msg, *last;
2733 uint_t aoff, asize;
2734
2735 /* 有効なリースが無ければ処理終了 */
2736 ct->flags &= ~DHCP6C_FLAG_TMOUT_MASK;
2737 if (ct->act_msg == NULL) {
2738 return;
2739 }
2740
2741 get_tim(&time);
2742 msg = ct->act_msg->msg.options;
2743 last = msg + (ct->act_msg->len - sizeof(T_DHCP6_MSG_HDR));
2744 while (msg < last) {
2745
2746 /* IA_NA/IA_PD オプションであれば、推奨有効時間を確認する。*/
2747 opt = (T_DHCP6_OPTION*)msg;
2748 if (MSG2HOST16(opt->code) == DHCP6_OPT_IA_NA || MSG2HOST16(opt->code) == DHCP6_OPT_IA_PD) {
2749
2750 ia = (T_DHCP6_OPT_IA_NA_PD*)opt;
2751 asize = MSG2HOST16(ia->len) + sizeof(*opt);
2752 for (aoff = sizeof(*ia); aoff < asize;
2753 aoff += (MSG2HOST16(iaa->len) & ~DHCP6C_IAA_FLAG_MASK) + sizeof(*iaa)) {
2754
2755 /* すでに推奨有効時間を経過していれば処理しない。*/
2756 iaa = (T_DHCP6_OPT_IAADDR*)((uint8_t*)opt + aoff);
2757 if ((MSG2HOST16(iaa->len) & DHCP6C_IAA_FLAG_DEPREFERD))
2758 continue;
2759
2760 /* 推奨有効時間経過していれば FLAG を設定する。*/
2761 if (TIMEC_GE(time, ct->act_msg->rcv_time + MSG2HOST32(iaa->prefer))) {
2762 HOST2MSG16(iaa->len, MSG2HOST16(iaa->len) | DHCP6C_IAA_FLAG_DEPREFERD);
2763 if (MSG2HOST16(ia->code) == DHCP6_OPT_IA_NA)
2764 syslog(LOG_NOTICE, "[DHCP6C] address depreferd: %s.", ipv62str(NULL, &iaa->addr));
2765 else
2766 syslog(LOG_NOTICE, "[DHCP6C] prefix depreferd: %s.", ipv62str(NULL, &iaa->addr));
2767
2768 /*【DNS の処理が必
2769要】*/
2770 }
2771 }
2772 }
2773 msg += MSG2HOST16(opt->len) + sizeof(*opt);
2774 }
2775
2776 eval_expire(ct);
2777 }
2778
2779/*
2780 * expire_timeout -- EXPIRE タイムアウト処理
2781 */
2782
2783static void
2784expire_timeout (T_DHCP6_CLI_CONTEXT *ct)
2785{
2786 T_DHCP6_OPTION *opt;
2787 T_DHCP6_OPT_IA_NA_PD *ia;
2788 T_DHCP6_OPT_IAADDR *iaa;
2789 SYSTIM time;
2790 uint8_t *msg, *last;
2791 uint_t aoff, asize, addrs = 0;
2792
2793 /* 有効なリースが無ければ処理終了 */
2794 ct->flags &= ~DHCP6C_FLAG_TMOUT_MASK;
2795 if (ct->act_msg == NULL) {
2796 return;
2797 }
2798
2799 get_tim(&time);
2800 msg = ct->act_msg->msg.options;
2801 last = msg + (ct->act_msg->len - sizeof(T_DHCP6_MSG_HDR));
2802 while (msg < last) {
2803
2804 /* IA_NA/IA_PD オプションであれば、有効時間を確認する。*/
2805 opt = (T_DHCP6_OPTION*)msg;
2806 if (MSG2HOST16(opt->code) == DHCP6_OPT_IA_NA || MSG2HOST16(opt->code) == DHCP6_OPT_IA_PD) {
2807
2808 ia = (T_DHCP6_OPT_IA_NA_PD*)opt;
2809 asize = MSG2HOST16(ia->len) + sizeof(*opt);
2810 for (aoff = sizeof(*ia); aoff < asize;
2811 aoff += (MSG2HOST16(iaa->len) & ~DHCP6C_IAA_FLAG_MASK) + sizeof(*iaa)) {
2812
2813 /* すでに有効時間を経過していれば処理しない。*/
2814 iaa = (T_DHCP6_OPT_IAADDR*)((uint8_t*)opt + aoff);
2815 if ((MSG2HOST16(iaa->len) & DHCP6C_IAA_FLAG_EXPIRED))
2816 continue;
2817
2818 /* 有効時間経過していれば FLAG を設定する。*/
2819 if (TIMEC_GE(time, ct->act_msg->rcv_time + MSG2HOST32(iaa->valid))) {
2820 HOST2MSG16(iaa->len, MSG2HOST16(iaa->len) | DHCP6C_IAA_FLAG_EXPIRED);
2821 if (MSG2HOST16(ia->code) == DHCP6_OPT_IA_NA)
2822 syslog(LOG_NOTICE, "[DHCP6C] address expired: %s.", ipv62str(NULL, &iaa->addr));
2823 else
2824 syslog(LOG_NOTICE, "[DHCP6C] prefix expired: %s.", ipv62str(NULL, &iaa->addr));
2825
2826 /*【DNS の処理が必
2827要】*/
2828 continue;
2829 }
2830 addrs ++;
2831 }
2832 }
2833 msg += MSG2HOST16(opt->len) + sizeof(*opt);
2834 }
2835
2836 /* 有効なアドレスがå…
2837¨ã¦ç„¡ããªã£ãŸæ™‚は INIT 状æ…
2838‹ã«é·ç§»ã™ã‚‹ã€‚*/
2839 if (addrs == 0) {
2840
2841 /* ACTIVE リースを受信メッセージ構造体リストに戻す。*/
2842 syslog(LOG_NOTICE, "[DHCP6C] all address expired.");
2843 syscall(wai_sem(SEM_DHCP6_CLI_LOCK));
2844 ct->act_msg->next = ct->rcv_lst;
2845 ct->rcv_lst = ct->act_msg;
2846 ct->act_msg = NULL;
2847 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
2848
2849 /* å…
2850¨ã¦ã® TIMER をキャンセルする。*/
2851 cancel_all_timers(ct);
2852
2853 /* INIT 状æ…
2854‹ã«é·ç§»ã™ã‚‹ã€‚*/
2855 start_init(ct);
2856 return;
2857 }
2858
2859 eval_expire(ct);
2860 }
2861
2862#endif /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL || DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_RA */
2863
2864/*
2865 * reply_msg_timeout -- REPLY メッセージのタイムアウト処理
2866 */
2867
2868static void
2869reply_msg_timeout (T_DHCP6_CLI_CONTEXT *ct)
2870{
2871 /* SOLICIT メッセージ送信タイマーを停止する。*/
2872 ct->flags &= ~DHCP6C_FLAG_TMOUT_MASK;
2873 syscall(wai_sem(SEM_DHCP6_CLI_TIMER));
2874 ct->timers[DHCP6C_TIMER_SND_REQ] = 0;
2875 ct->timers[DHCP6C_TIMER_SND_REF] = 0;
2876 syscall(sig_sem(SEM_DHCP6_CLI_TIMER));
2877
2878#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS || DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_RA
2879
2880 /* STATELES モードではSLEEP に遷移する。*/
2881 ct->error = E_TMOUT;
2882 ct->fsm = DHCP6_FSM_SLEEP;
2883
2884#endif /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS || DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_RA */
2885
2886#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL || DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_RA
2887
2888 /* RENEW メッセージの選択が終了していれば、BOUND 状æ…
2889‹ã«é·ç§»ã™ã‚‹ã€‚*/
2890 if (select_reply(ct)) {
2891
2892 /* リース情
2893報を解放する。*/
2894 rel_lease(ct);
2895
2896 /* BOUND 状æ…
2897‹ã«é·ç§»ã™ã‚‹ã€‚*/
2898 start_bound(ct);
2899 }
2900 else if (ct->fsm == DHCP6_FSM_RENEW || ct->fsm == DHCP6_FSM_REBIND)
2901 eval_expire(ct);
2902 else {
2903 /* SLEEP に遷移する。*/
2904 ct->error = E_TMOUT;
2905 ct->fsm = DHCP6_FSM_SLEEP;
2906 }
2907
2908#endif /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL || DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_RA */
2909 }
2910
2911/*
2912 * dispatch_timeout -- タイムアウトした時の処理
2913 */
2914
2915static ER
2916dispatch_timeout (T_DHCP6_CLI_CONTEXT *ct)
2917{
2918
2919 switch (ct->flags & DHCP6C_FLAG_TMOUT_TIMER_MASK) {
2920
2921#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS || DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_RA
2922
2923 case DHCP6C_TIMER_SND_IREQ:
2924 send_info_req_msg(ct);
2925 break;
2926
2927#endif /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS || DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_RA */
2928
2929#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL || DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_RA
2930
2931 case DHCP6C_TIMER_SND_SOL:
2932 send_solicit_msg(ct);
2933 break;
2934
2935 case DHCP6C_TIMER_SND_REQ:
2936 send_request_msg(ct);
2937 break;
2938
2939 case DHCP6C_TIMER_SND_REF:
2940 send_refresh_msg(ct);
2941 break;
2942
2943 case DHCP6C_TIMER_SND_REL:
2944 send_release_msg(ct);
2945 break;
2946
2947 case DHCP6C_TIMER_RCV_ADV:
2948 advertise_msg_timeout(ct);
2949 break;
2950
2951 case DHCP6C_TIMER_RENEW:
2952 renew_timeout(ct);
2953 break;
2954
2955 case DHCP6C_TIMER_REBIND:
2956 rebind_timeout(ct);
2957 break;
2958
2959 case DHCP6C_TIMER_DEPREF:
2960 depref_timeout(ct);
2961 break;
2962
2963 case DHCP6C_TIMER_EXPIRE:
2964 expire_timeout(ct);
2965 break;
2966
2967#endif /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL || DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_RA */
2968
2969 case DHCP6C_TIMER_RCV_REPLY:
2970 reply_msg_timeout(ct);
2971 break;
2972
2973 default:
2974 syslog(LOG_NOTICE, "[DHCP6C] error, unknown timeout: %d.", ct->flags & DHCP6C_FLAG_TMOUT_TIMER_MASK);
2975 break;
2976 }
2977
2978 return ct->error;
2979 }
2980
2981/*
2982 * dispatch_event -- イベント毎の処理
2983 */
2984
2985static ER
2986dispatch_event (T_DHCP6_CLI_CONTEXT *ct)
2987{
2988 ER error = E_OK;
2989
2990 while (ct->fsm != DHCP6_FSM_SLEEP && error == E_OK) {
2991
2992 /* メッセージの送受信とタイムアウトを待
2993つ。*/
2994 syscall(wai_sem(SEM_DHCP6_CLI_READY));
2995
2996 if (ct->flags & DHCP6C_FLAG_RCV_MSG) {
2997 while (ct->val_lst != NULL) {
2998 error = eval_rcv_msg(ct);
2999 }
3000 ct->flags &= ~DHCP6C_FLAG_RCV_MSG;
3001 }
3002
3003 if (ct->flags & DHCP6C_FLAG_TMOUT_MASK)
3004 error = dispatch_timeout(ct);
3005
3006 if (ct->error != E_OK)
3007 error = ct->error;
3008 }
3009
3010 return error;
3011 }
3012
3013/*
3014 * init_context -- DHCPv6 クライアントコンテキスト構造体を初期化する。
3015 */
3016
3017static void
3018init_context (T_DHCP6_CLI_CONTEXT *ct, ID cepid)
3019{
3020 memset(ct, 0, sizeof(*ct));
3021 ct->cepid = cepid;
3022 ct->sc = IF_ETHER_NIC_GET_SOFTC();
3023 ct->dst.portno = DHCP6_SRV_CFG_PORTNO;
3024 }
3025
3026/*
3027 * rel_cli_msg -- メッセージ構造体を解放する。
3028 */
3029
3030static void
3031rel_cli_msg (T_DHCP6_CLI_CONTEXT *ct)
3032{
3033 T_DHCP6_CLI_MSG *ptr, *cell;
3034
3035 syscall(wai_sem(SEM_DHCP6_CLI_LOCK));
3036 for (ptr = ct->rcv_lst; ptr != NULL; ) {
3037 cell = ptr;
3038 ptr = ptr->next;
3039 syscall(rel_mpf(MPF_DHCP6_CLI_MSG, (void*)cell));
3040 }
3041
3042 for (ptr = ct->val_lst; ptr != NULL; ) {
3043 cell = ptr;
3044 ptr = ptr->next;
3045 syscall(rel_mpf(MPF_DHCP6_CLI_MSG, (void*)cell));
3046 }
3047
3048 for (ptr = ct->prf_lst; ptr != NULL; ) {
3049 cell = ptr;
3050 ptr = ptr->next;
3051 syscall(rel_mpf(MPF_DHCP6_CLI_MSG, (void*)cell));
3052 }
3053
3054 if (ct->snd_msg != NULL)
3055 syscall(rel_mpf(MPF_DHCP6_CLI_MSG, (void*)ct->snd_msg));
3056 if (ct->adv_msg != NULL)
3057 syscall(rel_mpf(MPF_DHCP6_CLI_MSG, (void*)ct->adv_msg));
3058 ct->rcv_lst = ct->prf_lst = ct->val_lst = ct->snd_msg = ct->adv_msg = NULL;
3059
3060#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS
3061
3062 /* ステートレスの時は有効なリース・メッセージ構造体も解放する。*/
3063 if (ct->act_msg != NULL) {
3064 syscall(rel_mpf(MPF_DHCP6_CLI_MSG, (void*)ct->act_msg));
3065 ct->act_msg = NULL;
3066 }
3067
3068#endif /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS */
3069
3070 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
3071 }
3072
3073/*
3074 * init_cli_msg -- 各メッセージ構造体を初期化する。
3075 */
3076
3077static ER
3078init_cli_msg (T_DHCP6_CLI_CONTEXT *ct)
3079{
3080 T_DHCP6_CLI_MSG *cell;
3081 ER error;
3082 int count;
3083
3084 /* 送信メッセージ構造体を獲得する。*/
3085 if ((error = tget_mpf(MPF_DHCP6_CLI_MSG, (void*)&ct->snd_msg, TMO_DHCP6C_MPF_GET)) != E_OK) {
3086 syslog(LOG_NOTICE, "[DHCP6C] error, tget_mpf() for send: %s.", itron_strerror(error));
3087 return error;
3088 }
3089
3090 /*
3091 * 有効なリース・メッセージ構造体がある場合は、
3092 * 獲得する受信メッセージ構造体リストの構造体を 1減らす。
3093 */
3094 if (ct->act_msg == NULL)
3095 count = NUM_DHCP6_CLI_MSG_LIST;
3096 else
3097 count = NUM_DHCP6_CLI_MSG_LIST - 1;
3098
3099 /* 受信メッセージ構造体を獲得する。*/
3100 syscall(wai_sem(SEM_DHCP6_CLI_LOCK));
3101 while (count --> 0) {
3102 if ((error = tget_mpf(MPF_DHCP6_CLI_MSG, (void*)&cell, TMO_DHCP6C_MPF_GET)) != E_OK) {
3103 syslog(LOG_NOTICE, "[DHCP6C] error, tget_mpf() for receive: %s.", itron_strerror(error));
3104 break;
3105 }
3106 cell->next = ct->rcv_lst;
3107 ct->rcv_lst = cell;
3108 }
3109 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
3110
3111 return E_OK;
3112 }
3113
3114/*
3115 * dhcp6c_renew_info -- ネットワーク情
3116報を再取得する。
3117 */
3118
3119ER
3120dhcp6c_renew_info (void)
3121{
3122
3123#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS
3124
3125 if (context.fsm == DHCP6_FSM_INFORMED) {
3126
3127 /* REL_INFO 状æ…
3128‹ã«é·ç§»ã—た後に SLEEP を解除するように設定する。*/
3129 context.flags |= DHCP6C_FLAG_RENEW;
3130 start_rel_info(&context);
3131 return E_OK;
3132 }
3133 else if (context.fsm == DHCP6_FSM_SLEEP) {
3134
3135 /* SLEEP を解除する。*/
3136 wup_tsk(DHCP6_CLI_TASK);
3137 return E_OK;
3138 }
3139 else
3140 return E_OBJ;
3141
3142#elif DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL
3143
3144 if (context.fsm == DHCP6_FSM_BOUND) {
3145
3146 /* RENEW 状æ…
3147‹ã«é·ç§»ã™ã‚‹ã€‚*/
3148 start_renew(&context);
3149 return E_OK;
3150 }
3151 else if (context.fsm == DHCP6_FSM_SLEEP) {
3152
3153 /* SLEEP を解除する。*/
3154 wup_tsk(DHCP6_CLI_TASK);
3155 return E_OK;
3156 }
3157 else
3158 return E_OBJ;
3159
3160#else /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS */
3161
3162#endif /* of #if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS */
3163
3164 }
3165
3166/*
3167 * dhcp6c_rel_info -- DHCP で設定されたネットワーク情
3168報を解放する。
3169 */
3170
3171ER
3172dhcp6c_rel_info (void)
3173{
3174 /* REL_INFO 状æ…
3175‹ã«é·ç§»ã™ã‚‹ã€‚*/
3176 start_rel_info(&context);
3177 return E_OK;
3178 }
3179
3180/*
3181 * dhcp6c_get_info -- DHCP で設定されたネットワーク情
3182報を返す。
3183 */
3184
3185ER
3186dhcp6c_get_info (T_IN6_ADDR *addr, uint32_t *expire, uint32_t *renew,
3187 uint32_t *rebind, uint32_t *deprefer, SYSTIM *bind_start)
3188{
3189 if (addr == NULL || expire == NULL || renew == NULL ||
3190 rebind == NULL || deprefer == NULL || bind_start == NULL)
3191 return E_PAR;
3192 else if (context.act_msg == NULL)
3193 return E_OBJ;
3194 else {
3195 // context.timers[DHCP6C_TIMER_EXPIRE],
3196 // context.timers[DHCP6C_TIMER_RENEW],
3197 // context.timers[DHCP6C_TIMER_REBIND],
3198 // context.timers[DHCP6C_TIMER_DEPREF]);
3199
3200 *addr = context.act_msg->srv.ipaddr;
3201 *expire = context.timers[DHCP6C_TIMER_EXPIRE];
3202 *renew = context.timers[DHCP6C_TIMER_RENEW];
3203 *rebind = context.timers[DHCP6C_TIMER_REBIND];
3204 *deprefer = context.timers[DHCP6C_TIMER_DEPREF];
3205 *bind_start = context.act_msg->rcv_time;
3206 return E_OK;
3207 }
3208 }
3209
3210/*
3211 * コールバック関数
3212 */
3213
3214ER
3215callback_nblk_dhcp6_cli (ID cepid, FN fncd, void *p_parblk)
3216{
3217 T_DHCP6_CLI_MSG *msg;
3218 ER_UINT len;
3219
3220 len = *(ER_UINT*)p_parblk;
3221 if (len < 0 && len != E_RLWAI) {
3222 /* E_RLWAI 以外で、0 以下の場合は、エラーコード */
3223 syslog(LOG_NOTICE, "[DHCP6C(CBR)] error: %s, fncd: %s.", itron_strerror(len), in_strtfn(fncd));
3224 }
3225 else {
3226 if (fncd == TEV_UDP_RCV_DAT) {
3227
3228 /* 受信メッセージリストが空の時は、受信しないでデータグラムを捨てる。*/
3229 if (context.rcv_lst == NULL)
3230 syslog(LOG_NOTICE, "[DHCP6C(CBR)] receive buffer all busy.");
3231 else {
3232 /* メッセージを受信するメッセージ構造体を準備する。*/
3233 syscall(wai_sem(SEM_DHCP6_CLI_LOCK));
3234 msg = context.rcv_lst;
3235 context.rcv_lst = context.rcv_lst->next;
3236 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
3237
3238 /* メッセージを受信する。*/
3239 len = UDP_RCV_DAT(context.cepid, &msg->srv, &msg->msg, sizeof(msg->msg), TMO_POL);
3240
3241 syscall(wai_sem(SEM_DHCP6_CLI_LOCK));
3242 msg->len = len;
3243 if (len >= 0) {
3244 /* 受信したメッセージを検証メッセージリストに移す。*/
3245 msg->next = context.val_lst;
3246 context.val_lst = msg;
3247 context.flags |= DHCP6C_FLAG_RCV_MSG;
3248 }
3249 else {
3250 /* メッセージ構造体を受信メッセージリストに戻す。*/
3251 context.error = len;
3252 msg->next = context.rcv_lst;
3253 context.rcv_lst = msg;
3254 }
3255 syscall(sig_sem(SEM_DHCP6_CLI_LOCK));
3256 }
3257 }
3258 syscall(sig_sem(SEM_DHCP6_CLI_READY));
3259 }
3260 return E_OK;
3261 }
3262/*
3263 * dhcp6_cli_task -- DHCPv6 クライアントタスク
3264 */
3265
3266void
3267dhcp6_cli_task (intptr_t exinf)
3268{
3269 T_DHCP6_CLI_CONTEXT *ct;
3270 ID tskid;
3271 ER error;
3272
3273 dly_tsk(1000);
3274 get_tid(&tskid);
3275
3276#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS
3277 syslog(LOG_NOTICE, "[DHCP6C:%d] started in stateless.", tskid);
3278#elif DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL
3279 syslog(LOG_NOTICE, "[DHCP6C:%d] started in statefull.", tskid);
3280#else
3281#endif
3282
3283 dly_tsk(500);
3284 ct = &context;
3285
3286 /* DHCP クライアントコンテキスト構造体を初期化する。*/
3287 init_context(ct, (ID)exinf);
3288
3289 while (true) {
3290
3291 /* 1秒毎にタイムアウトするようにタイマーを設定する。*/
3292 timeout((callout_func)dhcpc_timer, ct, NET_TIMER_HZ / DHCP6C_TIMER_HZ);
3293
3294 /* クライアント DUID を設定する。*/
3295 init_duid(ct);
3296
3297 /* メッセージ構造体を初期化する。*/
3298 if ((error = init_cli_msg(ct)) == E_OK) {
3299
3300#if DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATELESS
3301 start_req_info(ct);
3302#elif DHCP6_CLI_CFG_MODE == DHCP6_CLI_CFG_STATEFULL
3303 start_init(ct);
3304#else
3305#endif
3306
3307 /* メインループ */
3308 error = dispatch_event(ct);
3309 }
3310
3311 /* å…
3312¨ã¦ã® TIMER をキャンセルする。*/
3313 cancel_all_timers(ct);
3314
3315 /* タイマーを停止する。*/
3316 untimeout((callout_func)dhcpc_timer, ct);
3317
3318 /* メッセージ構造体を解放する。*/
3319 rel_cli_msg(ct);
3320
3321 /* リースを解放後、再取得が指定されていなければ休止する。*/
3322 if (!(ct->flags & DHCP6C_FLAG_RENEW)) {
3323
3324 /* 休止する。*/
3325 if (error == E_OK)
3326 syslog(LOG_NOTICE, "[DHCP6C] lease released, go to sleep.");
3327 else {
3328 syslog(LOG_NOTICE, "[DHCP6C] server not available, go to sleep, error: %s.", itron_strerror(error));
3329 ct->fsm = DHCP6_FSM_SLEEP;
3330 }
3331 slp_tsk();
3332 }
3333 ct->flags = 0;
3334 ct->error = E_OK;
3335 }
3336 }
3337
3338#endif /* of #ifdef DHCP6_CLI_CFG */
Note: See TracBrowser for help on using the repository browser.