source: asp3_tinet_ecnl_arm/trunk/asp3_dcre/tinet/netapp/dhcp6_cli.c@ 352

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

arm向けASP3版ECNLを追加

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