source: asp3_tinet_ecnl_arm/trunk/asp3_dcre/tinet/netapp/dhcp4_cli.c@ 364

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

TINETとSocket APIなどを更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 58.8 KB
Line 
1/*
2 * Copyright 2004 Henning Brauer <henning@openbsd.org>
3 * Copyright (c) 1995, 1996, 1997, 1998, 1999
4 * The Internet Software Consortium. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of The Internet Software Consortium nor the names
16 * of its contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
20 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
21 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * This software has been written for the Internet Software Consortium
34 * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
35 * Enterprises. To learn more about the Internet Software Consortium,
36 * see ``http://www.vix.com/isc''. To learn more about Vixie
37 * Enterprises, see ``http://www.vix.com''.
38 *
39 * This client was substantially modified and enhanced by Elliot Poger
40 * for use on Linux while he was working on the MosquitoNet project at
41 * Stanford.
42 *
43 * The current version owes much to Elliot's Linux enhancements, but
44 * was substantially reorganized and partially rewritten by Ted Lemon
45 * so as to use the same networking framework that the Internet Software
46 * Consortium DHCP server uses. Much system-specific configuration code
47 * was moved into a shell script so that as support for more operating
48 * systems is added, it will not be necessary to port and maintain
49 * system-specific configuration code to these operating systems - instead,
50 * the shell script can invoke the native tools to accomplish the same
51 * purpose.
52 */
53/*
54 * WIDE Project DHCP Implementation
55 * Copyright (c) 1995-1997 Akihiro Tominaga
56 * Copyright (c) 1995-1997 WIDE Project
57 * All rights reserved.
58 *
59 * Permission to use, copy, modify and distribute this software and its
60 * documentation is hereby granted, provided the following conditions
61 * are satisfied,
62 *
63 * 1. Both the copyright notice and this permission notice appear in
64 * all copies of the software, derivative works or modified versions,
65 * and any portions thereof, and that both notices appear in
66 * supporting documentation.
67 * 2. All advertising materials mentioning features or use of this software
68 * must display the following acknowledgement:
69 * This product includes software developed by WIDE Project and
70 * its contributors.
71 * 3. Neither the name of WIDE Project nor the names of its contributors
72 * may be used to endorse or promote products derived from this software
73 * without specific prior written permission.
74 *
75 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND WIDE
76 * PROJECT DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
77 * WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ALSO, THERE
78 * IS NO WARRANTY IMPLIED OR OTHERWISE, NOR IS SUPPORT PROVIDED.
79 *
80 * Feedback of the results generated from any improvements or
81 * extensions made to this software would be much appreciated.
82 * Any such feedback should be sent to:
83 *
84 * Akihiro Tominaga
85 * WIDE Project
86 * Keio University, Endo 5322, Kanagawa, Japan
87 * (E-mail: dhcp-dist@wide.ad.jp)
88 *
89 * WIDE project has the rights to redistribute these changes.
90 */
91/*
92 * TINET (TCP/IP Protocol Stack)
93 *
94 * Copyright (C) 2011 by Dep. of Computer Science and Engineering
95 * Tomakomai National College of Technology, JAPAN
96 *
97 * 上記著作権者は,以下の (1)~(4) の条件か,Free Software Foundation
98 * によって公表されている GNU General Public License の Version 2 に記
99 * 述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア
100 * を改変したものを含む.以下同じ)を使用・複製・改変・再配布(以下,
101 * 利用と呼ぶ)することを無償で許諾する.
102 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
103 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
104 * スコード中に含まれていること.
105 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
106 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
107 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
108 * の無保証規定を掲載すること.
109 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
110 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
111 * と.
112 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
113 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
114 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
115 * 報告すること.
116 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
117 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
118 *
119 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
120 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も
121 * 含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直
122 * 接的または間接的に生じたいかなる損害に関しても,その責任を負わない.
123 *
124 * @(#) $Id$
125 */
126
127#include <string.h>
128
129#ifdef TARGET_KERNEL_ASP
130
131#include <kernel.h>
132#include <sil.h>
133#include <t_syslog.h>
134#include "kernel_cfg.h"
135
136#endif /* of #ifdef TARGET_KERNEL_ASP */
137
138#ifdef TARGET_KERNEL_JSP
139
140#include <s_services.h>
141#include <t_services.h>
142#include "kernel_id.h"
143
144#endif /* of #ifdef TARGET_KERNEL_JSP */
145
146#include <tinet_defs.h>
147#include <tinet_config.h>
148
149#include <net/if.h>
150#include <net/ethernet.h>
151#include <net/net.h>
152#include <net/net_endian.h>
153#include <net/net_var.h>
154#include <net/net_timer.h>
155
156#include <netinet/in.h>
157#include <netinet/in_var.h>
158#include <netinet/in_itron.h>
159#include <netinet/if_ether.h>
160
161#include <net/if_var.h>
162
163#include <netapp/netapp.h>
164#include <netapp/netapp_var.h>
165#include <netapp/dhcp4_cli.h>
166#include <netapp/dhcp4_cli_var.h>
167#include <netapp/resolver.h>
168#include "lcd.h"
169
170/*
171 * DHCP クライアントタスク
172 */
173
174#ifdef DHCP4_CLI_CFG
175
176/*
177 * 変数
178 */
179
180static T_DHCP4_CLI_CONTEXT context; /* クライアントコンテキスト */
181static uint8_t magicno[DHCP4_MAGIC_LEN] = DHCP4_RFC1048_MAGIC; /* magic 番号(RFC1048)*/
182
183/* 必須オプションリスト */
184#ifdef DHCP4_CLI_CFG_REQUIRED_OLIST
185static uint8_t required_plist[] = DHCP4_CLI_CFG_REQUIRED_OLIST;
186#endif
187
188/* 要求オプションリスト */
189#ifdef DHCP4_CLI_CFG_REQUEST_OLIST
190static uint8_t request_plist[] = DHCP4_CLI_CFG_REQUEST_OLIST;
191#endif
192
193#ifdef SEM_DHCP4_CLI_TIMER
194#define DHCP4_CLI_TIMER_LOCK() do { syscall(wai_sem(SEM_DHCP4_CLI_TIMER)); } while(0)
195#define DHCP4_CLI_TIMER_UNLOCK() do { syscall(sig_sem(SEM_DHCP4_CLI_TIMER)); } while(0)
196#else
197#define DHCP4_CLI_TIMER_LOCK() do { } while(0)
198#define DHCP4_CLI_TIMER_UNLOCK() do { } while(0)
199#endif
200
201#ifdef SEM_DHCP4_CLI_READY
202#define DHCP4_CLI_READY_WAIT(ct) do { syscall(wai_sem(SEM_DHCP4_CLI_READY)); } while(0)
203#define DHCP4_CLI_READY_SIGNAL(ct) do { syscall(sig_sem(SEM_DHCP4_CLI_READY)); } while(0)
204#else
205#define DHCP4_CLI_READY_WAIT(ct) do { } while(0)
206#define DHCP4_CLI_READY_SIGNAL(ct) do { syscall(wup_tsk(ct->tskid)); } while(0)
207#endif
208
209/*
210 * dhcp4_cksum -- チェックサムの計算関数
211 */
212
213static uint32_t
214dhcp4_cksum (void *data, uint_t len /*オクテット単位*/)
215{
216 uint32_t carry, sum = 0;
217
218 for ( ; len > 0; len -= 2) {
219 sum += (*(uint8_t*)data << 8) + *((uint8_t*)data + 1);
220 data = (uint8_t*)data + 2;
221 }
222
223 while (sum >= 0x00010000) {
224 carry = sum >> 16;
225 sum = (sum & 0xffff) + carry;
226 }
227
228 return sum;
229 }
230
231/*
232 * create_xid -- トランザクション ID を生成する。
233 */
234
235static uint32_t
236create_xid (void)
237{
238 T_IF_SOFTC *ic;
239 SYSTIM time;
240
241 ic = IF_ETHER_NIC_GET_SOFTC();
242 get_tim(&time);
243 return (dhcp4_cksum((void*)&ic->ifaddr.lladdr, ETHER_ADDR_LEN) << 16)
244 + dhcp4_cksum((void*)&time, sizeof(time));
245 }
246
247/*
248 * find_option_sub -- 指定したオプションを探索する。
249 *
250 * 注意: 引数 size が 0 の時はオプションサイズを検証しない。
251 */
252
253static uint8_t *
254find_option_sub (T_DHCP4_CLI_MSG *msg, uint_t off, uint_t len,
255 uint_t tag, uint_t size, bool_t overload)
256{
257 uint8_t *opt, *tmp;
258
259 opt = (uint8_t*)&msg->msg + off;
260 while (opt < (uint8_t*)&msg->msg + off + len && *opt != DHCP4_OPT_END) {
261 if (*opt == DHCP4_OPT_PAD)
262 opt ++;
263 else if ((*opt == DHCP4_OPT_OPT_OVERLOAD) && overload) {
264 if (*(opt + 2) & DHCP4_OPTOL_FILE) {
265 tmp = find_option_sub(msg, DHCP4_FILE_OFFSET, DHCP4_FILE_LEN, tag, len, false);
266 if (tmp != NULL)
267 return tmp;
268 }
269 if (*(opt + 2) & DHCP4_OPTOL_SNAME) {
270 tmp = find_option_sub(msg, DHCP4_SNAME_OFFSET, DHCP4_SNAME_LEN, tag, len, false);
271 if (tmp != NULL)
272 return tmp;
273 }
274 opt += *(opt + 1) + 2;
275 }
276 else if (*opt == tag && (size == 0 || *(opt + 1) == size))
277 return opt;
278 else
279 opt += *(opt + 1) + 2;
280 }
281 return NULL;
282 }
283
284/*
285 * find_option -- 指定したオプションを探索する。
286 *
287 * 注意: 引数 size が 0 の時はオプションサイズを検証しない。
288 */
289
290static uint8_t *
291find_option (T_DHCP4_CLI_MSG *msg, uint_t tag, uint_t size)
292{
293 return find_option_sub(msg, DHCP4_OPTION_OFFSET + DHCP4_MAGIC_LEN,
294 msg->len - (DHCP4_OPTION_OFFSET + DHCP4_MAGIC_LEN),
295 tag, size, true);
296 }
297
298/*
299 * is_equal_sid -- メッセージ内の SERVER ID を比較する。
300 */
301
302static bool_t
303is_equal_sid (T_DHCP4_CLI_MSG *msg1, T_DHCP4_CLI_MSG *msg2)
304{
305 uint8_t *opt1, *opt2;
306
307 if ((opt1 = find_option(msg1, DHCP4_OPT_SERVER_ID, sizeof(T_IN4_ADDR))) == NULL)
308 return false;
309 if ((opt2 = find_option(msg2, DHCP4_OPT_SERVER_ID, sizeof(T_IN4_ADDR))) == NULL)
310 return false;
311
312 return msg2host32(opt1) == msg2host32(opt2);
313 }
314
315/*
316 * timer_value -- メッセージから時間情報を取り出す。
317 */
318
319static uint32_t
320timer_value (T_DHCP4_CLI_MSG *msg, uint_t tag, uint32_t def_value)
321{
322 uint8_t *opt;
323 uint32_t seconds;
324
325 if ((opt = find_option(msg, tag, sizeof(uint32_t))) == NULL)
326 return def_value;
327 else {
328
329 /* サーバからのリース時間は[s]。*/
330 seconds = msg2host32(opt + 2);
331
332 /* コンテキスト内のリース時間は SYSTIM_HZ。*/
333 if (seconds == DHCP4_TIME_INFINITY)
334 return DHCP4_TIME_INFINITY;
335 else if (seconds > SYSTIM2SEC(DHCP4_TIME_INFINITY))
336 return DHCP4_TIME_INFINITY;
337 else
338 return SEC2SYSTIM(seconds);
339 }
340 }
341
342/*
343 * rel_addr -- IPv4 アドレス、サブネットマスク、静的経路表を解放する。
344 */
345
346static void
347rel_addr (void)
348{
349 ER error;
350 uint_t count = 0;
351
352 if ((error = in4_add_ifaddr(IPV4_ADDRANY, IPV4_ADDRANY)) != E_OK) {
353 syslog(LOG_NOTICE, "[DHCP4C] error, IPv4 addr: %s", itron_strerror(error));
354 count ++;
355 }
356
357 if ((error = in4_add_route(0, IPV4_ADDRANY, IPV4_ADDRANY, IPV4_ADDRANY)) != E_OK) {
358 syslog(LOG_NOTICE, "[DHCP4C] error, release routing table: %s", itron_strerror(error));
359 count ++;
360 }
361
362 if ((error = in4_add_route(1, IPV4_ADDRANY, IPV4_ADDRANY, IPV4_ADDRANY)) != E_OK) {
363 syslog(LOG_NOTICE, "[DHCP4C] error, release routing table: %s", itron_strerror(error));
364 count ++;
365 }
366
367 if ((error = in4_add_route(2, 0xffffffff, 0xffffffff, IPV4_ADDRANY)) != E_OK) {
368 syslog(LOG_NOTICE, "[DHCP4C] error, release routing table: %s", itron_strerror(error));
369 count ++;
370 }
371
372 if (count == 0) {
373 syslog(LOG_NOTICE, "[DHCP4C] release IPv4 addr.");
374
375#if 0
376#ifdef USE_LCD
377 dly_tsk(1 * 1000);
378 lcd_puts(LCD_PORTID, "0.0.0.0\n");
379#endif /* of #ifdef USE_LCD */
380#endif
381 ether_set_down();
382 }
383 }
384
385/*
386 * rel_options -- リースされたオプションを解析して値を解放する。
387 */
388
389static void
390rel_options (T_DHCP4_CLI_CONTEXT *ct, uint_t off, uint_t len, bool_t overload)
391{
392#if defined(USE_RESOLVER)
393 T_IN4_ADDR addr;
394#endif
395
396 uint8_t *opt;
397
398 opt = (uint8_t*)&ct->act_msg->msg + off;
399 while (opt < (uint8_t*)&ct->act_msg->msg + off + len && *opt != DHCP4_OPT_END) {
400 if (*opt == DHCP4_OPT_PAD)
401 opt ++;
402 else if ((*opt == DHCP4_OPT_OPT_OVERLOAD) && overload) {
403 if (*(opt + 2) & DHCP4_OPTOL_FILE)
404 rel_options(ct, DHCP4_FILE_OFFSET, DHCP4_FILE_LEN, false);
405 if (*(opt + 2) & DHCP4_OPTOL_SNAME)
406 rel_options(ct, DHCP4_SNAME_OFFSET, DHCP4_SNAME_LEN, false);
407 opt += *(opt + 1) + 2;
408 }
409 else {
410
411 switch (*opt) {
412
413#if defined(USE_RESOLVER)
414
415 case DHCP4_OPT_DNS_SERVER:
416 addr = IPV4_ADDRANY;
417 dns_in4_set_addr(&addr);
418 break;
419
420 case DHCP4_OPT_HOST_NAME:
421 break;
422
423 case DHCP4_OPT_DOMAIN_NAME:
424 dns_in4_set_dname("", 0);
425 break;
426
427#else /* of #if defined(USE_RESOLVER) */
428
429 case DHCP4_OPT_DNS_SERVER:
430 case DHCP4_OPT_HOST_NAME:
431 case DHCP4_OPT_DOMAIN_NAME:
432
433#endif /* of #if defined(USE_RESOLVER) */
434
435 case DHCP4_OPT_SUBNET_MASK:
436 case DHCP4_OPT_ROUTER:
437 case DHCP4_OPT_LEASE_TIME:
438 case DHCP4_OPT_RENEWAL_T1:
439 case DHCP4_OPT_REBINDING_T2:
440 break;
441
442 default:
443 break;
444 }
445
446 opt += *(opt + 1) + 2;
447 }
448 }
449 }
450
451/*
452 * rel_lease -- リースされた情報を解放する。
453 */
454
455static void
456rel_lease (T_DHCP4_CLI_CONTEXT *ct)
457{
458 /* 有効なリース・メッセージ構造体が無ければ何もしない。*/
459 if (ct->act_msg == NULL)
460 return;
461
462 /* リースされたオプションを解析して値を解放する。*/
463 rel_options(ct, DHCP4_OPTION_OFFSET + DHCP4_MAGIC_LEN,
464 ct->act_msg->len - (DHCP4_OPTION_OFFSET + DHCP4_MAGIC_LEN), true);
465 rel_addr();
466
467 /* 有効なリース・メッセージ構造体を解放する。*/
468 syscall(rel_mpf(MPF_DHCP4_CLI_MSG, (void*)ct->act_msg));
469 ct->act_msg = NULL;
470 }
471
472/*
473 * set_addr -- IPv4 アドレス、サブネットマスク、静的経路表を設定する。
474 */
475
476static void
477set_addr (T_DHCP4_CLI_CONTEXT *ct, uint8_t *mopt, uint8_t *ropt)
478{
479 ER error;
480 T_IN4_ADDR addr, mask, router, net_addr;
481
482 addr = ntohl(ct->act_msg->msg.yiaddr);
483 mask = msg2host32(mopt + 2);
484 net_addr = addr & mask;
485 router = msg2host32(ropt + 2);
486
487 if ((error = in4_add_ifaddr(addr, mask)) != E_OK)
488 syslog(LOG_NOTICE, "[DHCP4C] error, set IPv4 addr: %s", itron_strerror(error));
489
490 if ((error = in4_add_route(0, IPV4_ADDRANY, IPV4_ADDRANY, router)) != E_OK)
491 syslog(LOG_NOTICE, "[DHCP4C] error, set routing table: %s", itron_strerror(error));
492
493 if ((error = in4_add_route(1, net_addr, mask, IPV4_ADDRANY)) != E_OK)
494 syslog(LOG_NOTICE, "[DHCP4C] error, set routing table: %s", itron_strerror(error));
495
496 if ((error = in4_add_route(2, 0xffffffff, 0xffffffff, IPV4_ADDRANY)) != E_OK)
497 syslog(LOG_NOTICE, "[DHCP4C] error, set routing table: %s", itron_strerror(error));
498
499 if (error == E_OK) {
500 syslog(LOG_NOTICE, "[DHCP4C] set IPv4 addr: %s.", ip2str(NULL, &addr));
501
502#ifdef USE_LCD
503 dly_tsk(1 * 1000);
504 lcd_puts(LCD_PORTID, ip2str(NULL, &addr));
505 lcd_putc(LCD_PORTID, '\n');
506#endif /* of #ifdef USE_LCD */
507 ether_set_up();
508 }
509 }
510
511/*
512 * set_options -- リースされたオプションを解析して値を設定する。
513 */
514
515static void
516set_options (T_DHCP4_CLI_CONTEXT *ct, uint_t off, uint_t len, bool_t overload)
517{
518#if defined(USE_RESOLVER)
519 T_IN4_ADDR addr;
520#endif
521
522 uint8_t *opt, *mopt = NULL, *ropt = NULL;
523
524 opt = (uint8_t*)&ct->act_msg->msg + off;
525 while (opt < (uint8_t*)&ct->act_msg->msg + off + len && *opt != DHCP4_OPT_END) {
526 if (*opt == DHCP4_OPT_PAD)
527 opt ++;
528 else if ((*opt == DHCP4_OPT_OPT_OVERLOAD) && overload) {
529 if (*(opt + 2) & DHCP4_OPTOL_FILE)
530 set_options(ct, DHCP4_FILE_OFFSET, DHCP4_FILE_LEN, false);
531 if (*(opt + 2) & DHCP4_OPTOL_SNAME)
532 set_options(ct, DHCP4_SNAME_OFFSET, DHCP4_SNAME_LEN, false);
533 opt += *(opt + 1) + 2;
534 }
535 else {
536
537 switch (*opt) {
538 case DHCP4_OPT_SUBNET_MASK:
539 mopt = opt;
540 break;
541
542 case DHCP4_OPT_ROUTER:
543 ropt = opt;
544 break;
545
546#if defined(USE_RESOLVER)
547
548 case DHCP4_OPT_DNS_SERVER:
549 addr = msg2host32(opt + 2);
550 dns_in4_set_addr(&addr);
551 break;
552
553 case DHCP4_OPT_HOST_NAME:
554 break;
555
556 case DHCP4_OPT_DOMAIN_NAME:
557 dns_in4_set_dname(opt + 2, *(opt + 1));
558 break;
559
560#else /* of #if defined(USE_RESOLVER) */
561
562 case DHCP4_OPT_DNS_SERVER:
563 case DHCP4_OPT_HOST_NAME:
564 case DHCP4_OPT_DOMAIN_NAME:
565
566#endif /* of #if defined(USE_RESOLVER) */
567
568 case DHCP4_OPT_LEASE_TIME:
569 case DHCP4_OPT_RENEWAL_T1:
570 case DHCP4_OPT_REBINDING_T2:
571 break;
572
573 default:
574 break;
575 }
576
577 opt += *(opt + 1) + 2;
578 }
579 }
580 if (!(mopt == NULL || ropt == NULL))
581 set_addr(ct, mopt, ropt);
582 }
583
584/*
585 * set_lease -- リースされた情報を設定する。
586 */
587
588static void
589set_lease (T_DHCP4_CLI_CONTEXT *ct)
590{
591 /* リースされたオプションを解析して値を設定する。*/
592 set_options(ct, DHCP4_OPTION_OFFSET + DHCP4_MAGIC_LEN,
593 ct->act_msg->len - (DHCP4_OPTION_OFFSET + DHCP4_MAGIC_LEN), true);
594 }
595
596/*
597 * validate_duplicate -- 指定された IPv4 アドレスが使われていないか検証する。
598 *
599 * 使われていない時は true を返す。
600 */
601
602static bool_t
603validate_duplicate (T_DHCP4_CLI_MSG *msg)
604{
605 T_IN4_ADDR yiaddr;
606
607 /* 指定された IPv4 アドレスが ADDR ANY なら使われていないと判断する。*/
608 yiaddr = ntohl(msg->msg.yiaddr);
609 if (yiaddr == IPV4_ADDRANY)
610 return true;
611
612 /* ARP キャッシュにあれば使われていると判断する。*/
613 if (arp_lookup(yiaddr, false) != NULL)
614 return false;
615
616 /*
617 * ARP 要求を出力して TMO_DHCP4C_ARP_WAIT 待ち、
618 * ARP キャッシュになければ使われていないと判断する。
619 */
620 arp_request(&IF_ETHER_NIC_GET_SOFTC()->ifaddr, yiaddr);
621 dly_tsk(TMO_DHCP4C_ARP_WAIT);
622 return arp_lookup(yiaddr, false) == NULL;
623 }
624
625/*
626 * validate_rcv_msg -- 受信メッセージを検証する。
627 */
628
629static ER
630validate_rcv_msg (T_DHCP4_CLI_CONTEXT *ct, T_DHCP4_CLI_MSG *msg)
631{
632 uint8_t *opt;
633
634 /* packet type が DHCP4_REPLY であることを確認する。*/
635 if (!(msg->msg.op == DHCP4_REPLY))
636 return false;
637
638 /* メッセージタイプオプションがあることを確認する。*/
639 if ((opt = find_option(msg, DHCP4_OPT_MSG_TYPE, 1)) == NULL)
640 return E_PAR;
641
642 /* メッセージのタイプが一致していることを検証する。*/
643 msg->type = *(opt + 2);
644 switch (ct->fsm) {
645
646 case DHCP4_FSM_SELECT:
647 if (!(msg->type == DHCP4_MTYPE_OFFER))
648 return E_PAR;
649 break;
650
651 case DHCP4_FSM_REQUEST:
652 case DHCP4_FSM_REBOOT:
653 case DHCP4_FSM_RENEW:
654 case DHCP4_FSM_REBIND:
655 case DHCP4_FSM_REL_INFO:
656 if (!((msg->type == DHCP4_MTYPE_ACK) || (msg->type == DHCP4_MTYPE_NAK)))
657 return E_PAR;
658 break;
659
660 case DHCP4_FSM_INIT:
661 case DHCP4_FSM_BOUND:
662 case DHCP4_FSM_INIT_REBOOT:
663 return E_PAR;
664 break;
665
666 default:
667 syslog(LOG_NOTICE, "[DHCP4C] error, unknown state: %d.", ct->fsm);
668 return E_PAR;
669 break;
670 }
671
672 /* マジック番号を検証する。*/
673 if (memcmp((uint8_t*)&msg->msg.options, magicno, DHCP4_MAGIC_LEN))
674 return E_PAR;
675
676 /* トランザクション ID が異なっていればエラー */
677 if (ntohl(msg->msg.xid) != ct->xid)
678 return E_PAR;
679
680 /* ハードウェアアドレス長が 6(MAC アドレス長)でなければエラー */
681 if (msg->msg.hlen != ETHER_ADDR_LEN)
682 return E_PAR;
683
684 /* ハードウェアアドレスが異なっていればエラー */
685 if (memcmp(&msg->msg.chaddr, &ct->sc->ifaddr.lladdr, sizeof(ct->sc->ifaddr.lladdr)))
686 return E_PAR;
687
688 /*
689 * メッセージタイプが OFFER の場合は、
690 * ARP を使用して、指定された IPv4 アドレスが使われていないか検証する。
691 * 使われている時は、他の IPv4 アドレスの提供を待つ。
692 */
693 if (msg->type == DHCP4_MTYPE_OFFER) {
694 if (!validate_duplicate(msg))
695 return E_PAR;
696 }
697
698 return E_OK;
699 }
700
701/*
702 * eval_prefer -- 受信メッセージの推奨度を評価する。
703 */
704
705static void
706eval_prefer (T_DHCP4_CLI_MSG *msg)
707{
708 int ix;
709
710 /* 無効の場合は終了する。*/
711 if (msg == NULL)
712 return;
713
714 /* 指定された IPv4 アドレスが ADDR ANY なら推奨度を 0に設定する。*/
715 if (ntohl(msg->msg.yiaddr) == IPV4_ADDRANY)
716 msg->prefer = 0;
717 else
718 msg->prefer = DHCP4_CLI_CFG_PREFER_ADDR;
719
720#if defined(DHCP4_CLI_CFG_REQUEST_OLIST)
721
722 /* 要求オプションを検証する。*/
723 for (ix = sizeof(request_plist); ix -- > 0; ) {
724 if (find_option(msg, request_plist[ix], 0) != NULL)
725 msg->prefer ++;
726 }
727
728#endif /* of #if defined(DHCP4_CLI_CFG_REQUEST_OLIST) */
729
730#if defined(DHCP4_CLI_CFG_REQUIRED_OLIST)
731
732 /* 必須オプションを検証する。*/
733 for (ix = sizeof(required_plist); ix -- > 0; ) {
734 if (find_option(msg, required_plist[ix], 0) == NULL)
735 msg->prefer = 0;
736 }
737
738#endif /* of #if defined(DHCP4_CLI_CFG_REQUIRED_OLIST) */
739 }
740
741/*
742 * eval_rcv_msg -- 受信メッセージを評価する。
743 */
744
745static ER
746eval_rcv_msg (T_DHCP4_CLI_CONTEXT *ct)
747{
748 T_DHCP4_CLI_MSG *evl, *msg;
749
750 /* メッセージを受信していなければ中止する。*/
751 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
752 if (ct->val_lst == NULL) {
753 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
754 return E_OK;
755 }
756
757 /* 検証メッセージリストから評価メッセージを取り出す。*/
758 evl = ct->val_lst;
759 ct->val_lst = ct->val_lst->next;
760 evl->next = NULL;
761 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
762
763 /* 評価メッセージを検証する。*/
764 if (validate_rcv_msg(ct, evl) != E_OK) {
765
766 /* エラーが発生した評価メッセージを受信メッセージ構造体リストに戻す。*/
767 goto rcv_ret;
768 }
769
770 /* 受信したメッセージが NAK の時の処理 */
771 if (evl->type == DHCP4_MTYPE_NAK) {
772
773 /* リースされた情報を解放する。*/
774 rel_lease(ct);
775
776 /* 内部エラーを設定して終了する。*/
777 return E_PAR;
778 }
779
780 /* REL_INFO 状態の時の処理 */
781 //cons_printf(CONSOLE_PORTID, "evl_rcv_msg3[s=%d]\n", ct->fsm);
782 if (ct->fsm == DHCP4_FSM_REL_INFO) {
783 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
784 evl->next = ct->prf_lst;
785 ct->prf_lst = evl;
786 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
787 return E_OK;
788 }
789
790 /* 評価メッセージの推奨度を評価する。*/
791 eval_prefer(evl);
792
793 /* 推奨メッセージリストが空なら評価メッセージを移して終了する。*/
794 if (ct->prf_lst == NULL) {
795 ct->max_prefer = evl->prefer;
796 ct->prf_lst = evl;
797 return E_OK;
798 }
799
800 /* 評価メッセージの推奨度と推奨メッセージリストの最大推奨度を比較する。*/
801 if (evl->prefer > ct->max_prefer) {
802
803 /*
804 * 評価メッセージの推奨度が推奨メッセージリストの最大推奨度より高ければ、
805 * 推奨メッセージリストを受信メッセージ構造体リストに戻し、
806 * 評価メッセージを推奨メッセージリストに移す。
807 */
808 ct->max_prefer = evl->prefer;
809 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
810 if (ct->rcv_lst == NULL)
811 ct->rcv_lst = ct->prf_lst;
812 else {
813 for (msg = ct->rcv_lst; msg->next != NULL; msg = msg->next)
814 ;
815 msg->next = ct->prf_lst;
816 }
817 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
818 ct->prf_lst = evl;
819 return E_OK;
820 }
821
822 else if (evl->prefer == ct->max_prefer) {
823 for (msg = ct->prf_lst; msg != NULL; msg = msg->next) {
824 if (is_equal_sid(evl, msg)) {
825
826 /*
827 * 推奨メッセージリストに同じ DHCP4_OPT_SERVER_ID のメッセージがあれば、
828 * 評価メッセージを受信メッセージ構造体リストに戻す。
829 */
830 goto rcv_ret;
831 }
832 }
833
834 /*
835 * 評価メッセージを推奨メッセージリストに移す。
836 */
837 evl->next = ct->prf_lst;
838 ct->prf_lst = evl;
839 return E_OK;
840 }
841
842 /*else */
843 /*
844 * 評価メッセージの推奨度が推奨メッセージリストの最大推奨度より低ければ、
845 * 評価メッセージを受信メッセージ構造体リストに戻す。
846 */
847
848rcv_ret:
849 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
850 evl->next = ct->rcv_lst;
851 ct->rcv_lst = evl;
852 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
853 return E_OK;
854 }
855
856/*
857 * select_msg -- 推奨メッセージを選択する。
858 */
859
860static T_DHCP4_CLI_MSG*
861select_msg (T_DHCP4_CLI_CONTEXT *ct)
862{
863 T_DHCP4_CLI_MSG *msg, *select;
864
865 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
866 if (ct->prf_lst == NULL) {
867 /* メッセージを受信していなければ中止する。*/
868 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
869 return NULL;
870 }
871
872 /* 推奨メッセージリストの先頭のメッセージを選択する。*/
873 select = ct->prf_lst;
874 ct->prf_lst = ct->prf_lst->next;
875 select->next = NULL;
876
877 /* 選択されなかった検証メッセージを受信メッセージ構造体リストに戻す。*/
878 if (ct->rcv_lst == NULL)
879 ct->rcv_lst = ct->prf_lst;
880 else {
881 for (msg = ct->rcv_lst; msg->next != NULL; msg = msg->next)
882 ;
883 msg->next = ct->prf_lst;
884 }
885 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
886 return select;
887 }
888
889/*
890 * select_ack -- ACK メッセージを検証する。
891 *
892 * 受け入れることが可能の時は true を返す。
893 */
894
895static bool_t
896select_ack (T_DHCP4_CLI_CONTEXT *ct)
897{
898 T_DHCP4_CLI_MSG *msg;
899
900 if ((msg = select_msg(ct)) == NULL)
901 return false;
902
903 /* 有効なリース・メッセージが残っていれば、受信メッセージ構造体リストに戻す。*/
904 if (ct->act_msg != NULL) {
905 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
906 ct->act_msg->next = ct->rcv_lst;
907 ct->rcv_lst = ct->act_msg;
908 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
909 }
910
911 /* 有効なリース・メッセージに設定する。*/
912 ct->act_msg = msg;
913 return true;
914 }
915
916/*
917 * select_offer -- OFFER メッセージを検証する。
918 *
919 * 受け入れることが可能の時は true を返す。
920 */
921
922static bool_t
923select_offer (T_DHCP4_CLI_CONTEXT *ct)
924{
925 return (ct->off_msg = select_msg(ct)) != NULL;
926 }
927
928/*
929 * cancel_all_timers -- 全ての TIMER をキャンセルする。
930 */
931
932static void
933cancel_all_timers (T_DHCP4_CLI_CONTEXT *ct)
934{
935 int ix;
936
937 DHCP4_CLI_TIMER_LOCK();
938 for (ix = NUM_DHCP4C_TIMERS; ix -- > 0; )
939 ct->timers[ix] = 0;
940 DHCP4_CLI_TIMER_UNLOCK();
941 }
942
943
944/*
945 * start_select -- DISCOVER メッセージを送信して SELECT 状態に遷移する。
946 */
947
948static void
949start_select (T_DHCP4_CLI_CONTEXT *ct)
950{
951 /* 送信を開始した時間を記録する。*/
952 get_tim(&ct->snd_start);
953
954 /* OFFER メッセージ受信タイムアウトを設定する。*/
955 DHCP4_CLI_TIMER_LOCK();
956 ct->timers[DHCP4C_TIMER_RCV_OFFER] = SYSTIM2TIMER(TMO_DHCP4C_OFFER);
957 DHCP4_CLI_TIMER_UNLOCK();
958
959 /* 送信先アドレスにローカルネットワークへのブロードキャストを設定する。*/
960 ct->dst.ipaddr = IPV4_ADDRBROADCAST;
961
962 /* 送信間隔をリセットする。*/
963 ct->interval = 0;
964
965 /* SELECT 状態に遷移する。*/
966 ct->fsm = DHCP4_FSM_SELECT;
967
968 /* DISCOVER メッセージを送信する。*/
969 ct->flags |= DHCP4C_FLAG_TMOUT_SND_DISC;
970 DHCP4_CLI_READY_SIGNAL(ct);
971 }
972
973/*
974 * start_bound -- BOUND 状態に遷移する。
975 */
976
977static void
978start_bound (T_DHCP4_CLI_CONTEXT *ct)
979{
980 /* リースされた情報を設定する。*/
981 set_lease(ct);
982
983 /* リースの有効時間を設定する。*/
984 ct->expire = timer_value(ct->act_msg, DHCP4_OPT_LEASE_TIME, TMO_DHCP4C_DEF_LEASE);
985
986 /* リース時間が TMO_DHCP4C_MIN_LEASE 以下の時は、TMO_DHCP4C_MIN_LEASE に設定する。*/
987 if (ct->expire < TMO_DHCP4C_MIN_LEASE)
988 ct->expire = TMO_DHCP4C_MIN_LEASE;
989
990 /* RENEW 状態までの時間を設定する。*/
991 ct->renew = timer_value(ct->act_msg, DHCP4_OPT_RENEWAL_T1, ct->expire / 2);
992
993 /* REBIND 状態までの時間を設定する。*/
994 ct->rebind = timer_value(ct->act_msg, DHCP4_OPT_REBINDING_T2, ct->renew + ct->renew / 2 + ct->renew / 4);
995
996 /* EXPIRE、RENEW、REBIND タイマーを設定する。*/
997 DHCP4_CLI_TIMER_LOCK();
998 ct->timers[DHCP4C_TIMER_EXPIRE] = SYSTIM2TIMER(ct->expire); /* EXPIRE までの時間 */
999 ct->timers[DHCP4C_TIMER_REBIND] = SYSTIM2TIMER(ct->rebind); /* REBIND(T2)までの時間 */
1000 ct->timers[DHCP4C_TIMER_RENEW] = SYSTIM2TIMER(ct->renew); /* RENEW (T1)までの時間 */
1001 DHCP4_CLI_TIMER_UNLOCK();
1002
1003 /* BOUND 状態に遷移する。*/
1004 ct->fsm = DHCP4_FSM_BOUND;
1005
1006 /* BIND を開始した時間を記録する。*/
1007 get_tim(&ct->bind_start);
1008 }
1009
1010/*
1011 * start_send_request -- REQUEST メッセージを送信して、指定された状態に遷移する。
1012 */
1013
1014static void
1015start_send_request (T_DHCP4_CLI_CONTEXT *ct, uint_t fsm)
1016{
1017 T_IFNET *ifp = IF_GET_IFNET();
1018
1019 /* 送信を開始した時間を記録する。*/
1020 get_tim(&ct->snd_start);
1021
1022 /* 遷移する状態が RENEW 以外では ACK/NAK メッセージ受信タイムアウトを設定する。*/
1023 if (fsm != DHCP4_FSM_RENEW) {
1024 DHCP4_CLI_TIMER_LOCK();
1025 ct->timers[DHCP4C_TIMER_RCV_ACK] = SYSTIM2TIMER(TMO_DHCP4C_ACK);
1026 DHCP4_CLI_TIMER_UNLOCK();
1027 }
1028
1029 /*
1030 * 遷移する状態が RENEW で、
1031 * SERVER ID オプションがあればローカルネットワークへのブロードキャストを送信する。
1032 */
1033 if ((fsm == DHCP4_FSM_RENEW) &&
1034 (find_option(ct->act_msg, DHCP4_OPT_SERVER_ID, sizeof(T_IN4_ADDR)) != NULL))
1035 ct->dst.ipaddr = (ifp->in4_ifaddr.addr & ifp->in4_ifaddr.mask) | ~ifp->in4_ifaddr.mask;
1036 else
1037 ct->dst.ipaddr = IPV4_ADDRBROADCAST;
1038
1039 /* 送信間隔をリセットする。*/
1040 ct->interval = 0;
1041
1042 /* 指定された状態に遷移する。*/
1043 ct->fsm = fsm;
1044
1045 /* REQUEST メッセージを送信する。*/
1046 ct->flags |= DHCP4C_FLAG_TMOUT_SND_REQ;
1047 DHCP4_CLI_READY_SIGNAL(ct);
1048 }
1049
1050/*
1051 * start_rel_info -- アドレス情報を解放する。
1052 *
1053 * 注意: DHCPv4 の RFC2131 には無い
1054 */
1055
1056static void
1057start_rel_info (T_DHCP4_CLI_CONTEXT *ct)
1058{
1059 /* 全ての TIMER をキャンセルする。*/
1060 cancel_all_timers(ct);
1061
1062 /* 有効なリース情報が無ければ SLEEP に遷移する。*/
1063 if (ct->act_msg == NULL) {
1064 ct->fsm = DHCP4_FSM_SLEEP;
1065 return;
1066 }
1067
1068 /* 送信先アドレスにローカルネットワークへのブロードキャストを設定する。*/
1069 ct->dst.ipaddr = IPV4_ADDRBROADCAST;
1070
1071 /* RELEASE メッセージを送信する。*/
1072 ct->flags |= DHCP4C_FLAG_TMOUT_SND_REL;
1073 DHCP4_CLI_READY_SIGNAL(ct);
1074 }
1075
1076/*
1077 * setup_dhcp_com_msg -- DHCP メッセージの共通部分を作成する。
1078 */
1079
1080static uint8_t *
1081setup_dhcp_com_msg (T_DHCP4_CLI_CONTEXT *ct, uint_t op, uint_t type)
1082{
1083 uint8_t *option;
1084
1085 memset((void*)&ct->snd_msg->msg, 0, sizeof(ct->snd_msg->msg));
1086 ct->snd_msg->len = sizeof(ct->snd_msg->msg);
1087
1088 /* ヘッダ部を設定する。*/
1089 ct->snd_msg->msg.op = op;
1090 ct->snd_msg->msg.htype = DHCP4_HWA_TYPE_ETHER;
1091 ct->snd_msg->msg.hlen = ETHER_ADDR_LEN;
1092 HOST2MSG32(ct->snd_msg->msg.xid, ct->xid);
1093
1094 /* MAC アドレスを設定する。*/
1095 memcpy(&ct->snd_msg->msg.chaddr, &ct->sc->ifaddr.lladdr, ETHER_ADDR_LEN);
1096
1097 /*
1098 * オプション部を設定する。
1099 */
1100
1101 /* RFC1048 に定義されているマジック番号を設定する。*/
1102 memcpy(&ct->snd_msg->msg.options, magicno, DHCP4_MAGIC_LEN);
1103 option = ct->snd_msg->msg.options + DHCP4_MAGIC_LEN;
1104
1105 /* DHCP メッセージタイプを設定する。*/
1106 *(option ++) = DHCP4_OPT_MSG_TYPE;
1107 *(option ++) = 1;
1108 *(option ++) = type;
1109
1110 return option;
1111 }
1112
1113/*
1114 * setup_release_msg -- RELEASE メッセージを作成する。
1115 */
1116
1117static ER
1118setup_release_msg (T_DHCP4_CLI_CONTEXT *ct, T_DHCP4_CLI_MSG *ref)
1119{
1120 uint8_t *opt, *ref_opt;
1121
1122 /* 有効なリース・メッセージがなければエラー */
1123 if (ref == NULL)
1124 return E_PAR;
1125
1126 ct->xid = create_xid();
1127 if ((opt = setup_dhcp_com_msg(ct, DHCP4_REQUEST, DHCP4_MTYPE_RELEASE)) == NULL)
1128 return E_PAR;
1129
1130 /*
1131 * サーバ ID(server-ip)を設定する。
1132 * RFC2131 4.4.1 Initialization and allocation of network address 参照
1133 */
1134 if ((ref_opt = find_option(ref, DHCP4_OPT_SERVER_ID, sizeof(T_IN4_ADDR))) == NULL)
1135 return E_PAR;
1136 *(opt ++) = *(ref_opt ++);
1137 *(opt ++) = *(ref_opt ++);
1138 memcpy(opt, ref_opt, *(ref_opt - 1));
1139 opt += *(ref_opt - 1);
1140
1141 /*
1142 * クライアント ID(MAC アドレス)を設定する。
1143 * RFC2131 4.4.1 Initialization and allocation of network address 参照
1144 */
1145 *(opt ++) = DHCP4_OPT_CLIENT_ID;
1146 *(opt ++) = ETHER_ADDR_LEN + 1;
1147 *(opt ++) = DHCP4_HWA_TYPE_ETHER;
1148 memcpy(opt, &ct->sc->ifaddr.lladdr, ETHER_ADDR_LEN);
1149 opt += ETHER_ADDR_LEN;
1150
1151 /* オプションの終了を設定する。*/
1152 *(opt ++) = DHCP4_OPT_END;
1153
1154 /*
1155 * クライアント IP アドレス(ciaddr)を設定する。
1156 * RFC2131 4.4.1 Initialization and allocation of network address 参照
1157 */
1158 HOST2MSG32(ct->snd_msg->msg.ciaddr, IF_GET_IFNET()->in4_ifaddr.addr);
1159
1160 /* メッセージ長を設定する。*/
1161 ct->snd_msg->len = sizeof(ct->snd_msg->msg) - DHCP4_DFLT_OPT_LEN
1162 + (opt - (uint8_t*)&ct->snd_msg->msg.options);
1163 return E_OK;
1164 }
1165
1166
1167/*
1168 * setup_request_msg -- REQUEST メッセージを作成する。
1169 */
1170
1171static ER
1172setup_request_msg (T_DHCP4_CLI_CONTEXT *ct, T_DHCP4_CLI_MSG *ref)
1173{
1174 uint8_t *opt, *ref_opt;
1175
1176#if defined(DHCP4_CLI_CFG_REQUIRED_OLIST) || defined(DHCP4_CLI_CFG_REQUEST_OLIST)
1177 uint_t len = 0;
1178#endif
1179
1180 /* 参照するメッセージがなければエラー */
1181 if (ref == NULL)
1182 return E_PAR;
1183
1184 ct->xid = create_xid();
1185 if ((opt = setup_dhcp_com_msg(ct, DHCP4_REQUEST, DHCP4_MTYPE_REQUEST)) == NULL)
1186 return E_PAR;
1187
1188#if defined(DHCP4_CLI_CFG_REQUIRED_OLIST) || defined(DHCP4_CLI_CFG_REQUEST_OLIST)
1189
1190 /* 追加のオプションを設定する。*/
1191
1192 *opt = DHCP4_OPT_REQ_PARAM;
1193 opt += 2;
1194
1195#if defined(DHCP4_CLI_CFG_REQUIRED_OLIST)
1196
1197 /* 要求オプションリストを設定する。*/
1198 if (sizeof(required_plist) > 0) {
1199 memcpy(opt, required_plist, sizeof(required_plist));
1200 opt += sizeof(required_plist);
1201 len += sizeof(required_plist);
1202 }
1203
1204#endif /* of #if defined(DHCP4_CLI_CFG_REQUIRED_OLIST) */
1205
1206#if defined(DHCP4_CLI_CFG_REQUEST_OLIST)
1207
1208 /* 要求オプションリストを設定する。*/
1209 if (sizeof(request_plist) > 0) {
1210 memcpy(opt, request_plist, sizeof(request_plist));
1211 opt += sizeof(request_plist);
1212 len += sizeof(request_plist);
1213 }
1214
1215#endif /* of #if defined(DHCP4_CLI_CFG_REQUEST_OLIST) */
1216
1217 *(opt - len - 1) = len;
1218
1219#endif /* of #if defined(DHCP4_CLI_CFG_REQUIRED_OLIST) || defined(DHCP4_CLI_CFG_REQUEST_OLIST) */
1220
1221 /*
1222 * サーバ ID(server-ip)を設定する。
1223 * RFC2131 4.4.1 Initialization and allocation of network address 参照
1224 */
1225 if (ct->fsm == DHCP4_FSM_REQUEST) {
1226 if ((ref_opt = find_option(ref, DHCP4_OPT_SERVER_ID, sizeof(T_IN4_ADDR))) == NULL)
1227 return E_PAR;
1228 *(opt ++) = *(ref_opt ++);
1229 *(opt ++) = *(ref_opt ++);
1230 memcpy(opt, ref_opt, *(ref_opt - 1));
1231 opt += *(ref_opt - 1);
1232 }
1233
1234 /*
1235 * 要求 IP アドレス(requested-ip)を設定する。
1236 * RFC2131 4.4.1 Initialization and allocation of network address 参照
1237 * RFC2131 では、DHCP4_FSM_RENEW の時 MUST NOT になっているが、
1238 * MUST のようである。
1239 */
1240 *(opt ++) = DHCP4_OPT_REQ_IPV4;
1241 *(opt ++) = sizeof(ref->msg.yiaddr);
1242 if (ct->fsm == DHCP4_FSM_REQUEST || ct->fsm == DHCP4_FSM_INIT_REBOOT ||
1243 ct->fsm == DHCP4_FSM_RENEW || ct->fsm == DHCP4_FSM_REBIND)
1244 /* 参照メッセージと同じ IP アドレス(requested-ip)を要求する。*/
1245 memcpy(opt, (uint8_t*)&ref->msg.yiaddr, sizeof(ref->msg.yiaddr));
1246 else
1247 host2msg32(opt, IPV4_ADDRANY);
1248 opt += sizeof(ref->msg.yiaddr);
1249
1250 /*
1251 * クライアント ID(MAC アドレス)を設定する。
1252 * RFC2131 4.4.1 Initialization and allocation of network address 参照
1253 */
1254 *(opt ++) = DHCP4_OPT_CLIENT_ID;
1255 *(opt ++) = ETHER_ADDR_LEN + 1;
1256 *(opt ++) = DHCP4_HWA_TYPE_ETHER;
1257 memcpy(opt, &ct->sc->ifaddr.lladdr, ETHER_ADDR_LEN);
1258 opt += ETHER_ADDR_LEN;
1259
1260 /* オプションの終了を設定する。*/
1261 *(opt ++) = DHCP4_OPT_END;
1262
1263 /*
1264 * クライアント IP アドレス(ciaddr)を設定する。
1265 * RFC2131 4.4.1 Initialization and allocation of network address 参照
1266 */
1267 if (ct->fsm == DHCP4_FSM_RENEW || ct->fsm == DHCP4_FSM_REBIND)
1268 HOST2MSG32(ct->snd_msg->msg.ciaddr, IF_GET_IFNET()->in4_ifaddr.addr);
1269 else
1270 HOST2MSG32(ct->snd_msg->msg.ciaddr, IPV4_ADDRANY);
1271
1272 /* メッセージ長を設定する。*/
1273 ct->snd_msg->len = sizeof(ct->snd_msg->msg) - DHCP4_DFLT_OPT_LEN
1274 + (opt - (uint8_t*)&ct->snd_msg->msg.options);
1275 return E_OK;
1276 }
1277
1278/*
1279 * setup_discover_msg -- DISCOVER メッセージを作成する。
1280 */
1281
1282static ER
1283setup_discover_msg (T_DHCP4_CLI_CONTEXT *ct)
1284{
1285 uint8_t *opt;
1286
1287#if defined(DHCP4_CLI_CFG_REQUIRED_OLIST) || defined(DHCP4_CLI_CFG_REQUEST_OLIST)
1288 uint_t len = 0;
1289#endif
1290
1291 ct->xid = create_xid();
1292 if ((opt = setup_dhcp_com_msg(ct, DHCP4_REQUEST, DHCP4_MTYPE_DISCOVER)) == NULL)
1293 return E_PAR;
1294
1295#if defined(DHCP4_CLI_CFG_REQUIRED_OLIST) || defined(DHCP4_CLI_CFG_REQUEST_OLIST)
1296
1297 /* 追加のオプションを設定する。*/
1298
1299 *opt = DHCP4_OPT_REQ_PARAM;
1300 opt += 2;
1301
1302#if defined(DHCP4_CLI_CFG_REQUIRED_OLIST)
1303
1304 /* 要求オプションリストを設定する。*/
1305 if (sizeof(required_plist) > 0) {
1306 memcpy(opt, required_plist, sizeof(required_plist));
1307 opt += sizeof(required_plist);
1308 len += sizeof(required_plist);
1309 }
1310
1311#endif /* of #if defined(DHCP4_CLI_CFG_REQUIRED_OLIST) */
1312
1313#if defined(DHCP4_CLI_CFG_REQUEST_OLIST)
1314
1315 /* 要求オプションリストを設定する。*/
1316 if (sizeof(request_plist) > 0) {
1317 memcpy(opt, request_plist, sizeof(request_plist));
1318 opt += sizeof(request_plist);
1319 len += sizeof(request_plist);
1320 }
1321
1322#endif /* of #if defined(DHCP4_CLI_CFG_REQUEST_OLIST) */
1323
1324 *(opt - len - 1) = len;
1325
1326#endif /* of #if defined(DHCP4_CLI_CFG_REQUIRED_OLIST) || defined(DHCP4_CLI_CFG_REQUEST_OLIST) */
1327
1328 /* 既にアドレス情報がリースされていれば、同じ IP アドレスを要求する。*/
1329 if (ct->act_msg != NULL) {
1330 *(opt ++) = DHCP4_OPT_REQ_IPV4;
1331 *(opt ++) = sizeof(ct->act_msg->msg.yiaddr);
1332 memcpy(opt, (uint8_t*)&ct->act_msg->msg.yiaddr, sizeof(ct->act_msg->msg.yiaddr));
1333 opt += sizeof(ct->act_msg->msg.yiaddr);
1334 }
1335
1336 /* クライアント ID(MAC アドレス)を設定する。*/
1337 *(opt ++) = DHCP4_OPT_CLIENT_ID;
1338 *(opt ++) = ETHER_ADDR_LEN + 1;
1339 *(opt ++) = DHCP4_HWA_TYPE_ETHER;
1340 memcpy(opt, &ct->sc->ifaddr.lladdr, ETHER_ADDR_LEN);
1341 opt += ETHER_ADDR_LEN;
1342
1343 /* オプションの終了を設定する。*/
1344 *(opt ++) = DHCP4_OPT_END;
1345
1346 /* 送信先アドレスを設定する。*/
1347 ct->dst.ipaddr = IPV4_ADDRBROADCAST;
1348
1349 /* メッセージ長を設定する。*/
1350 ct->snd_msg->len = sizeof(ct->snd_msg->msg) - DHCP4_DFLT_OPT_LEN
1351 + (opt - (uint8_t*)&ct->snd_msg->msg.options);
1352 return E_OK;
1353 }
1354
1355/*
1356 * ack_msg_timeout -- ACK/NAK メッセージ受信タイムアウト処理
1357 */
1358
1359static void
1360ack_msg_timeout (T_DHCP4_CLI_CONTEXT *ct)
1361{
1362 /* ACK メッセージを受信していれば。BOUND 状態に遷移する。*/
1363 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1364 if (select_ack(ct)) {
1365
1366 /* REQUEST メッセージ送信タイマーを停止する。*/
1367 DHCP4_CLI_TIMER_LOCK();
1368 ct->timers[DHCP4C_TIMER_SND_REQ] = 0;
1369 DHCP4_CLI_TIMER_UNLOCK();
1370
1371 /*
1372 * 状態が REQUEST の時は、
1373 * OFFER メッセージを受信メッセージ構造体リストに戻す。
1374 */
1375 if (ct->fsm == DHCP4_FSM_REQUEST && ct->off_msg != NULL) {
1376 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
1377 ct->off_msg->next = ct->rcv_lst;
1378 ct->rcv_lst = ct->off_msg;
1379 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
1380 ct->off_msg = NULL;
1381 }
1382
1383 /* BOUND 状態に遷移する。*/
1384 start_bound(ct);
1385 return;
1386 }
1387 else {
1388
1389 /* リース情報を解放する。*/
1390 rel_lease(ct);
1391
1392 ct->error = E_TMOUT;
1393 }
1394 }
1395
1396/*
1397 * send_request_msg -- REQUEST メッセージを送信する。
1398 */
1399
1400static void
1401send_request_msg (T_DHCP4_CLI_CONTEXT *ct)
1402{
1403 T_DHCP4_CLI_MSG *ref;
1404 ER error;
1405 SYSTIM time;
1406 RELTIM interval;
1407 uint16_t secs;
1408
1409 /* タイムアウトフラグをクリアーする。*/
1410 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1411
1412 /* ACK メッセージを受信していれば。BOUND 状態に遷移する。*/
1413 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1414 if (select_ack(ct)) {
1415
1416 /* ACK/NAK メッセージ受信タイマーを停止する。*/
1417 DHCP4_CLI_TIMER_LOCK();
1418 ct->timers[DHCP4C_TIMER_RCV_ACK] = 0;
1419 DHCP4_CLI_TIMER_UNLOCK();
1420
1421 /*
1422 * 状態が REQUEST の時は、
1423 * OFFER メッセージを受信メッセージ構造体リストに戻す。
1424 */
1425 if (ct->fsm == DHCP4_FSM_REQUEST && ct->off_msg != NULL) {
1426 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
1427 ct->off_msg->next = ct->rcv_lst;
1428 ct->rcv_lst = ct->off_msg;
1429 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
1430 ct->off_msg = NULL;
1431 }
1432
1433 /* BOUND 状態に遷移する。*/
1434 start_bound(ct);
1435 return;
1436 }
1437
1438 /* REQUEST メッセージを作成する。*/
1439 if (ct->fsm == DHCP4_FSM_REQUEST)
1440 ref = ct->off_msg;
1441 else
1442 ref = ct->act_msg;
1443 if ((error = setup_request_msg(ct, ref)) != E_OK) {
1444 syslog(LOG_NOTICE, "[DHCP4C] error, setup request message: %s", itron_strerror(error));
1445 ct->error = error;
1446 return;
1447 }
1448
1449 /* 送信を開始してからの時間を得る。*/
1450 get_tim(&time);
1451 interval = time - ct->snd_start;
1452
1453 /*
1454 * 送信を開始してからの時間(秒)をメッセージに設定する。
1455 * 最大値は 65535。
1456 */
1457 if (ct->fsm == DHCP4_FSM_REQUEST)
1458 secs = ct->secs;
1459 else {
1460 if (SYSTIM2SEC(interval) < 65536)
1461 secs = SYSTIM2SEC(interval);
1462 else
1463 secs = 65535;
1464 }
1465 HOST2MSG16(ct->snd_msg->msg.secs, secs);
1466
1467 /* ノンブロッキングコールでメッセージを送信する。*/
1468 error = udp_snd_dat(ct->cepid, &ct->dst, &ct->snd_msg->msg, ct->snd_msg->len, TMO_NBLK);
1469 if (error != E_WBLK) {
1470 syslog(LOG_NOTICE, "[DHCP4C] error, send request message: %s", itron_strerror(error));
1471 ct->error = error;
1472 return;
1473 }
1474
1475 /* 送信間隔を設定する。*/
1476 if (ct->interval == 0)
1477 /* 未設定 */
1478 ct->interval = TMO_DHCP4C_INIT_INTVL;
1479 else
1480 /* バックオフアルゴリズムで 2倍にした(乱数使用)送信間隔を加算する。*/
1481 ct->interval += (netapp_rand() >> 2) % (ct->interval << 1);
1482
1483 /* 送信周期の制限値を超えないようにする。*/
1484 if (ct->interval > TMO_DHCP4C_MAX_BACKOFF)
1485 ct->interval = (TMO_DHCP4C_MAX_BACKOFF >> 1) + ((netapp_rand() >> 2) % TMO_DHCP4C_MAX_BACKOFF);
1486
1487 /* リース時間のタイムアウト【先送り】 */
1488 if (ct->fsm != DHCP4_FSM_REQUEST &&
1489 TIMEC_GT(ct->interval + time, ct->expire + ct->bind_start))
1490 ct->interval = ct->expire + ct->bind_start - time + SYSTIM_HZ;
1491
1492 /* 再送信タイムアウトを設定する。*/
1493 DHCP4_CLI_TIMER_LOCK();
1494 ct->timers[DHCP4C_TIMER_SND_REQ] = SYSTIM2TIMER(ct->interval);
1495 DHCP4_CLI_TIMER_UNLOCK();
1496 }
1497
1498/*
1499 * send_release_msg -- RELEASE メッセージを送信する。
1500 */
1501
1502static void
1503send_release_msg (T_DHCP4_CLI_CONTEXT *ct)
1504{
1505 ER error;
1506
1507 /* タイムアウトフラグをクリアーする。*/
1508 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1509
1510 /* RELEASE メッセージを作成する。*/
1511 if ((error = setup_release_msg(ct, ct->act_msg)) != E_OK) {
1512 syslog(LOG_NOTICE, "[DHCP4C] error, setup release message: %s", itron_strerror(error));
1513 ct->error = error;
1514 return;
1515 }
1516
1517 /* リース情報を解放する。*/
1518 rel_lease(ct);
1519
1520 /* ノンブロッキングコールでメッセージを送信する。*/
1521 error = udp_snd_dat(ct->cepid, &ct->dst, &ct->snd_msg->msg, ct->snd_msg->len, TMO_NBLK);
1522 if (error != E_WBLK) {
1523 syslog(LOG_NOTICE, "[DHCP4C] error, send release message: %s", itron_strerror(error));
1524 ct->error = error;
1525 return;
1526 }
1527
1528 /* メッセージ送信待ちを行う。*/
1529 DHCP4_CLI_READY_WAIT(ct);
1530
1531 /* SLEEP 状態に遷移する。*/
1532 ct->fsm = DHCP4_FSM_SLEEP;
1533 }
1534
1535/*
1536 * offer_msg_timeout -- OFFER メッセージ受信タイムアウト処理
1537 */
1538
1539static void
1540offer_msg_timeout (T_DHCP4_CLI_CONTEXT *ct)
1541{
1542 /* OFFER メッセージを受信していれば。REQUEST 状態に遷移する。*/
1543 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1544 if (select_offer(ct)) {
1545
1546 /* DISCOVER メッセージ送信タイマーを停止する。*/
1547 DHCP4_CLI_TIMER_LOCK();
1548 ct->timers[DHCP4C_TIMER_SND_DISC] = 0;
1549 DHCP4_CLI_TIMER_UNLOCK();
1550
1551 /* REQUEST メッセージを送信して REQUEST 状態に遷移する。*/
1552 start_send_request(ct, DHCP4_FSM_REQUEST);
1553 }
1554 else
1555 ct->error = E_TMOUT;
1556 }
1557
1558/*
1559 * send_discover_msg -- DISCOVERメッセージを送信する。
1560 */
1561
1562static void
1563send_discover_msg (T_DHCP4_CLI_CONTEXT *ct)
1564{
1565 ER error;
1566 SYSTIM time;
1567 RELTIM interval;
1568
1569 /* タイムアウトフラグをクリアーする。*/
1570 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1571
1572 /* OFFER メッセージを受信していれば。REQUEST 状態に遷移する。*/
1573 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1574 if (select_offer(ct)) {
1575
1576 /* OFFER メッセージ受信タイマーを停止する。*/
1577 DHCP4_CLI_TIMER_LOCK();
1578 ct->timers[DHCP4C_TIMER_RCV_OFFER] = 0;
1579 DHCP4_CLI_TIMER_UNLOCK();
1580
1581 /* REQUEST メッセージを送信して REQUEST 状態に遷移する。*/
1582 start_send_request(ct, DHCP4_FSM_REQUEST);
1583 return;
1584 }
1585
1586 /* DISCOVER メッセージを作成する。*/
1587 if ((error = setup_discover_msg(ct)) != E_OK) {
1588 syslog(LOG_NOTICE, "[DHCP4C] error, setup discover message: %s", itron_strerror(error));
1589 ct->error = error;
1590 return;
1591 }
1592
1593 /* 送信を開始してからの時間を得る。*/
1594 get_tim(&time);
1595 interval = time - ct->snd_start;
1596
1597 /*
1598 * 送信を開始してからの時間(秒)をメッセージに設定する。
1599 * 最大値は 65535。
1600 */
1601 if (SYSTIM2SEC(interval) < 65536)
1602 ct->secs = SYSTIM2SEC(interval);
1603 else
1604 ct->secs = 65535;
1605 HOST2MSG16(ct->snd_msg->msg.secs, ct->secs);
1606
1607 /* ノンブロッキングコールでメッセージを送信する。*/
1608 error = udp_snd_dat(ct->cepid, &ct->dst, &ct->snd_msg->msg, ct->snd_msg->len, TMO_NBLK);
1609 if (error != E_WBLK) {
1610 syslog(LOG_NOTICE, "[DHCP4C] error, send discover message: %s", itron_strerror(error));
1611 ct->error = error;
1612 return;
1613 }
1614
1615 /* 送信間隔を設定する。*/
1616 if (ct->interval == 0)
1617 /* 未設定 */
1618 ct->interval = TMO_DHCP4C_INIT_INTVL;
1619 else
1620 /* バックオフアルゴリズムで 2倍にした(乱数使用)送信間隔を加算する。*/
1621 ct->interval += (netapp_rand() >> 2) % (ct->interval << 1);
1622
1623 /* 送信周期の制限値を超えないようにする。*/
1624 if (ct->interval > TMO_DHCP4C_MAX_BACKOFF)
1625 ct->interval = (TMO_DHCP4C_MAX_BACKOFF >> 1) + ((netapp_rand() >> 2) % TMO_DHCP4C_MAX_BACKOFF);
1626
1627 /* OFFER メッセージの受信タイムアウトを超えないように調整する。*/
1628 if (TIMEC_GT(time + ct->interval, ct->snd_start + TMO_DHCP4C_OFFER))
1629 ct->interval = (TMO_DHCP4C_INIT_INTVL + TMO_DHCP4C_OFFER) - time + 1;
1630
1631 /* 再送信タイムアウトを設定する。*/
1632 DHCP4_CLI_TIMER_LOCK();
1633 ct->timers[DHCP4C_TIMER_SND_DISC] = SYSTIM2TIMER(ct->interval);
1634 DHCP4_CLI_TIMER_UNLOCK();
1635 }
1636
1637#ifdef DHCP4_CLI_TASK
1638
1639/*
1640 * dhcpc_timer -- TIMER 管理
1641 */
1642
1643static void
1644dhcpc_timer (T_DHCP4_CLI_CONTEXT *ct)
1645{
1646 int ix;
1647
1648 DHCP4_CLI_TIMER_LOCK();
1649 for (ix = NUM_DHCP4C_TIMERS; ix -- > 0; ) {
1650 if (ct->timers[ix] != 0) {
1651 ct->timers[ix] --;
1652 if (ct->timers[ix] == 0) {
1653 ct->flags = (ct->flags & ~DHCP4C_FLAG_TMOUT_MASK) | DHCP4C_FLAG_TMOUT_TIMER | ix;
1654 DHCP4_CLI_READY_SIGNAL(ct);
1655 }
1656 }
1657 }
1658 DHCP4_CLI_TIMER_UNLOCK();
1659
1660 /* 1秒毎にタイムアウトする。*/
1661 timeout((callout_func)dhcpc_timer, ct, NET_TIMER_HZ);
1662 }
1663
1664#endif
1665
1666/*
1667 * expire_timeout -- EXPIRE タイムアウト処理
1668 */
1669
1670static void
1671expire_timeout (T_DHCP4_CLI_CONTEXT *ct)
1672{
1673 //ER error;
1674
1675 /* タイムアウトフラグをクリアーする。*/
1676 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1677
1678 /* 状態が REQUEST の時は何もしない。*/
1679 if (ct->fsm == DHCP4_FSM_REQUEST)
1680 return;
1681
1682 /* 全ての TIMER をキャンセルする。*/
1683 cancel_all_timers(ct);
1684
1685 /* リースされた情報を解放する。*/
1686 rel_lease(ct);
1687
1688 ct->error = E_TMOUT;
1689 }
1690
1691/*
1692 * rebind_timeout -- REBIND タイムアウト処理
1693 */
1694
1695static void
1696rebind_timeout (T_DHCP4_CLI_CONTEXT *ct)
1697{
1698 /* タイムアウトフラグをクリアーする。*/
1699 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1700
1701 /* 全ての TIMER をキャンセルする。*/
1702 cancel_all_timers(ct);
1703
1704 /* REQUEST メッセージを送信して REBIND 状態に遷移する。*/
1705 start_send_request(ct, DHCP4_FSM_REBIND);
1706 }
1707
1708/*
1709 * renew_timeout -- RENEW タイムアウト処理
1710 */
1711
1712static void
1713renew_timeout (T_DHCP4_CLI_CONTEXT *ct)
1714{
1715 /* タイムアウトフラグをクリアーする。*/
1716 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1717
1718 /* REQUEST メッセージを送信して RENEW 状態に遷移する。*/
1719 start_send_request(ct, DHCP4_FSM_RENEW);
1720 }
1721
1722/*
1723 * dispatch_timeout -- タイムアウトした時の処理
1724 */
1725
1726static ER
1727dispatch_timeout (T_DHCP4_CLI_CONTEXT *ct)
1728{
1729 switch (ct->flags & DHCP4C_FLAG_TMOUT_TIMER_MASK) {
1730
1731 case DHCP4C_TIMER_SND_DISC:
1732 send_discover_msg(ct);
1733 break;
1734
1735 case DHCP4C_TIMER_SND_REQ:
1736 send_request_msg(ct);
1737 break;
1738
1739 case DHCP4C_TIMER_RCV_OFFER:
1740 offer_msg_timeout(ct);
1741 break;
1742
1743 case DHCP4C_TIMER_RCV_ACK:
1744 ack_msg_timeout(ct);
1745 break;
1746
1747 case DHCP4C_TIMER_RENEW:
1748 renew_timeout(ct);
1749 break;
1750
1751 case DHCP4C_TIMER_REBIND:
1752 rebind_timeout(ct);
1753 break;
1754
1755 case DHCP4C_TIMER_EXPIRE:
1756 expire_timeout(ct);
1757 break;
1758
1759 case DHCP4C_TIMER_SND_REL:
1760 send_release_msg(ct);
1761 break;
1762
1763 default:
1764 break;
1765 }
1766
1767 return ct->error;
1768 }
1769
1770#ifdef DHCP4_CLI_TASK
1771
1772/*
1773 * dispatch_event -- イベント毎の処理
1774 */
1775
1776static ER
1777dispatch_event (T_DHCP4_CLI_CONTEXT *ct)
1778{
1779 ER error = E_OK;
1780
1781 while (ct->fsm != DHCP4_FSM_SLEEP && error == E_OK) {
1782
1783 /* メッセージの受信とタイムアウトを待つ。*/
1784 DHCP4_CLI_READY_WAIT(ct);
1785
1786 if (ct->flags & DHCP4C_FLAG_RCV_MSG) {
1787 while (ct->val_lst != NULL) {
1788 error = eval_rcv_msg(ct);
1789 }
1790 ct->flags &= ~DHCP4C_FLAG_RCV_MSG;
1791 }
1792 if (ct->flags & DHCP4C_FLAG_TMOUT_MASK)
1793 error = dispatch_timeout(ct);
1794
1795 if (ct->error != E_OK)
1796 error = ct->error;
1797 }
1798
1799 return error;
1800 }
1801
1802#endif
1803
1804/*
1805 * init_context -- DHCP クライアントコンテキスト構造体を初期化する。
1806 */
1807
1808static void
1809init_context (T_DHCP4_CLI_CONTEXT *ct, ID tskid, ID cepid)
1810{
1811 memset(ct, 0, sizeof(*ct));
1812 ct->tskid = tskid;
1813 ct->cepid = cepid;
1814 ct->sc = IF_ETHER_NIC_GET_SOFTC();
1815 ct->dst.portno = DHCP4_SRV_CFG_PORTNO;
1816 ct->dst.ipaddr = IPV4_ADDRANY;
1817 }
1818
1819/*
1820 * rel_cli_msg -- メッセージ構造体を解放する。
1821 */
1822
1823static void
1824rel_cli_msg (T_DHCP4_CLI_CONTEXT *ct)
1825{
1826 T_DHCP4_CLI_MSG *ptr, *cell;
1827
1828 for (ptr = ct->rcv_lst; ptr != NULL; ) {
1829 cell = ptr;
1830 ptr = ptr->next;
1831 syscall(rel_mpf(MPF_DHCP4_CLI_MSG, (void*)cell));
1832 }
1833
1834 for (ptr = ct->val_lst; ptr != NULL; ) {
1835 cell = ptr;
1836 ptr = ptr->next;
1837 syscall(rel_mpf(MPF_DHCP4_CLI_MSG, (void*)cell));
1838 }
1839
1840 for (ptr = ct->prf_lst; ptr != NULL; ) {
1841 cell = ptr;
1842 ptr = ptr->next;
1843 syscall(rel_mpf(MPF_DHCP4_CLI_MSG, (void*)cell));
1844 }
1845
1846 if (ct->snd_msg != NULL)
1847 syscall(rel_mpf(MPF_DHCP4_CLI_MSG, (void*)ct->snd_msg));
1848 ct->rcv_lst = ct->prf_lst = ct->val_lst = ct->snd_msg = NULL;
1849 }
1850
1851/*
1852 * init_cli_msg -- 各メッセージ構造体を初期化する。
1853 */
1854
1855static ER
1856init_cli_msg (T_DHCP4_CLI_CONTEXT *ct)
1857{
1858 T_DHCP4_CLI_MSG *cell;
1859 ER error;
1860 int count;
1861
1862 /* 送信メッセージ構造体を獲得する。*/
1863 if ((error = tget_mpf(MPF_DHCP4_CLI_MSG, (void*)&ct->snd_msg, TMO_DHCP4C_MPF_GET)) != E_OK) {
1864 syslog(LOG_NOTICE, "[DHCP4C] error, tget_mpf() for send: %s.", itron_strerror(error));
1865 return error;
1866 }
1867
1868 /*
1869 * 有効なリース・メッセージ構造体がある場合は、
1870 * 獲得する受信メッセージ構造体リストの構造体を 1減らす。
1871 */
1872 if (ct->act_msg == NULL)
1873 count = NUM_DHCP4_MSG_LIST;
1874 else
1875 count = NUM_DHCP4_MSG_LIST - 1;
1876
1877 /* 受信メッセージ構造体を獲得する。*/
1878 while (count --> 0) {
1879 if ((error = tget_mpf(MPF_DHCP4_CLI_MSG, (void*)&cell, TMO_DHCP4C_MPF_GET)) != E_OK) {
1880 syslog(LOG_NOTICE, "[DHCP4C] error, tget_mpf() for receive: %s.", itron_strerror(error));
1881 break;
1882 }
1883 cell->next = ct->rcv_lst;
1884 ct->rcv_lst = cell;
1885 }
1886
1887 return E_OK;
1888 }
1889
1890/*
1891 * dhcp4c_renew_info -- ネットワーク情報を再取得する。
1892 */
1893
1894ER
1895dhcp4c_renew_info (void)
1896{
1897 if (context.fsm == DHCP4_FSM_BOUND) {
1898
1899 /* REL_INFO 状態に遷移した後に SLEEP を解除するように設定する。*/
1900 context.flags |= DHCP4C_FLAG_RENEW;
1901 start_rel_info(&context);
1902 return E_OK;
1903 }
1904 else if (context.fsm == DHCP4_FSM_SLEEP) {
1905
1906 /* SLEEP を解除する。*/
1907 context.fsm = DHCP4_FSM_WAKE;
1908 context.timer = 0;
1909 wup_tsk(context.tskid);
1910 return E_OK;
1911 }
1912 else
1913 return E_OBJ;
1914 }
1915
1916/*
1917 * dhcp4c_rel_info -- DHCP で設定されたネットワーク情報を解放する。
1918 */
1919
1920ER
1921dhcp4c_rel_info (void)
1922{
1923 /* REL_INFO 状態に遷移する。*/
1924 start_rel_info(&context);
1925 return E_OK;
1926 }
1927
1928/*
1929 * dhcp4c_get_info -- DHCP で設定されたネットワーク情報を返す。
1930 */
1931
1932ER
1933dhcp4c_get_info (T_IN4_ADDR *addr, uint32_t *expire, uint32_t *renew,
1934 uint32_t *rebind, SYSTIM *bind_start)
1935{
1936 if (addr == NULL || expire == NULL ||
1937 renew == NULL || rebind == NULL || bind_start == NULL)
1938 return E_PAR;
1939 else if (context.act_msg == NULL)
1940 return E_OBJ;
1941 else {
1942 *addr = context.act_msg->srv.ipaddr;
1943 *expire = context.timers[DHCP4C_TIMER_EXPIRE];
1944 *renew = context.timers[DHCP4C_TIMER_RENEW];
1945 *rebind = context.timers[DHCP4C_TIMER_REBIND];
1946 *bind_start = context.bind_start;
1947 return E_OK;
1948 }
1949 }
1950
1951/*
1952 * コールバック関数
1953 */
1954
1955ER
1956callback_nblk_dhcp4_cli (ID cepid, FN fncd, void *p_parblk)
1957{
1958 T_DHCP4_CLI_MSG *msg;
1959 ER_UINT len;
1960
1961 len = *(ER_UINT*)p_parblk;
1962 if (len < 0 && len != E_RLWAI) {
1963 /* E_RLWAI 以外で、0 以下の場合は、エラーを意味している。*/
1964 syslog(LOG_NOTICE, "[DHCPC(CBR)] error: %s, fncd: %s", itron_strerror(len), in_strtfn(fncd));
1965 }
1966 else {
1967 if (fncd == TEV_UDP_RCV_DAT) {
1968
1969 /* 受信メッセージリストが空の時は、受信しないでデータグラムを捨てる。*/
1970 if (context.rcv_lst == NULL)
1971 syslog(LOG_NOTICE, "[DHCP4C(CBR)] receive buffer all busy.");
1972 else {
1973 /* メッセージを受信するメッセージ構造体を準備する。*/
1974 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
1975 msg = context.rcv_lst;
1976 context.rcv_lst = context.rcv_lst->next;
1977 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
1978
1979 /* メッセージを受信する。*/
1980 len = udp_rcv_dat(context.cepid, &msg->srv, &msg->msg, sizeof(msg->msg), TMO_POL);
1981
1982 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
1983 msg->len = len;
1984 if (len >= 0) {
1985 /* 受信したメッセージを検証メッセージリストに移す。*/
1986 msg->next = context.val_lst;
1987 context.val_lst = msg;
1988 context.flags |= DHCP4C_FLAG_RCV_MSG;
1989 }
1990 else {
1991 /* メッセージ構造体を受信メッセージリストに戻す。*/
1992 context.error = len;
1993 msg->next = context.rcv_lst;
1994 context.rcv_lst = msg;
1995 }
1996 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
1997 }
1998 }
1999 DHCP4_CLI_READY_SIGNAL((&context));
2000 }
2001 return E_OK;
2002 }
2003
2004#ifdef DHCP4_CLI_TASK
2005
2006/*
2007 * dhcp4_cli_task -- DHCP クライアントタスク
2008 */
2009
2010void
2011dhcp4_cli_task (intptr_t exinf)
2012{
2013 T_DHCP4_CLI_CONTEXT *ct;
2014 ID tskid;
2015 ER error = E_OK;
2016
2017 dly_tsk(1000);
2018 get_tid(&tskid);
2019 syslog(LOG_NOTICE, "[DHCP4C:%d,%d] started.", tskid, (ID)exinf);
2020 dly_tsk(500);
2021 ct = &context;
2022
2023 /* DHCP クライアントコンテキスト構造体を初期化する。*/
2024 init_context(ct, tskid, (ID)exinf);
2025 ct->fsm = DHCP4_FSM_SLEEP;
2026
2027 while (true) {
2028
2029 /* リースを解放後、再取得が指定されていなければ休止する。*/
2030 if (!(ct->flags & DHCP4C_FLAG_RENEW)) {
2031
2032 /* 休止する。*/
2033 if (error == E_OK) {
2034 if (ct->fsm != DHCP4_FSM_SLEEP)
2035 syslog(LOG_NOTICE, "[DHCP4C] lease released, go to sleep.");
2036 }
2037 else {
2038 syslog(LOG_NOTICE, "[DHCP4C] server not available, go to sleep, error: %s.", itron_strerror(error));
2039 ct->fsm = DHCP4_FSM_SLEEP;
2040 }
2041 slp_tsk();
2042 }
2043 ct->flags = 0;
2044 ct->error = E_OK;
2045
2046 /* 1秒毎にタイムアウトするようにタイマーを設定する。*/
2047 timeout((callout_func)dhcpc_timer, ct, NET_TIMER_HZ / DHCP4C_TIMER_HZ);
2048
2049 /* メッセージ構造体を初期化する。*/
2050 if ((error = init_cli_msg(ct)) == E_OK) {
2051
2052 /* SELECT 状態に遷移する。*/
2053 start_select(ct);
2054
2055 /* メインループ */
2056 error = dispatch_event(ct);
2057 }
2058
2059 /* 全ての TIMER をキャンセルする。*/
2060 cancel_all_timers(ct);
2061
2062 /* タイマーを停止する。*/
2063 untimeout((callout_func)dhcpc_timer, ct);
2064
2065 /* メッセージ構造体を解放する。*/
2066 rel_cli_msg (ct);
2067 }
2068 }
2069
2070#else
2071
2072T_DHCP4_CLI_CONTEXT *
2073dhcp4_cli_initialize(ID tskid, ID cepid)
2074{
2075 T_DHCP4_CLI_CONTEXT *ct = &context;
2076 /* DHCP クライアントコンテキスト構造体を初期化する。*/
2077 init_context(ct, tskid, cepid);
2078 ct->fsm = DHCP4_FSM_SLEEP;
2079 ct->timer = TMO_FEVR;
2080 return ct;
2081 }
2082
2083int
2084dhcp4_cli_get_timer(T_DHCP4_CLI_CONTEXT *ct)
2085{
2086 if (ct->fsm == DHCP4_FSM_SLEEP)
2087 return TMO_FEVR;
2088
2089 return ct->timer;
2090 }
2091
2092void
2093dhcp4_cli_progress(T_DHCP4_CLI_CONTEXT *ct, int elapse)
2094{
2095 int ix;
2096
2097 if ((ct->fsm == DHCP4_FSM_SLEEP) || (ct->timer == TMO_FEVR))
2098 return;
2099
2100 ct->timer -= elapse;
2101 if (ct->timer > 0)
2102 return;
2103
2104 /* 1秒毎にタイムアウトするようにタイマーを設定する。*/
2105 ct->timer = 1000 * 1000;
2106
2107 for (ix = NUM_DHCP4C_TIMERS; ix-- > 0; ) {
2108 if (ct->timers[ix] != 0) {
2109 ct->timers[ix] --;
2110 if (ct->timers[ix] <= 0) {
2111 ct->timers[ix] = 0;
2112 ct->flags = (ct->flags & ~DHCP4C_FLAG_TMOUT_MASK) | DHCP4C_FLAG_TMOUT_TIMER | ix;
2113 DHCP4_CLI_READY_SIGNAL(ct);
2114 }
2115 }
2116 }
2117 }
2118
2119void
2120dhcp4_cli_wakeup(T_DHCP4_CLI_CONTEXT *ct)
2121{
2122 if (ct->fsm == DHCP4_FSM_WAKE) {
2123 ct->flags = 0;
2124 ct->error = E_OK;
2125
2126 /* メッセージ構造体を初期化する。*/
2127 if ((ct->error = init_cli_msg(ct)) != E_OK)
2128 return;
2129
2130 ct->timer = 1000 * 1000;
2131
2132 /* SELECT 状態に遷移する。*/
2133 start_select(ct);
2134 }
2135
2136 if (ct->flags & DHCP4C_FLAG_RCV_MSG) {
2137 while (ct->val_lst != NULL) {
2138 ct->error = eval_rcv_msg(ct);
2139 }
2140 ct->flags &= ~DHCP4C_FLAG_RCV_MSG;
2141 }
2142 }
2143
2144void
2145dhcp4_cli_timeout(T_DHCP4_CLI_CONTEXT *ct)
2146{
2147 if (ct->flags & DHCP4C_FLAG_TMOUT_MASK)
2148 ct->error = dispatch_timeout(ct);
2149
2150 if (ct->error != E_OK || ct->fsm == DHCP4_FSM_SLEEP) {
2151 /* 全ての TIMER をキャンセルする。*/
2152 cancel_all_timers(ct);
2153 ct->timer = TMO_FEVR;
2154
2155 /* メッセージ構造体を解放する。*/
2156 rel_cli_msg(ct);
2157
2158 /* リースを解放後、再取得が指定されていなければ休止する。*/
2159 if (!(ct->flags & DHCP4C_FLAG_RENEW)) {
2160
2161 /* 休止する。*/
2162 if (ct->error == E_OK) {
2163 if (ct->fsm != DHCP4_FSM_SLEEP)
2164 syslog(LOG_NOTICE, "[DHCP4C] lease released, go to sleep.");
2165 }
2166 else {
2167 syslog(LOG_NOTICE, "[DHCP4C] server not available, go to sleep, error: %s.", itron_strerror(ct->error));
2168 ct->error = E_OK;
2169 ct->fsm = DHCP4_FSM_SLEEP;
2170 }
2171 }
2172 }
2173 }
2174
2175#endif /* DHCP4_CLI_TASK */
2176#endif /* of #ifdef DHCP4_CLI_CFG */
Note: See TracBrowser for help on using the repository browser.