source: asp3_tinet_ecnl_rx/trunk/asp3_dcre/tinet/netapp/dhcp4_cli.c@ 337

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

ASP3版ECNLを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 56.0 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/*
194 * dhcp4_cksum -- チェックサムの計算関数
195 */
196
197static uint32_t
198dhcp4_cksum (void *data, uint_t len /*オクテット単位*/)
199{
200 uint32_t carry, sum = 0;
201
202 for ( ; len > 0; len -= 2) {
203 sum += (*(uint8_t*)data << 8) + *((uint8_t*)data + 1);
204 data = (uint8_t*)data + 2;
205 }
206
207 while (sum >= 0x00010000) {
208 carry = sum >> 16;
209 sum = (sum & 0xffff) + carry;
210 }
211
212 return sum;
213 }
214
215/*
216 * create_xid -- トランザクション ID を生成する。
217 */
218
219static uint32_t
220create_xid (void)
221{
222 T_IF_SOFTC *ic;
223 SYSTIM time;
224
225 ic = IF_ETHER_NIC_GET_SOFTC();
226 get_tim(&time);
227 return (dhcp4_cksum((void*)&ic->ifaddr.lladdr, ETHER_ADDR_LEN) << 16)
228 + dhcp4_cksum((void*)&time, sizeof(time));
229 }
230
231/*
232 * find_option_sub -- 指定したオプションを探索する。
233 *
234 * 注意: 引数 size が 0 の時はオプションサイズを検証しない。
235 */
236
237static uint8_t *
238find_option_sub (T_DHCP4_CLI_MSG *msg, uint_t off, uint_t len,
239 uint_t tag, uint_t size, bool_t overload)
240{
241 uint8_t *opt, *tmp;
242
243 opt = (uint8_t*)&msg->msg + off;
244 while (opt < (uint8_t*)&msg->msg + off + len && *opt != DHCP4_OPT_END) {
245 if (*opt == DHCP4_OPT_PAD)
246 opt ++;
247 else if ((*opt == DHCP4_OPT_OPT_OVERLOAD) && overload) {
248 if (*(opt + 2) & DHCP4_OPTOL_FILE) {
249 tmp = find_option_sub(msg, DHCP4_FILE_OFFSET, DHCP4_FILE_LEN, tag, len, false);
250 if (tmp != NULL)
251 return tmp;
252 }
253 if (*(opt + 2) & DHCP4_OPTOL_SNAME) {
254 tmp = find_option_sub(msg, DHCP4_SNAME_OFFSET, DHCP4_SNAME_LEN, tag, len, false);
255 if (tmp != NULL)
256 return tmp;
257 }
258 opt += *(opt + 1) + 2;
259 }
260 else if (*opt == tag && (size == 0 || *(opt + 1) == size))
261 return opt;
262 else
263 opt += *(opt + 1) + 2;
264 }
265 return NULL;
266 }
267
268/*
269 * find_option -- 指定したオプションを探索する。
270 *
271 * 注意: 引数 size が 0 の時はオプションサイズを検証しない。
272 */
273
274static uint8_t *
275find_option (T_DHCP4_CLI_MSG *msg, uint_t tag, uint_t size)
276{
277 return find_option_sub(msg, DHCP4_OPTION_OFFSET + DHCP4_MAGIC_LEN,
278 msg->len - (DHCP4_OPTION_OFFSET + DHCP4_MAGIC_LEN),
279 tag, size, true);
280 }
281
282/*
283 * is_equal_sid -- メッセージ内の SERVER ID を比較する。
284 */
285
286static bool_t
287is_equal_sid (T_DHCP4_CLI_MSG *msg1, T_DHCP4_CLI_MSG *msg2)
288{
289 uint8_t *opt1, *opt2;
290
291 if ((opt1 = find_option(msg1, DHCP4_OPT_SERVER_ID, sizeof(T_IN4_ADDR))) == NULL)
292 return false;
293 if ((opt2 = find_option(msg2, DHCP4_OPT_SERVER_ID, sizeof(T_IN4_ADDR))) == NULL)
294 return false;
295
296 return msg2host32(opt1) == msg2host32(opt2);
297 }
298
299/*
300 * timer_value -- メッセージから時間情報を取り出す。
301 */
302
303static uint32_t
304timer_value (T_DHCP4_CLI_MSG *msg, uint_t tag, uint32_t def_value)
305{
306 uint8_t *opt;
307 uint32_t seconds;
308
309 if ((opt = find_option(msg, tag, sizeof(uint32_t))) == NULL)
310 return def_value;
311 else {
312
313 /* サーバからのリース時間は[s]。*/
314 seconds = msg2host32(opt + 2);
315
316 /* コンテキスト内のリース時間は SYSTIM_HZ。*/
317 if (seconds == DHCP4_TIME_INFINITY)
318 return DHCP4_TIME_INFINITY;
319 else if (seconds > SYSTIM2SEC(DHCP4_TIME_INFINITY))
320 return DHCP4_TIME_INFINITY;
321 else
322 return SEC2SYSTIM(seconds);
323 }
324 }
325
326/*
327 * rel_addr -- IPv4 アドレス、サブネットマスク、静的経路表を解放する。
328 */
329
330static void
331rel_addr (void)
332{
333 ER error;
334 uint_t count = 0;
335
336 if ((error = in4_add_ifaddr(IPV4_ADDRANY, IPV4_ADDRANY)) != E_OK) {
337 syslog(LOG_NOTICE, "[DHCP4C] error, IPv4 addr: %s", itron_strerror(error));
338 count ++;
339 }
340
341 if ((error = in4_add_route(0, IPV4_ADDRANY, IPV4_ADDRANY, IPV4_ADDRANY)) != E_OK) {
342 syslog(LOG_NOTICE, "[DHCP4C] error, release routing table: %s", itron_strerror(error));
343 count ++;
344 }
345
346 if ((error = in4_add_route(1, IPV4_ADDRANY, IPV4_ADDRANY, IPV4_ADDRANY)) != E_OK) {
347 syslog(LOG_NOTICE, "[DHCP4C] error, release routing table: %s", itron_strerror(error));
348 count ++;
349 }
350
351 if ((error = in4_add_route(2, 0xffffffff, 0xffffffff, IPV4_ADDRANY)) != E_OK) {
352 syslog(LOG_NOTICE, "[DHCP4C] error, release routing table: %s", itron_strerror(error));
353 count ++;
354 }
355
356 if (count == 0) {
357 syslog(LOG_NOTICE, "[DHCP4C] release IPv4 addr.");
358
359#if 0
360#ifdef USE_LCD
361 dly_tsk(1 * 1000);
362 lcd_puts(LCD_PORTID, "0.0.0.0\n");
363#endif /* of #ifdef USE_LCD */
364#endif
365 ether_set_down();
366 }
367 }
368
369/*
370 * rel_options -- リースされたオプションを解析して値を解放する。
371 */
372
373static void
374rel_options (T_DHCP4_CLI_CONTEXT *ct, uint_t off, uint_t len, bool_t overload)
375{
376#if defined(USE_RESOLVER)
377 T_IN4_ADDR addr;
378#endif
379
380 uint8_t *opt;
381
382 opt = (uint8_t*)&ct->act_msg->msg + off;
383 while (opt < (uint8_t*)&ct->act_msg->msg + off + len && *opt != DHCP4_OPT_END) {
384 if (*opt == DHCP4_OPT_PAD)
385 opt ++;
386 else if ((*opt == DHCP4_OPT_OPT_OVERLOAD) && overload) {
387 if (*(opt + 2) & DHCP4_OPTOL_FILE)
388 rel_options(ct, DHCP4_FILE_OFFSET, DHCP4_FILE_LEN, false);
389 if (*(opt + 2) & DHCP4_OPTOL_SNAME)
390 rel_options(ct, DHCP4_SNAME_OFFSET, DHCP4_SNAME_LEN, false);
391 opt += *(opt + 1) + 2;
392 }
393 else {
394
395 switch (*opt) {
396
397#if defined(USE_RESOLVER)
398
399 case DHCP4_OPT_DNS_SERVER:
400 addr = IPV4_ADDRANY;
401 dns_in4_set_addr(&addr);
402 break;
403
404 case DHCP4_OPT_HOST_NAME:
405 break;
406
407 case DHCP4_OPT_DOMAIN_NAME:
408 dns_in4_set_dname("", 0);
409 break;
410
411#else /* of #if defined(USE_RESOLVER) */
412
413 case DHCP4_OPT_DNS_SERVER:
414 case DHCP4_OPT_HOST_NAME:
415 case DHCP4_OPT_DOMAIN_NAME:
416
417#endif /* of #if defined(USE_RESOLVER) */
418
419 case DHCP4_OPT_SUBNET_MASK:
420 case DHCP4_OPT_ROUTER:
421 case DHCP4_OPT_LEASE_TIME:
422 case DHCP4_OPT_RENEWAL_T1:
423 case DHCP4_OPT_REBINDING_T2:
424 break;
425
426 default:
427 break;
428 }
429
430 opt += *(opt + 1) + 2;
431 }
432 }
433 }
434
435/*
436 * rel_lease -- リースされた情報を解放する。
437 */
438
439static void
440rel_lease (T_DHCP4_CLI_CONTEXT *ct)
441{
442 /* 有効なリース・メッセージ構造体が無ければ何もしない。*/
443 if (ct->act_msg == NULL)
444 return;
445
446 /* リースされたオプションを解析して値を解放する。*/
447 rel_options(ct, DHCP4_OPTION_OFFSET + DHCP4_MAGIC_LEN,
448 ct->act_msg->len - (DHCP4_OPTION_OFFSET + DHCP4_MAGIC_LEN), true);
449 rel_addr();
450
451 /* 有効なリース・メッセージ構造体を解放する。*/
452 syscall(rel_mpf(MPF_DHCP4_CLI_MSG, (void*)ct->act_msg));
453 ct->act_msg = NULL;
454 }
455
456/*
457 * set_addr -- IPv4 アドレス、サブネットマスク、静的経路表を設定する。
458 */
459
460static void
461set_addr (T_DHCP4_CLI_CONTEXT *ct, uint8_t *mopt, uint8_t *ropt)
462{
463 ER error;
464 T_IN4_ADDR addr, mask, router, net_addr;
465
466 addr = ntohl(ct->act_msg->msg.yiaddr);
467 mask = msg2host32(mopt + 2);
468 net_addr = addr & mask;
469 router = msg2host32(ropt + 2);
470
471 if ((error = in4_add_ifaddr(addr, mask)) != E_OK)
472 syslog(LOG_NOTICE, "[DHCP4C] error, set IPv4 addr: %s", itron_strerror(error));
473
474 if ((error = in4_add_route(0, IPV4_ADDRANY, IPV4_ADDRANY, router)) != E_OK)
475 syslog(LOG_NOTICE, "[DHCP4C] error, set routing table: %s", itron_strerror(error));
476
477 if ((error = in4_add_route(1, net_addr, mask, IPV4_ADDRANY)) != E_OK)
478 syslog(LOG_NOTICE, "[DHCP4C] error, set routing table: %s", itron_strerror(error));
479
480 if ((error = in4_add_route(2, 0xffffffff, 0xffffffff, IPV4_ADDRANY)) != E_OK)
481 syslog(LOG_NOTICE, "[DHCP4C] error, set routing table: %s", itron_strerror(error));
482
483 if (error == E_OK) {
484 syslog(LOG_NOTICE, "[DHCP4C] set IPv4 addr: %s.", ip2str(NULL, &addr));
485
486#ifdef USE_LCD
487 dly_tsk(1 * 1000);
488 lcd_puts(LCD_PORTID, ip2str(NULL, &addr));
489 lcd_putc(LCD_PORTID, '\n');
490#endif /* of #ifdef USE_LCD */
491 ether_set_up();
492 }
493 }
494
495/*
496 * set_options -- リースされたオプションを解析して値を設定する。
497 */
498
499static void
500set_options (T_DHCP4_CLI_CONTEXT *ct, uint_t off, uint_t len, bool_t overload)
501{
502#if defined(USE_RESOLVER)
503 T_IN4_ADDR addr;
504#endif
505
506 uint8_t *opt, *mopt = NULL, *ropt = NULL;
507
508 opt = (uint8_t*)&ct->act_msg->msg + off;
509 while (opt < (uint8_t*)&ct->act_msg->msg + off + len && *opt != DHCP4_OPT_END) {
510 if (*opt == DHCP4_OPT_PAD)
511 opt ++;
512 else if ((*opt == DHCP4_OPT_OPT_OVERLOAD) && overload) {
513 if (*(opt + 2) & DHCP4_OPTOL_FILE)
514 set_options(ct, DHCP4_FILE_OFFSET, DHCP4_FILE_LEN, false);
515 if (*(opt + 2) & DHCP4_OPTOL_SNAME)
516 set_options(ct, DHCP4_SNAME_OFFSET, DHCP4_SNAME_LEN, false);
517 opt += *(opt + 1) + 2;
518 }
519 else {
520
521 switch (*opt) {
522 case DHCP4_OPT_SUBNET_MASK:
523 mopt = opt;
524 break;
525
526 case DHCP4_OPT_ROUTER:
527 ropt = opt;
528 break;
529
530#if defined(USE_RESOLVER)
531
532 case DHCP4_OPT_DNS_SERVER:
533 addr = msg2host32(opt + 2);
534 dns_in4_set_addr(&addr);
535 break;
536
537 case DHCP4_OPT_HOST_NAME:
538 break;
539
540 case DHCP4_OPT_DOMAIN_NAME:
541 dns_in4_set_dname(opt + 2, *(opt + 1));
542 break;
543
544#else /* of #if defined(USE_RESOLVER) */
545
546 case DHCP4_OPT_DNS_SERVER:
547 case DHCP4_OPT_HOST_NAME:
548 case DHCP4_OPT_DOMAIN_NAME:
549
550#endif /* of #if defined(USE_RESOLVER) */
551
552 case DHCP4_OPT_LEASE_TIME:
553 case DHCP4_OPT_RENEWAL_T1:
554 case DHCP4_OPT_REBINDING_T2:
555 break;
556
557 default:
558 break;
559 }
560
561 opt += *(opt + 1) + 2;
562 }
563 }
564 if (!(mopt == NULL || ropt == NULL))
565 set_addr(ct, mopt, ropt);
566 }
567
568/*
569 * set_lease -- リースされた情報を設定する。
570 */
571
572static void
573set_lease (T_DHCP4_CLI_CONTEXT *ct)
574{
575 /* リースされたオプションを解析して値を設定する。*/
576 set_options(ct, DHCP4_OPTION_OFFSET + DHCP4_MAGIC_LEN,
577 ct->act_msg->len - (DHCP4_OPTION_OFFSET + DHCP4_MAGIC_LEN), true);
578 }
579
580/*
581 * validate_duplicate -- 指定された IPv4 アドレスが使われていないか検証する。
582 *
583 * 使われていない時は true を返す。
584 */
585
586static bool_t
587validate_duplicate (T_DHCP4_CLI_MSG *msg)
588{
589 T_IN4_ADDR yiaddr;
590
591 /* 指定された IPv4 アドレスが ADDR ANY なら使われていないと判断する。*/
592 yiaddr = ntohl(msg->msg.yiaddr);
593 if (yiaddr == IPV4_ADDRANY)
594 return true;
595
596 /* ARP キャッシュにあれば使われていると判断する。*/
597 if (arp_lookup(yiaddr, false) != NULL)
598 return false;
599
600 /*
601 * ARP 要求を出力して TMO_DHCP4C_ARP_WAIT 待ち、
602 * ARP キャッシュになければ使われていないと判断する。
603 */
604 arp_request(&IF_ETHER_NIC_GET_SOFTC()->ifaddr, yiaddr);
605 dly_tsk(TMO_DHCP4C_ARP_WAIT);
606 return arp_lookup(yiaddr, false) == NULL;
607 }
608
609/*
610 * validate_rcv_msg -- 受信メッセージを検証する。
611 */
612
613static ER
614validate_rcv_msg (T_DHCP4_CLI_CONTEXT *ct, T_DHCP4_CLI_MSG *msg)
615{
616 uint8_t *opt;
617
618 /* packet type が DHCP4_REPLY であることを確認する。*/
619 if (!(msg->msg.op == DHCP4_REPLY))
620 return false;
621
622 /* メッセージタイプオプションがあることを確認する。*/
623 if ((opt = find_option(msg, DHCP4_OPT_MSG_TYPE, 1)) == NULL)
624 return E_PAR;
625
626 /* メッセージのタイプが一致していることを検証する。*/
627 msg->type = *(opt + 2);
628 switch (ct->fsm) {
629
630 case DHCP4_FSM_SELECT:
631 if (!(msg->type == DHCP4_MTYPE_OFFER))
632 return E_PAR;
633 break;
634
635 case DHCP4_FSM_REQUEST:
636 case DHCP4_FSM_REBOOT:
637 case DHCP4_FSM_RENEW:
638 case DHCP4_FSM_REBIND:
639 case DHCP4_FSM_REL_INFO:
640 if (!((msg->type == DHCP4_MTYPE_ACK) || (msg->type == DHCP4_MTYPE_NAK)))
641 return E_PAR;
642 break;
643
644 case DHCP4_FSM_INIT:
645 case DHCP4_FSM_BOUND:
646 case DHCP4_FSM_INIT_REBOOT:
647 return E_PAR;
648 break;
649
650 default:
651 syslog(LOG_NOTICE, "[DHCP4C] error, unknown state: %d.", ct->fsm);
652 return E_PAR;
653 break;
654 }
655
656 /* マジック番号を検証する。*/
657 if (memcmp((uint8_t*)&msg->msg.options, magicno, DHCP4_MAGIC_LEN))
658 return E_PAR;
659
660 /* トランザクション ID が異なっていればエラー */
661 if (ntohl(msg->msg.xid) != ct->xid)
662 return E_PAR;
663
664 /* ハードウェアアドレス長が 6(MAC アドレス長)でなければエラー */
665 if (msg->msg.hlen != ETHER_ADDR_LEN)
666 return E_PAR;
667
668 /* ハードウェアアドレスが異なっていればエラー */
669 if (memcmp(&msg->msg.chaddr, &ct->sc->ifaddr.lladdr, sizeof(ct->sc->ifaddr.lladdr)))
670 return E_PAR;
671
672 /*
673 * メッセージタイプが OFFER の場合は、
674 * ARP を使用して、指定された IPv4 アドレスが使われていないか検証する。
675 * 使われている時は、他の IPv4 アドレスの提供を待つ。
676 */
677 if (msg->type == DHCP4_MTYPE_OFFER) {
678 if (!validate_duplicate(msg))
679 return E_PAR;
680 }
681
682 return E_OK;
683 }
684
685/*
686 * eval_prefer -- 受信メッセージの推奨度を評価する。
687 */
688
689static void
690eval_prefer (T_DHCP4_CLI_MSG *msg)
691{
692 int ix;
693
694 /* 無効の場合は終了する。*/
695 if (msg == NULL)
696 return;
697
698 /* 指定された IPv4 アドレスが ADDR ANY なら推奨度を 0に設定する。*/
699 if (ntohl(msg->msg.yiaddr) == IPV4_ADDRANY)
700 msg->prefer = 0;
701 else
702 msg->prefer = DHCP4_CLI_CFG_PREFER_ADDR;
703
704#if defined(DHCP4_CLI_CFG_REQUEST_OLIST)
705
706 /* 要求オプションを検証する。*/
707 for (ix = sizeof(request_plist); ix -- > 0; ) {
708 if (find_option(msg, request_plist[ix], 0) != NULL)
709 msg->prefer ++;
710 }
711
712#endif /* of #if defined(DHCP4_CLI_CFG_REQUEST_OLIST) */
713
714#if defined(DHCP4_CLI_CFG_REQUIRED_OLIST)
715
716 /* 必須オプションを検証する。*/
717 for (ix = sizeof(required_plist); ix -- > 0; ) {
718 if (find_option(msg, required_plist[ix], 0) == NULL)
719 msg->prefer = 0;
720 }
721
722#endif /* of #if defined(DHCP4_CLI_CFG_REQUIRED_OLIST) */
723 }
724
725/*
726 * eval_rcv_msg -- 受信メッセージを評価する。
727 */
728
729static ER
730eval_rcv_msg (T_DHCP4_CLI_CONTEXT *ct)
731{
732 T_DHCP4_CLI_MSG *evl, *msg;
733
734 /* メッセージを受信していなければ中止する。*/
735 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
736 if (ct->val_lst == NULL) {
737 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
738 return E_OK;
739 }
740
741 /* 検証メッセージリストから評価メッセージを取り出す。*/
742 evl = ct->val_lst;
743 ct->val_lst = ct->val_lst->next;
744 evl->next = NULL;
745 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
746
747 /* 評価メッセージを検証する。*/
748 if (validate_rcv_msg(ct, evl) != E_OK) {
749
750 /* エラーが発生した評価メッセージを受信メッセージ構造体リストに戻す。*/
751 goto rcv_ret;
752 }
753
754 /* 受信したメッセージが NAK の時の処理 */
755 if (evl->type == DHCP4_MTYPE_NAK) {
756
757 /* リースされた情報を解放する。*/
758 rel_lease(ct);
759
760 /* 内部エラーを設定して終了する。*/
761 return E_PAR;
762 }
763
764 /* REL_INFO 状態の時の処理 */
765 //cons_printf(CONSOLE_PORTID, "evl_rcv_msg3[s=%d]\n", ct->fsm);
766 if (ct->fsm == DHCP4_FSM_REL_INFO) {
767 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
768 evl->next = ct->prf_lst;
769 ct->prf_lst = evl;
770 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
771 return E_OK;
772 }
773
774 /* 評価メッセージの推奨度を評価する。*/
775 eval_prefer(evl);
776
777 /* 推奨メッセージリストが空なら評価メッセージを移して終了する。*/
778 if (ct->prf_lst == NULL) {
779 ct->max_prefer = evl->prefer;
780 ct->prf_lst = evl;
781 return E_OK;
782 }
783
784 /* 評価メッセージの推奨度と推奨メッセージリストの最大推奨度を比較する。*/
785 if (evl->prefer > ct->max_prefer) {
786
787 /*
788 * 評価メッセージの推奨度が推奨メッセージリストの最大推奨度より高ければ、
789 * 推奨メッセージリストを受信メッセージ構造体リストに戻し、
790 * 評価メッセージを推奨メッセージリストに移す。
791 */
792 ct->max_prefer = evl->prefer;
793 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
794 if (ct->rcv_lst == NULL)
795 ct->rcv_lst = ct->prf_lst;
796 else {
797 for (msg = ct->rcv_lst; msg->next != NULL; msg = msg->next)
798 ;
799 msg->next = ct->prf_lst;
800 }
801 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
802 ct->prf_lst = evl;
803 return E_OK;
804 }
805
806 else if (evl->prefer == ct->max_prefer) {
807 for (msg = ct->prf_lst; msg != NULL; msg = msg->next) {
808 if (is_equal_sid(evl, msg)) {
809
810 /*
811 * 推奨メッセージリストに同じ DHCP4_OPT_SERVER_ID のメッセージがあれば、
812 * 評価メッセージを受信メッセージ構造体リストに戻す。
813 */
814 goto rcv_ret;
815 }
816 }
817
818 /*
819 * 評価メッセージを推奨メッセージリストに移す。
820 */
821 evl->next = ct->prf_lst;
822 ct->prf_lst = evl;
823 return E_OK;
824 }
825
826 /*else */
827 /*
828 * 評価メッセージの推奨度が推奨メッセージリストの最大推奨度より低ければ、
829 * 評価メッセージを受信メッセージ構造体リストに戻す。
830 */
831
832rcv_ret:
833 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
834 evl->next = ct->rcv_lst;
835 ct->rcv_lst = evl;
836 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
837 return E_OK;
838 }
839
840/*
841 * select_msg -- 推奨メッセージを選択する。
842 */
843
844static T_DHCP4_CLI_MSG*
845select_msg (T_DHCP4_CLI_CONTEXT *ct)
846{
847 T_DHCP4_CLI_MSG *msg, *select;
848
849 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
850 if (ct->prf_lst == NULL) {
851 /* メッセージを受信していなければ中止する。*/
852 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
853 return NULL;
854 }
855
856 /* 推奨メッセージリストの先頭のメッセージを選択する。*/
857 select = ct->prf_lst;
858 ct->prf_lst = ct->prf_lst->next;
859 select->next = NULL;
860
861 /* 選択されなかった検証メッセージを受信メッセージ構造体リストに戻す。*/
862 if (ct->rcv_lst == NULL)
863 ct->rcv_lst = ct->prf_lst;
864 else {
865 for (msg = ct->rcv_lst; msg->next != NULL; msg = msg->next)
866 ;
867 msg->next = ct->prf_lst;
868 }
869 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
870 return select;
871 }
872
873/*
874 * select_ack -- ACK メッセージを検証する。
875 *
876 * 受け入れることが可能の時は true を返す。
877 */
878
879static bool_t
880select_ack (T_DHCP4_CLI_CONTEXT *ct)
881{
882 T_DHCP4_CLI_MSG *msg;
883
884 if ((msg = select_msg(ct)) == NULL)
885 return false;
886
887 /* 有効なリース・メッセージが残っていれば、受信メッセージ構造体リストに戻す。*/
888 if (ct->act_msg != NULL) {
889 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
890 ct->act_msg->next = ct->rcv_lst;
891 ct->rcv_lst = ct->act_msg;
892 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
893 }
894
895 /* 有効なリース・メッセージに設定する。*/
896 ct->act_msg = msg;
897 return true;
898 }
899
900/*
901 * select_offer -- OFFER メッセージを検証する。
902 *
903 * 受け入れることが可能の時は true を返す。
904 */
905
906static bool_t
907select_offer (T_DHCP4_CLI_CONTEXT *ct)
908{
909 return (ct->off_msg = select_msg(ct)) != NULL;
910 }
911
912/*
913 * cancel_all_timers -- 全ての TIMER をキャンセルする。
914 */
915
916static void
917cancel_all_timers (T_DHCP4_CLI_CONTEXT *ct)
918{
919 int ix;
920
921 syscall(wai_sem(SEM_DHCP4_CLI_TIMER));
922 for (ix = NUM_DHCP4C_TIMERS; ix -- > 0; )
923 ct->timers[ix] = 0;
924 syscall(sig_sem(SEM_DHCP4_CLI_TIMER));
925 }
926
927
928/*
929 * start_select -- DISCOVER メッセージを送信して SELECT 状態に遷移する。
930 */
931
932static void
933start_select (T_DHCP4_CLI_CONTEXT *ct)
934{
935 /* 送信を開始した時間を記録する。*/
936 get_tim(&ct->snd_start);
937
938 /* OFFER メッセージ受信タイムアウトを設定する。*/
939 syscall(wai_sem(SEM_DHCP4_CLI_TIMER));
940 ct->timers[DHCP4C_TIMER_RCV_OFFER] = SYSTIM2TIMER(TMO_DHCP4C_OFFER);
941 syscall(sig_sem(SEM_DHCP4_CLI_TIMER));
942
943 /* 送信先アドレスにローカルネットワークへのブロードキャストを設定する。*/
944 ct->dst.ipaddr = IPV4_ADDRBROADCAST;
945
946 /* 送信間隔をリセットする。*/
947 ct->interval = 0;
948
949 /* SELECT 状態に遷移する。*/
950 ct->fsm = DHCP4_FSM_SELECT;
951
952 /* DISCOVER メッセージを送信する。*/
953 ct->flags |= DHCP4C_FLAG_TMOUT_SND_DISC;
954 syscall(sig_sem(SEM_DHCP4_CLI_READY));
955 }
956
957/*
958 * start_bound -- BOUND 状態に遷移する。
959 */
960
961static void
962start_bound (T_DHCP4_CLI_CONTEXT *ct)
963{
964 /* リースされた情報を設定する。*/
965 set_lease(ct);
966
967 /* リースの有効時間を設定する。*/
968 ct->expire = timer_value(ct->act_msg, DHCP4_OPT_LEASE_TIME, TMO_DHCP4C_DEF_LEASE);
969
970 /* リース時間が TMO_DHCP4C_MIN_LEASE 以下の時は、TMO_DHCP4C_MIN_LEASE に設定する。*/
971 if (ct->expire < TMO_DHCP4C_MIN_LEASE)
972 ct->expire = TMO_DHCP4C_MIN_LEASE;
973
974 /* RENEW 状態までの時間を設定する。*/
975 ct->renew = timer_value(ct->act_msg, DHCP4_OPT_RENEWAL_T1, ct->expire / 2);
976
977 /* REBIND 状態までの時間を設定する。*/
978 ct->rebind = timer_value(ct->act_msg, DHCP4_OPT_REBINDING_T2, ct->renew + ct->renew / 2 + ct->renew / 4);
979
980 /* EXPIRE、RENEW、REBIND タイマーを設定する。*/
981 syscall(wai_sem(SEM_DHCP4_CLI_TIMER));
982 ct->timers[DHCP4C_TIMER_EXPIRE] = SYSTIM2TIMER(ct->expire); /* EXPIRE までの時間 */
983 ct->timers[DHCP4C_TIMER_REBIND] = SYSTIM2TIMER(ct->rebind); /* REBIND(T2)までの時間 */
984 ct->timers[DHCP4C_TIMER_RENEW] = SYSTIM2TIMER(ct->renew); /* RENEW (T1)までの時間 */
985 syscall(sig_sem(SEM_DHCP4_CLI_TIMER));
986
987 /* BOUND 状態に遷移する。*/
988 ct->fsm = DHCP4_FSM_BOUND;
989
990 /* BIND を開始した時間を記録する。*/
991 get_tim(&ct->bind_start);
992 }
993
994/*
995 * start_send_request -- REQUEST メッセージを送信して、指定された状態に遷移する。
996 */
997
998static void
999start_send_request (T_DHCP4_CLI_CONTEXT *ct, uint_t fsm)
1000{
1001 T_IFNET *ifp = IF_GET_IFNET();
1002
1003 /* 送信を開始した時間を記録する。*/
1004 get_tim(&ct->snd_start);
1005
1006 /* 遷移する状態が RENEW 以外では ACK/NAK メッセージ受信タイムアウトを設定する。*/
1007 if (fsm != DHCP4_FSM_RENEW) {
1008 syscall(wai_sem(SEM_DHCP4_CLI_TIMER));
1009 ct->timers[DHCP4C_TIMER_RCV_ACK] = SYSTIM2TIMER(TMO_DHCP4C_ACK);
1010 syscall(sig_sem(SEM_DHCP4_CLI_TIMER));
1011 }
1012
1013 /*
1014 * 遷移する状態が RENEW で、
1015 * SERVER ID オプションがあればローカルネットワークへのブロードキャストを送信する。
1016 */
1017 if ((fsm == DHCP4_FSM_RENEW) &&
1018 (find_option(ct->act_msg, DHCP4_OPT_SERVER_ID, sizeof(T_IN4_ADDR)) != NULL))
1019 ct->dst.ipaddr = (ifp->in4_ifaddr.addr & ifp->in4_ifaddr.mask) | ~ifp->in4_ifaddr.mask;
1020 else
1021 ct->dst.ipaddr = IPV4_ADDRBROADCAST;
1022
1023 /* 送信間隔をリセットする。*/
1024 ct->interval = 0;
1025
1026 /* 指定された状態に遷移する。*/
1027 ct->fsm = fsm;
1028
1029 /* REQUEST メッセージを送信する。*/
1030 ct->flags |= DHCP4C_FLAG_TMOUT_SND_REQ;
1031 syscall(sig_sem(SEM_DHCP4_CLI_READY));
1032 }
1033
1034/*
1035 * start_rel_info -- アドレス情報を解放する。
1036 *
1037 * 注意: DHCPv4 の RFC2131 には無い
1038 */
1039
1040static void
1041start_rel_info (T_DHCP4_CLI_CONTEXT *ct)
1042{
1043 /* 全ての TIMER をキャンセルする。*/
1044 cancel_all_timers(ct);
1045
1046 /* 有効なリース情報が無ければ SLEEP に遷移する。*/
1047 if (ct->act_msg == NULL) {
1048 ct->fsm = DHCP4_FSM_SLEEP;
1049 return;
1050 }
1051
1052 /* 送信先アドレスにローカルネットワークへのブロードキャストを設定する。*/
1053 ct->dst.ipaddr = IPV4_ADDRBROADCAST;
1054
1055 /* RELEASE メッセージを送信する。*/
1056 ct->flags |= DHCP4C_FLAG_TMOUT_SND_REL;
1057 syscall(sig_sem(SEM_DHCP4_CLI_READY));
1058 }
1059
1060/*
1061 * setup_dhcp_com_msg -- DHCP メッセージの共通部分を作成する。
1062 */
1063
1064static uint8_t *
1065setup_dhcp_com_msg (T_DHCP4_CLI_CONTEXT *ct, uint_t op, uint_t type)
1066{
1067 uint8_t *option;
1068
1069 memset((void*)&ct->snd_msg->msg, 0, sizeof(ct->snd_msg->msg));
1070 ct->snd_msg->len = sizeof(ct->snd_msg->msg);
1071
1072 /* ヘッダ部を設定する。*/
1073 ct->snd_msg->msg.op = op;
1074 ct->snd_msg->msg.htype = DHCP4_HWA_TYPE_ETHER;
1075 ct->snd_msg->msg.hlen = ETHER_ADDR_LEN;
1076 HOST2MSG32(ct->snd_msg->msg.xid, ct->xid);
1077
1078 /* MAC アドレスを設定する。*/
1079 memcpy(&ct->snd_msg->msg.chaddr, &ct->sc->ifaddr.lladdr, ETHER_ADDR_LEN);
1080
1081 /*
1082 * オプション部を設定する。
1083 */
1084
1085 /* RFC1048 に定義されているマジック番号を設定する。*/
1086 memcpy(&ct->snd_msg->msg.options, magicno, DHCP4_MAGIC_LEN);
1087 option = ct->snd_msg->msg.options + DHCP4_MAGIC_LEN;
1088
1089 /* DHCP メッセージタイプを設定する。*/
1090 *(option ++) = DHCP4_OPT_MSG_TYPE;
1091 *(option ++) = 1;
1092 *(option ++) = type;
1093
1094 return option;
1095 }
1096
1097/*
1098 * setup_release_msg -- RELEASE メッセージを作成する。
1099 */
1100
1101static ER
1102setup_release_msg (T_DHCP4_CLI_CONTEXT *ct, T_DHCP4_CLI_MSG *ref)
1103{
1104 uint8_t *opt, *ref_opt;
1105
1106 /* 有効なリース・メッセージがなければエラー */
1107 if (ref == NULL)
1108 return E_PAR;
1109
1110 ct->xid = create_xid();
1111 if ((opt = setup_dhcp_com_msg(ct, DHCP4_REQUEST, DHCP4_MTYPE_RELEASE)) == NULL)
1112 return E_PAR;
1113
1114 /*
1115 * サーバ ID(server-ip)を設定する。
1116 * RFC2131 4.4.1 Initialization and allocation of network address 参照
1117 */
1118 if ((ref_opt = find_option(ref, DHCP4_OPT_SERVER_ID, sizeof(T_IN4_ADDR))) == NULL)
1119 return E_PAR;
1120 *(opt ++) = *(ref_opt ++);
1121 *(opt ++) = *(ref_opt ++);
1122 memcpy(opt, ref_opt, *(ref_opt - 1));
1123 opt += *(ref_opt - 1);
1124
1125 /*
1126 * クライアント ID(MAC アドレス)を設定する。
1127 * RFC2131 4.4.1 Initialization and allocation of network address 参照
1128 */
1129 *(opt ++) = DHCP4_OPT_CLIENT_ID;
1130 *(opt ++) = ETHER_ADDR_LEN + 1;
1131 *(opt ++) = DHCP4_HWA_TYPE_ETHER;
1132 memcpy(opt, &ct->sc->ifaddr.lladdr, ETHER_ADDR_LEN);
1133 opt += ETHER_ADDR_LEN;
1134
1135 /* オプションの終了を設定する。*/
1136 *(opt ++) = DHCP4_OPT_END;
1137
1138 /*
1139 * クライアント IP アドレス(ciaddr)を設定する。
1140 * RFC2131 4.4.1 Initialization and allocation of network address 参照
1141 */
1142 HOST2MSG32(ct->snd_msg->msg.ciaddr, IF_GET_IFNET()->in4_ifaddr.addr);
1143
1144 /* メッセージ長を設定する。*/
1145 ct->snd_msg->len = sizeof(ct->snd_msg->msg) - DHCP4_DFLT_OPT_LEN
1146 + (opt - (uint8_t*)&ct->snd_msg->msg.options);
1147 return E_OK;
1148 }
1149
1150
1151/*
1152 * setup_request_msg -- REQUEST メッセージを作成する。
1153 */
1154
1155static ER
1156setup_request_msg (T_DHCP4_CLI_CONTEXT *ct, T_DHCP4_CLI_MSG *ref)
1157{
1158 uint8_t *opt, *ref_opt;
1159
1160#if defined(DHCP4_CLI_CFG_REQUIRED_OLIST) || defined(DHCP4_CLI_CFG_REQUEST_OLIST)
1161 uint_t len = 0;
1162#endif
1163
1164 /* 参照するメッセージがなければエラー */
1165 if (ref == NULL)
1166 return E_PAR;
1167
1168 ct->xid = create_xid();
1169 if ((opt = setup_dhcp_com_msg(ct, DHCP4_REQUEST, DHCP4_MTYPE_REQUEST)) == NULL)
1170 return E_PAR;
1171
1172#if defined(DHCP4_CLI_CFG_REQUIRED_OLIST) || defined(DHCP4_CLI_CFG_REQUEST_OLIST)
1173
1174 /* 追加のオプションを設定する。*/
1175
1176 *opt = DHCP4_OPT_REQ_PARAM;
1177 opt += 2;
1178
1179#if defined(DHCP4_CLI_CFG_REQUIRED_OLIST)
1180
1181 /* 要求オプションリストを設定する。*/
1182 if (sizeof(required_plist) > 0) {
1183 memcpy(opt, required_plist, sizeof(required_plist));
1184 opt += sizeof(required_plist);
1185 len += sizeof(required_plist);
1186 }
1187
1188#endif /* of #if defined(DHCP4_CLI_CFG_REQUIRED_OLIST) */
1189
1190#if defined(DHCP4_CLI_CFG_REQUEST_OLIST)
1191
1192 /* 要求オプションリストを設定する。*/
1193 if (sizeof(request_plist) > 0) {
1194 memcpy(opt, request_plist, sizeof(request_plist));
1195 opt += sizeof(request_plist);
1196 len += sizeof(request_plist);
1197 }
1198
1199#endif /* of #if defined(DHCP4_CLI_CFG_REQUEST_OLIST) */
1200
1201 *(opt - len - 1) = len;
1202
1203#endif /* of #if defined(DHCP4_CLI_CFG_REQUIRED_OLIST) || defined(DHCP4_CLI_CFG_REQUEST_OLIST) */
1204
1205 /*
1206 * サーバ ID(server-ip)を設定する。
1207 * RFC2131 4.4.1 Initialization and allocation of network address 参照
1208 */
1209 if (ct->fsm == DHCP4_FSM_REQUEST) {
1210 if ((ref_opt = find_option(ref, DHCP4_OPT_SERVER_ID, sizeof(T_IN4_ADDR))) == NULL)
1211 return E_PAR;
1212 *(opt ++) = *(ref_opt ++);
1213 *(opt ++) = *(ref_opt ++);
1214 memcpy(opt, ref_opt, *(ref_opt - 1));
1215 opt += *(ref_opt - 1);
1216 }
1217
1218 /*
1219 * 要求 IP アドレス(requested-ip)を設定する。
1220 * RFC2131 4.4.1 Initialization and allocation of network address 参照
1221 * RFC2131 では、DHCP4_FSM_RENEW の時 MUST NOT になっているが、
1222 * MUST のようである。
1223 */
1224 *(opt ++) = DHCP4_OPT_REQ_IPV4;
1225 *(opt ++) = sizeof(ref->msg.yiaddr);
1226 if (ct->fsm == DHCP4_FSM_REQUEST || ct->fsm == DHCP4_FSM_INIT_REBOOT ||
1227 ct->fsm == DHCP4_FSM_RENEW || ct->fsm == DHCP4_FSM_REBIND)
1228 /* 参照メッセージと同じ IP アドレス(requested-ip)を要求する。*/
1229 memcpy(opt, (uint8_t*)&ref->msg.yiaddr, sizeof(ref->msg.yiaddr));
1230 else
1231 host2msg32(opt, IPV4_ADDRANY);
1232 opt += sizeof(ref->msg.yiaddr);
1233
1234 /*
1235 * クライアント ID(MAC アドレス)を設定する。
1236 * RFC2131 4.4.1 Initialization and allocation of network address 参照
1237 */
1238 *(opt ++) = DHCP4_OPT_CLIENT_ID;
1239 *(opt ++) = ETHER_ADDR_LEN + 1;
1240 *(opt ++) = DHCP4_HWA_TYPE_ETHER;
1241 memcpy(opt, &ct->sc->ifaddr.lladdr, ETHER_ADDR_LEN);
1242 opt += ETHER_ADDR_LEN;
1243
1244 /* オプションの終了を設定する。*/
1245 *(opt ++) = DHCP4_OPT_END;
1246
1247 /*
1248 * クライアント IP アドレス(ciaddr)を設定する。
1249 * RFC2131 4.4.1 Initialization and allocation of network address 参照
1250 */
1251 if (ct->fsm == DHCP4_FSM_RENEW || ct->fsm == DHCP4_FSM_REBIND)
1252 HOST2MSG32(ct->snd_msg->msg.ciaddr, IF_GET_IFNET()->in4_ifaddr.addr);
1253 else
1254 HOST2MSG32(ct->snd_msg->msg.ciaddr, IPV4_ADDRANY);
1255
1256 /* メッセージ長を設定する。*/
1257 ct->snd_msg->len = sizeof(ct->snd_msg->msg) - DHCP4_DFLT_OPT_LEN
1258 + (opt - (uint8_t*)&ct->snd_msg->msg.options);
1259 return E_OK;
1260 }
1261
1262/*
1263 * setup_discover_msg -- DISCOVER メッセージを作成する。
1264 */
1265
1266static ER
1267setup_discover_msg (T_DHCP4_CLI_CONTEXT *ct)
1268{
1269 uint8_t *opt;
1270
1271#if defined(DHCP4_CLI_CFG_REQUIRED_OLIST) || defined(DHCP4_CLI_CFG_REQUEST_OLIST)
1272 uint_t len = 0;
1273#endif
1274
1275 ct->xid = create_xid();
1276 if ((opt = setup_dhcp_com_msg(ct, DHCP4_REQUEST, DHCP4_MTYPE_DISCOVER)) == NULL)
1277 return E_PAR;
1278
1279#if defined(DHCP4_CLI_CFG_REQUIRED_OLIST) || defined(DHCP4_CLI_CFG_REQUEST_OLIST)
1280
1281 /* 追加のオプションを設定する。*/
1282
1283 *opt = DHCP4_OPT_REQ_PARAM;
1284 opt += 2;
1285
1286#if defined(DHCP4_CLI_CFG_REQUIRED_OLIST)
1287
1288 /* 要求オプションリストを設定する。*/
1289 if (sizeof(required_plist) > 0) {
1290 memcpy(opt, required_plist, sizeof(required_plist));
1291 opt += sizeof(required_plist);
1292 len += sizeof(required_plist);
1293 }
1294
1295#endif /* of #if defined(DHCP4_CLI_CFG_REQUIRED_OLIST) */
1296
1297#if defined(DHCP4_CLI_CFG_REQUEST_OLIST)
1298
1299 /* 要求オプションリストを設定する。*/
1300 if (sizeof(request_plist) > 0) {
1301 memcpy(opt, request_plist, sizeof(request_plist));
1302 opt += sizeof(request_plist);
1303 len += sizeof(request_plist);
1304 }
1305
1306#endif /* of #if defined(DHCP4_CLI_CFG_REQUEST_OLIST) */
1307
1308 *(opt - len - 1) = len;
1309
1310#endif /* of #if defined(DHCP4_CLI_CFG_REQUIRED_OLIST) || defined(DHCP4_CLI_CFG_REQUEST_OLIST) */
1311
1312 /* 既にアドレス情報がリースされていれば、同じ IP アドレスを要求する。*/
1313 if (ct->act_msg != NULL) {
1314 *(opt ++) = DHCP4_OPT_REQ_IPV4;
1315 *(opt ++) = sizeof(ct->act_msg->msg.yiaddr);
1316 memcpy(opt, (uint8_t*)&ct->act_msg->msg.yiaddr, sizeof(ct->act_msg->msg.yiaddr));
1317 opt += sizeof(ct->act_msg->msg.yiaddr);
1318 }
1319
1320 /* クライアント ID(MAC アドレス)を設定する。*/
1321 *(opt ++) = DHCP4_OPT_CLIENT_ID;
1322 *(opt ++) = ETHER_ADDR_LEN + 1;
1323 *(opt ++) = DHCP4_HWA_TYPE_ETHER;
1324 memcpy(opt, &ct->sc->ifaddr.lladdr, ETHER_ADDR_LEN);
1325 opt += ETHER_ADDR_LEN;
1326
1327 /* オプションの終了を設定する。*/
1328 *(opt ++) = DHCP4_OPT_END;
1329
1330 /* 送信先アドレスを設定する。*/
1331 ct->dst.ipaddr = IPV4_ADDRBROADCAST;
1332
1333 /* メッセージ長を設定する。*/
1334 ct->snd_msg->len = sizeof(ct->snd_msg->msg) - DHCP4_DFLT_OPT_LEN
1335 + (opt - (uint8_t*)&ct->snd_msg->msg.options);
1336 return E_OK;
1337 }
1338
1339/*
1340 * ack_msg_timeout -- ACK/NAK メッセージ受信タイムアウト処理
1341 */
1342
1343static void
1344ack_msg_timeout (T_DHCP4_CLI_CONTEXT *ct)
1345{
1346 /* ACK メッセージを受信していれば。BOUND 状態に遷移する。*/
1347 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1348 if (select_ack(ct)) {
1349
1350 /* REQUEST メッセージ送信タイマーを停止する。*/
1351 syscall(wai_sem(SEM_DHCP4_CLI_TIMER));
1352 ct->timers[DHCP4C_TIMER_SND_REQ] = 0;
1353 syscall(sig_sem(SEM_DHCP4_CLI_TIMER));
1354
1355 /*
1356 * 状態が REQUEST の時は、
1357 * OFFER メッセージを受信メッセージ構造体リストに戻す。
1358 */
1359 if (ct->fsm == DHCP4_FSM_REQUEST && ct->off_msg != NULL) {
1360 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
1361 ct->off_msg->next = ct->rcv_lst;
1362 ct->rcv_lst = ct->off_msg;
1363 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
1364 ct->off_msg = NULL;
1365 }
1366
1367 /* BOUND 状態に遷移する。*/
1368 start_bound(ct);
1369 return;
1370 }
1371 else {
1372
1373 /* リース情報を解放する。*/
1374 rel_lease(ct);
1375
1376 ct->error = E_TMOUT;
1377 }
1378 }
1379
1380/*
1381 * send_request_msg -- REQUEST メッセージを送信する。
1382 */
1383
1384static void
1385send_request_msg (T_DHCP4_CLI_CONTEXT *ct)
1386{
1387 T_DHCP4_CLI_MSG *ref;
1388 ER error;
1389 SYSTIM time;
1390 RELTIM interval;
1391 uint16_t secs;
1392
1393 /* タイムアウトフラグをクリアーする。*/
1394 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1395
1396 /* ACK メッセージを受信していれば。BOUND 状態に遷移する。*/
1397 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1398 if (select_ack(ct)) {
1399
1400 /* ACK/NAK メッセージ受信タイマーを停止する。*/
1401 syscall(wai_sem(SEM_DHCP4_CLI_TIMER));
1402 ct->timers[DHCP4C_TIMER_RCV_ACK] = 0;
1403 syscall(sig_sem(SEM_DHCP4_CLI_TIMER));
1404
1405 /*
1406 * 状態が REQUEST の時は、
1407 * OFFER メッセージを受信メッセージ構造体リストに戻す。
1408 */
1409 if (ct->fsm == DHCP4_FSM_REQUEST && ct->off_msg != NULL) {
1410 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
1411 ct->off_msg->next = ct->rcv_lst;
1412 ct->rcv_lst = ct->off_msg;
1413 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
1414 ct->off_msg = NULL;
1415 }
1416
1417 /* BOUND 状態に遷移する。*/
1418 start_bound(ct);
1419 return;
1420 }
1421
1422 /* REQUEST メッセージを作成する。*/
1423 if (ct->fsm == DHCP4_FSM_REQUEST)
1424 ref = ct->off_msg;
1425 else
1426 ref = ct->act_msg;
1427 if ((error = setup_request_msg(ct, ref)) != E_OK) {
1428 syslog(LOG_NOTICE, "[DHCP4C] error, setup request message: %s", itron_strerror(error));
1429 ct->error = error;
1430 return;
1431 }
1432
1433 /* 送信を開始してからの時間を得る。*/
1434 get_tim(&time);
1435 interval = time - ct->snd_start;
1436
1437 /*
1438 * 送信を開始してからの時間(秒)をメッセージに設定する。
1439 * 最大値は 65535。
1440 */
1441 if (ct->fsm == DHCP4_FSM_REQUEST)
1442 secs = ct->secs;
1443 else {
1444 if (SYSTIM2SEC(interval) < 65536)
1445 secs = SYSTIM2SEC(interval);
1446 else
1447 secs = 65535;
1448 }
1449 HOST2MSG16(ct->snd_msg->msg.secs, secs);
1450
1451 /* ノンブロッキングコールでメッセージを送信する。*/
1452 error = udp_snd_dat(ct->cepid, &ct->dst, &ct->snd_msg->msg, ct->snd_msg->len, TMO_NBLK);
1453 if (error != E_WBLK) {
1454 syslog(LOG_NOTICE, "[DHCP4C] error, send request message: %s", itron_strerror(error));
1455 ct->error = error;
1456 return;
1457 }
1458
1459 /* 送信間隔を設定する。*/
1460 if (ct->interval == 0)
1461 /* 未設定 */
1462 ct->interval = TMO_DHCP4C_INIT_INTVL;
1463 else
1464 /* バックオフアルゴリズムで 2倍にした(乱数使用)送信間隔を加算する。*/
1465 ct->interval += (netapp_rand() >> 2) % (ct->interval << 1);
1466
1467 /* 送信周期の制限値を超えないようにする。*/
1468 if (ct->interval > TMO_DHCP4C_MAX_BACKOFF)
1469 ct->interval = (TMO_DHCP4C_MAX_BACKOFF >> 1) + ((netapp_rand() >> 2) % TMO_DHCP4C_MAX_BACKOFF);
1470
1471 /* リース時間のタイムアウト【先送り】 */
1472 if (ct->fsm != DHCP4_FSM_REQUEST &&
1473 TIMEC_GT(ct->interval + time, ct->expire + ct->bind_start))
1474 ct->interval = ct->expire + ct->bind_start - time + SYSTIM_HZ;
1475
1476 /* 再送信タイムアウトを設定する。*/
1477 syscall(wai_sem(SEM_DHCP4_CLI_TIMER));
1478 ct->timers[DHCP4C_TIMER_SND_REQ] = SYSTIM2TIMER(ct->interval);
1479 syscall(sig_sem(SEM_DHCP4_CLI_TIMER));
1480 }
1481
1482/*
1483 * send_release_msg -- RELEASE メッセージを送信する。
1484 */
1485
1486static void
1487send_release_msg (T_DHCP4_CLI_CONTEXT *ct)
1488{
1489 ER error;
1490
1491 /* タイムアウトフラグをクリアーする。*/
1492 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1493
1494 /* RELEASE メッセージを作成する。*/
1495 if ((error = setup_release_msg(ct, ct->act_msg)) != E_OK) {
1496 syslog(LOG_NOTICE, "[DHCP4C] error, setup release message: %s", itron_strerror(error));
1497 ct->error = error;
1498 return;
1499 }
1500
1501 /* リース情報を解放する。*/
1502 rel_lease(ct);
1503
1504 /* ノンブロッキングコールでメッセージを送信する。*/
1505 error = udp_snd_dat(ct->cepid, &ct->dst, &ct->snd_msg->msg, ct->snd_msg->len, TMO_NBLK);
1506 if (error != E_WBLK) {
1507 syslog(LOG_NOTICE, "[DHCP4C] error, send release message: %s", itron_strerror(error));
1508 ct->error = error;
1509 return;
1510 }
1511
1512 /* メッセージ送信待ちを行う。*/
1513 syscall(wai_sem(SEM_DHCP4_CLI_READY));
1514
1515 /* SLEEP 状態に遷移する。*/
1516 ct->fsm = DHCP4_FSM_SLEEP;
1517 }
1518
1519/*
1520 * offer_msg_timeout -- OFFER メッセージ受信タイムアウト処理
1521 */
1522
1523static void
1524offer_msg_timeout (T_DHCP4_CLI_CONTEXT *ct)
1525{
1526 /* OFFER メッセージを受信していれば。REQUEST 状態に遷移する。*/
1527 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1528 if (select_offer(ct)) {
1529
1530 /* DISCOVER メッセージ送信タイマーを停止する。*/
1531 syscall(wai_sem(SEM_DHCP4_CLI_TIMER));
1532 ct->timers[DHCP4C_TIMER_SND_DISC] = 0;
1533 syscall(sig_sem(SEM_DHCP4_CLI_TIMER));
1534
1535 /* REQUEST メッセージを送信して REQUEST 状態に遷移する。*/
1536 start_send_request(ct, DHCP4_FSM_REQUEST);
1537 }
1538 else
1539 ct->error = E_TMOUT;
1540 }
1541
1542/*
1543 * send_discover_msg -- DISCOVERメッセージを送信する。
1544 */
1545
1546static void
1547send_discover_msg (T_DHCP4_CLI_CONTEXT *ct)
1548{
1549 ER error;
1550 SYSTIM time;
1551 RELTIM interval;
1552
1553 /* タイムアウトフラグをクリアーする。*/
1554 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1555
1556 /* OFFER メッセージを受信していれば。REQUEST 状態に遷移する。*/
1557 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1558 if (select_offer(ct)) {
1559
1560 /* OFFER メッセージ受信タイマーを停止する。*/
1561 syscall(wai_sem(SEM_DHCP4_CLI_TIMER));
1562 ct->timers[DHCP4C_TIMER_RCV_OFFER] = 0;
1563 syscall(sig_sem(SEM_DHCP4_CLI_TIMER));
1564
1565 /* REQUEST メッセージを送信して REQUEST 状態に遷移する。*/
1566 start_send_request(ct, DHCP4_FSM_REQUEST);
1567 return;
1568 }
1569
1570 /* DISCOVER メッセージを作成する。*/
1571 if ((error = setup_discover_msg(ct)) != E_OK) {
1572 syslog(LOG_NOTICE, "[DHCP4C] error, setup discover message: %s", itron_strerror(error));
1573 ct->error = error;
1574 return;
1575 }
1576
1577 /* 送信を開始してからの時間を得る。*/
1578 get_tim(&time);
1579 interval = time - ct->snd_start;
1580
1581 /*
1582 * 送信を開始してからの時間(秒)をメッセージに設定する。
1583 * 最大値は 65535。
1584 */
1585 if (SYSTIM2SEC(interval) < 65536)
1586 ct->secs = SYSTIM2SEC(interval);
1587 else
1588 ct->secs = 65535;
1589 HOST2MSG16(ct->snd_msg->msg.secs, ct->secs);
1590
1591 /* ノンブロッキングコールでメッセージを送信する。*/
1592 error = udp_snd_dat(ct->cepid, &ct->dst, &ct->snd_msg->msg, ct->snd_msg->len, TMO_NBLK);
1593 if (error != E_WBLK) {
1594 syslog(LOG_NOTICE, "[DHCP4C] error, send discover message: %s", itron_strerror(error));
1595 ct->error = error;
1596 return;
1597 }
1598
1599 /* 送信間隔を設定する。*/
1600 if (ct->interval == 0)
1601 /* 未設定 */
1602 ct->interval = TMO_DHCP4C_INIT_INTVL;
1603 else
1604 /* バックオフアルゴリズムで 2倍にした(乱数使用)送信間隔を加算する。*/
1605 ct->interval += (netapp_rand() >> 2) % (ct->interval << 1);
1606
1607 /* 送信周期の制限値を超えないようにする。*/
1608 if (ct->interval > TMO_DHCP4C_MAX_BACKOFF)
1609 ct->interval = (TMO_DHCP4C_MAX_BACKOFF >> 1) + ((netapp_rand() >> 2) % TMO_DHCP4C_MAX_BACKOFF);
1610
1611 /* OFFER メッセージの受信タイムアウトを超えないように調整する。*/
1612 if (TIMEC_GT(time + ct->interval, ct->snd_start + TMO_DHCP4C_OFFER))
1613 ct->interval = (TMO_DHCP4C_INIT_INTVL + TMO_DHCP4C_OFFER) - time + 1;
1614
1615 /* 再送信タイムアウトを設定する。*/
1616 syscall(wai_sem(SEM_DHCP4_CLI_TIMER));
1617 ct->timers[DHCP4C_TIMER_SND_DISC] = SYSTIM2TIMER(ct->interval);
1618 syscall(sig_sem(SEM_DHCP4_CLI_TIMER));
1619 }
1620
1621/*
1622 * dhcpc_timer -- TIMER 管理
1623 */
1624
1625static void
1626dhcpc_timer (T_DHCP4_CLI_CONTEXT *ct)
1627{
1628 int ix;
1629
1630 syscall(wai_sem(SEM_DHCP4_CLI_TIMER));
1631 for (ix = NUM_DHCP4C_TIMERS; ix -- > 0; ) {
1632 if (ct->timers[ix] != 0) {
1633 ct->timers[ix] --;
1634 if (ct->timers[ix] == 0) {
1635 ct->flags = (ct->flags & ~DHCP4C_FLAG_TMOUT_MASK) | DHCP4C_FLAG_TMOUT_TIMER | ix;
1636 syscall(sig_sem(SEM_DHCP4_CLI_READY));
1637 }
1638 }
1639 }
1640 syscall(sig_sem(SEM_DHCP4_CLI_TIMER));
1641
1642 /* 1秒毎にタイムアウトする。*/
1643 timeout((callout_func)dhcpc_timer, ct, NET_TIMER_HZ);
1644 }
1645
1646/*
1647 * expire_timeout -- EXPIRE タイムアウト処理
1648 */
1649
1650static void
1651expire_timeout (T_DHCP4_CLI_CONTEXT *ct)
1652{
1653 //ER error;
1654
1655 /* タイムアウトフラグをクリアーする。*/
1656 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1657
1658 /* 状態が REQUEST の時は何もしない。*/
1659 if (ct->fsm == DHCP4_FSM_REQUEST)
1660 return;
1661
1662 /* 全ての TIMER をキャンセルする。*/
1663 cancel_all_timers(ct);
1664
1665 /* リースされた情報を解放する。*/
1666 rel_lease(ct);
1667
1668 ct->error = E_TMOUT;
1669 }
1670
1671/*
1672 * rebind_timeout -- REBIND タイムアウト処理
1673 */
1674
1675static void
1676rebind_timeout (T_DHCP4_CLI_CONTEXT *ct)
1677{
1678 /* タイムアウトフラグをクリアーする。*/
1679 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1680
1681 /* 全ての TIMER をキャンセルする。*/
1682 cancel_all_timers(ct);
1683
1684 /* REQUEST メッセージを送信して REBIND 状態に遷移する。*/
1685 start_send_request(ct, DHCP4_FSM_REBIND);
1686 }
1687
1688/*
1689 * renew_timeout -- RENEW タイムアウト処理
1690 */
1691
1692static void
1693renew_timeout (T_DHCP4_CLI_CONTEXT *ct)
1694{
1695 /* タイムアウトフラグをクリアーする。*/
1696 ct->flags &= ~DHCP4C_FLAG_TMOUT_MASK;
1697
1698 /* REQUEST メッセージを送信して RENEW 状態に遷移する。*/
1699 start_send_request(ct, DHCP4_FSM_RENEW);
1700 }
1701
1702/*
1703 * dispatch_timeout -- タイムアウトした時の処理
1704 */
1705
1706static ER
1707dispatch_timeout (T_DHCP4_CLI_CONTEXT *ct)
1708{
1709 switch (ct->flags & DHCP4C_FLAG_TMOUT_TIMER_MASK) {
1710
1711 case DHCP4C_TIMER_SND_DISC:
1712 send_discover_msg(ct);
1713 break;
1714
1715 case DHCP4C_TIMER_SND_REQ:
1716 send_request_msg(ct);
1717 break;
1718
1719 case DHCP4C_TIMER_RCV_OFFER:
1720 offer_msg_timeout(ct);
1721 break;
1722
1723 case DHCP4C_TIMER_RCV_ACK:
1724 ack_msg_timeout(ct);
1725 break;
1726
1727 case DHCP4C_TIMER_RENEW:
1728 renew_timeout(ct);
1729 break;
1730
1731 case DHCP4C_TIMER_REBIND:
1732 rebind_timeout(ct);
1733 break;
1734
1735 case DHCP4C_TIMER_EXPIRE:
1736 expire_timeout(ct);
1737 break;
1738
1739 case DHCP4C_TIMER_SND_REL:
1740 send_release_msg(ct);
1741 break;
1742
1743 default:
1744 break;
1745 }
1746
1747 return ct->error;
1748 }
1749
1750/*
1751 * dispatch_event -- イベント毎の処理
1752 */
1753
1754static ER
1755dispatch_event (T_DHCP4_CLI_CONTEXT *ct)
1756{
1757 ER error = E_OK;
1758
1759 while (ct->fsm != DHCP4_FSM_SLEEP && error == E_OK) {
1760
1761 /* メッセージの受信とタイムアウトを待つ。*/
1762 syscall(wai_sem(SEM_DHCP4_CLI_READY));
1763
1764 if (ct->flags & DHCP4C_FLAG_RCV_MSG) {
1765 while (ct->val_lst != NULL) {
1766 error = eval_rcv_msg(ct);
1767 }
1768 ct->flags &= ~DHCP4C_FLAG_RCV_MSG;
1769 }
1770 if (ct->flags & DHCP4C_FLAG_TMOUT_MASK)
1771 error = dispatch_timeout(ct);
1772
1773 if (ct->error != E_OK)
1774 error = ct->error;
1775 }
1776
1777 return error;
1778 }
1779
1780/*
1781 * init_context -- DHCP クライアントコンテキスト構造体を初期化する。
1782 */
1783
1784static void
1785init_context (T_DHCP4_CLI_CONTEXT *ct, ID cepid)
1786{
1787 memset(ct, 0, sizeof(*ct));
1788 ct->cepid = cepid;
1789 ct->sc = IF_ETHER_NIC_GET_SOFTC();
1790 ct->dst.portno = DHCP4_SRV_CFG_PORTNO;
1791 ct->dst.ipaddr = IPV4_ADDRANY;
1792 }
1793
1794/*
1795 * rel_cli_msg -- メッセージ構造体を解放する。
1796 */
1797
1798static void
1799rel_cli_msg (T_DHCP4_CLI_CONTEXT *ct)
1800{
1801 T_DHCP4_CLI_MSG *ptr, *cell;
1802
1803 for (ptr = ct->rcv_lst; ptr != NULL; ) {
1804 cell = ptr;
1805 ptr = ptr->next;
1806 syscall(rel_mpf(MPF_DHCP4_CLI_MSG, (void*)cell));
1807 }
1808
1809 for (ptr = ct->val_lst; ptr != NULL; ) {
1810 cell = ptr;
1811 ptr = ptr->next;
1812 syscall(rel_mpf(MPF_DHCP4_CLI_MSG, (void*)cell));
1813 }
1814
1815 for (ptr = ct->prf_lst; ptr != NULL; ) {
1816 cell = ptr;
1817 ptr = ptr->next;
1818 syscall(rel_mpf(MPF_DHCP4_CLI_MSG, (void*)cell));
1819 }
1820
1821 if (ct->snd_msg != NULL)
1822 syscall(rel_mpf(MPF_DHCP4_CLI_MSG, (void*)ct->snd_msg));
1823 ct->rcv_lst = ct->prf_lst = ct->val_lst = ct->snd_msg = NULL;
1824 }
1825
1826/*
1827 * init_cli_msg -- 各メッセージ構造体を初期化する。
1828 */
1829
1830static ER
1831init_cli_msg (T_DHCP4_CLI_CONTEXT *ct)
1832{
1833 T_DHCP4_CLI_MSG *cell;
1834 ER error;
1835 int count;
1836
1837 /* 送信メッセージ構造体を獲得する。*/
1838 if ((error = tget_mpf(MPF_DHCP4_CLI_MSG, (void*)&ct->snd_msg, TMO_DHCP4C_MPF_GET)) != E_OK) {
1839 syslog(LOG_NOTICE, "[DHCP4C] error, tget_mpf() for send: %s.", itron_strerror(error));
1840 return error;
1841 }
1842
1843 /*
1844 * 有効なリース・メッセージ構造体がある場合は、
1845 * 獲得する受信メッセージ構造体リストの構造体を 1減らす。
1846 */
1847 if (ct->act_msg == NULL)
1848 count = NUM_DHCP4_MSG_LIST;
1849 else
1850 count = NUM_DHCP4_MSG_LIST - 1;
1851
1852 /* 受信メッセージ構造体を獲得する。*/
1853 while (count --> 0) {
1854 if ((error = tget_mpf(MPF_DHCP4_CLI_MSG, (void*)&cell, TMO_DHCP4C_MPF_GET)) != E_OK) {
1855 syslog(LOG_NOTICE, "[DHCP4C] error, tget_mpf() for receive: %s.", itron_strerror(error));
1856 break;
1857 }
1858 cell->next = ct->rcv_lst;
1859 ct->rcv_lst = cell;
1860 }
1861
1862 return E_OK;
1863 }
1864
1865/*
1866 * dhcp4c_renew_info -- ネットワーク情報を再取得する。
1867 */
1868
1869ER
1870dhcp4c_renew_info (void)
1871{
1872 if (context.fsm == DHCP4_FSM_BOUND) {
1873
1874 /* REL_INFO 状態に遷移した後に SLEEP を解除するように設定する。*/
1875 context.flags |= DHCP4C_FLAG_RENEW;
1876 start_rel_info(&context);
1877 return E_OK;
1878 }
1879 else if (context.fsm == DHCP4_FSM_SLEEP) {
1880
1881 /* SLEEP を解除する。*/
1882 wup_tsk(DHCP4_CLI_TASK);
1883 return E_OK;
1884 }
1885 else
1886 return E_OBJ;
1887 }
1888
1889/*
1890 * dhcp4c_rel_info -- DHCP で設定されたネットワーク情報を解放する。
1891 */
1892
1893ER
1894dhcp4c_rel_info (void)
1895{
1896 /* REL_INFO 状態に遷移する。*/
1897 start_rel_info(&context);
1898 return E_OK;
1899 }
1900
1901/*
1902 * dhcp4c_get_info -- DHCP で設定されたネットワーク情報を返す。
1903 */
1904
1905ER
1906dhcp4c_get_info (T_IN4_ADDR *addr, uint32_t *expire, uint32_t *renew,
1907 uint32_t *rebind, SYSTIM *bind_start)
1908{
1909 if (addr == NULL || expire == NULL ||
1910 renew == NULL || rebind == NULL || bind_start == NULL)
1911 return E_PAR;
1912 else if (context.act_msg == NULL)
1913 return E_OBJ;
1914 else {
1915 *addr = context.act_msg->srv.ipaddr;
1916 *expire = context.timers[DHCP4C_TIMER_EXPIRE];
1917 *renew = context.timers[DHCP4C_TIMER_RENEW];
1918 *rebind = context.timers[DHCP4C_TIMER_REBIND];
1919 *bind_start = context.bind_start;
1920 return E_OK;
1921 }
1922 }
1923
1924/*
1925 * コールバック関数
1926 */
1927
1928ER
1929callback_nblk_dhcp4_cli (ID cepid, FN fncd, void *p_parblk)
1930{
1931 T_DHCP4_CLI_MSG *msg;
1932 ER_UINT len;
1933
1934 len = *(ER_UINT*)p_parblk;
1935 if (len < 0 && len != E_RLWAI) {
1936 /* E_RLWAI 以外で、0 以下の場合は、エラーを意味している。*/
1937 syslog(LOG_NOTICE, "[DHCPC(CBR)] error: %s, fncd: %s", itron_strerror(len), in_strtfn(fncd));
1938 }
1939 else {
1940 if (fncd == TEV_UDP_RCV_DAT) {
1941
1942 /* 受信メッセージリストが空の時は、受信しないでデータグラムを捨てる。*/
1943 if (context.rcv_lst == NULL)
1944 syslog(LOG_NOTICE, "[DHCP4C(CBR)] receive buffer all busy.");
1945 else {
1946 /* メッセージを受信するメッセージ構造体を準備する。*/
1947 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
1948 msg = context.rcv_lst;
1949 context.rcv_lst = context.rcv_lst->next;
1950 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
1951
1952 /* メッセージを受信する。*/
1953 len = udp_rcv_dat(context.cepid, &msg->srv, &msg->msg, sizeof(msg->msg), TMO_POL);
1954
1955 syscall(wai_sem(SEM_DHCP4_CLI_LOCK));
1956 msg->len = len;
1957 if (len >= 0) {
1958 /* 受信したメッセージを検証メッセージリストに移す。*/
1959 msg->next = context.val_lst;
1960 context.val_lst = msg;
1961 context.flags |= DHCP4C_FLAG_RCV_MSG;
1962 }
1963 else {
1964 /* メッセージ構造体を受信メッセージリストに戻す。*/
1965 context.error = len;
1966 msg->next = context.rcv_lst;
1967 context.rcv_lst = msg;
1968 }
1969 syscall(sig_sem(SEM_DHCP4_CLI_LOCK));
1970 }
1971 }
1972 syscall(sig_sem(SEM_DHCP4_CLI_READY));
1973 }
1974 return E_OK;
1975 }
1976
1977/*
1978 * dhcp4_cli_task -- DHCP クライアントタスク
1979 */
1980
1981void
1982dhcp4_cli_task (intptr_t exinf)
1983{
1984 T_DHCP4_CLI_CONTEXT *ct;
1985 ID tskid;
1986 ER error = E_OK;
1987
1988 dly_tsk(1000);
1989 get_tid(&tskid);
1990 syslog(LOG_NOTICE, "[DHCP4C:%d,%d] started.", tskid, (ID)exinf);
1991 dly_tsk(500);
1992 ct = &context;
1993
1994 /* DHCP クライアントコンテキスト構造体を初期化する。*/
1995 init_context(ct, (ID)exinf);
1996 ct->fsm = DHCP4_FSM_SLEEP;
1997
1998 while (true) {
1999
2000 /* リースを解放後、再取得が指定されていなければ休止する。*/
2001 if (!(ct->flags & DHCP4C_FLAG_RENEW)) {
2002
2003 /* 休止する。*/
2004 if (error == E_OK)
2005 syslog(LOG_NOTICE, "[DHCP4C] lease released, go to sleep.");
2006 else {
2007 syslog(LOG_NOTICE, "[DHCP4C] server not available, go to sleep, error: %s.", itron_strerror(error));
2008 ct->fsm = DHCP4_FSM_SLEEP;
2009 }
2010 slp_tsk();
2011 }
2012 ct->flags = 0;
2013 ct->error = E_OK;
2014
2015 /* 1秒毎にタイムアウトするようにタイマーを設定する。*/
2016 timeout((callout_func)dhcpc_timer, ct, NET_TIMER_HZ / DHCP4C_TIMER_HZ);
2017
2018 /* メッセージ構造体を初期化する。*/
2019 if ((error = init_cli_msg(ct)) == E_OK) {
2020
2021 /* SELECT 状態に遷移する。*/
2022 start_select(ct);
2023
2024 /* メインループ */
2025 error = dispatch_event(ct);
2026 }
2027
2028 /* 全ての TIMER をキャンセルする。*/
2029 cancel_all_timers(ct);
2030
2031 /* タイマーを停止する。*/
2032 untimeout((callout_func)dhcpc_timer, ct);
2033
2034 /* メッセージ構造体を解放する。*/
2035 rel_cli_msg (ct);
2036 }
2037 }
2038
2039#endif /* of #ifdef DHCP4_CLI_CFG */
Note: See TracBrowser for help on using the repository browser.