usbmodeswitch: Updated to v.1.2.6 from shibby's branch.
[tomato.git] / release / src / router / dhcpv6 / dhcp6c_ia.c
blob6877c2052c2d19ee0054a8349ed7a84ee47b5188
1 /* $KAME: dhcp6c_ia.c,v 1.33 2005/07/22 08:50:05 jinmei Exp $ */
3 /*
4 * Copyright (C) 2003 WIDE Project.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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 project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
31 #include <sys/types.h>
32 #include <sys/queue.h>
33 #include <sys/socket.h>
34 #include <sys/time.h>
36 #include <netinet/in.h>
38 #include <syslog.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
43 #include "dhcp6.h"
44 #include "config.h"
45 #include "common.h"
46 #include "timer.h"
47 #include "dhcp6c.h"
48 #include "dhcp6c_ia.h"
49 #include "prefixconf.h"
50 #include "addrconf.h"
52 typedef enum {IAS_ACTIVE, IAS_RENEW, IAS_REBIND} iastate_t;
54 struct ia {
55 TAILQ_ENTRY(ia) link;
57 /* back pointer to configuration */
58 struct ia_conf *conf;
60 /* common parameters of IA */
61 u_int32_t t1; /* duration for renewal */
62 u_int32_t t2; /* duration for rebind */
64 /* internal parameters for renewal/rebinding */
65 iastate_t state;
66 struct dhcp6_timer *timer;
67 struct dhcp6_eventdata *evdata;
69 /* DHCP related parameters */
70 struct dhcp6_if *ifp; /* DHCP interface */
71 struct duid serverid; /* the server ID that provided this IA */
73 /* control information shared with each particular config routine */
74 struct iactl *ctl;
76 /* authentication parameters for transaction with servers on this IA */
77 struct authparam *authparam;
80 static int update_authparam __P((struct ia *, struct authparam *));
81 static void reestablish_ia __P((struct ia *));
82 static void callback __P((struct ia *));
83 static int release_ia __P((struct ia *));
84 static void remove_ia __P((struct ia *));
85 static struct ia *get_ia __P((iatype_t, struct dhcp6_if *, struct ia_conf *,
86 struct dhcp6_listval *, struct duid *));
87 static struct ia *find_ia __P((struct ia_conf *, iatype_t, u_int32_t));
88 static struct dhcp6_timer *ia_timo __P((void *));
90 static char *iastr __P((iatype_t));
91 static char *statestr __P((iastate_t));
93 void
94 update_ia(iatype, ialist, ifp, serverid, authparam)
95 iatype_t iatype;
96 struct dhcp6_list *ialist;
97 struct dhcp6_if *ifp;
98 struct duid *serverid;
99 struct authparam *authparam;
101 struct ia *ia;
102 struct ia_conf *iac;
103 struct iapd_conf *iapdc;
104 struct iana_conf *ianac;
105 struct dhcp6_listval *iav, *siav;
106 struct timeval timo;
108 for (iav = TAILQ_FIRST(ialist); iav; iav = TAILQ_NEXT(iav, link)) {
109 /* if we're not interested in this IA, ignore it. */
110 if ((iac = find_iaconf(&ifp->iaconf_list, iatype,
111 iav->val_ia.iaid)) == NULL) {
112 continue;
115 /* validate parameters */
117 * If a client receives an IA_NA with T1 greater than T2, and
118 * both T1 and T2 are greater than 0, the client discards the
119 * IA_NA option and processes the remainder of the message as
120 * though the server had not included the invalid IA_NA option.
121 * [RFC3315 22.4]
122 * We apply the same rule to IA_PD as well.
124 if (iav->val_ia.t2 != 0 && iav->val_ia.t1 > iav->val_ia.t2) {
125 dprintf(LOG_INFO, FNAME,
126 "invalid IA: T1(%lu) > T2(%lu)",
127 iav->val_ia.t1, iav->val_ia.t2);
128 continue;
131 /* locate the local IA or make a new one */
132 ia = get_ia(iatype, ifp, iac, iav, serverid);
133 if (ia == NULL) {
134 dprintf(LOG_WARNING, FNAME, "failed to get an IA "
135 "type: %s, ID: %u", iastr(iac->type), iac->iaid);
136 continue;
139 /* update authentication parameters */
140 if (update_authparam(ia, authparam)) {
141 dprintf(LOG_WARNING, FNAME, "failed to update "
142 "authentication param for IA "
143 "type: %s, ID: %u", iastr(iac->type), iac->iaid);
144 remove_ia(ia);
145 continue;
148 /* update IA configuration information */
149 for (siav = TAILQ_FIRST(&iav->sublist); siav;
150 siav = TAILQ_NEXT(siav, link)) {
151 switch (siav->type) {
152 case DHCP6_LISTVAL_PREFIX6:
153 /* add or update the prefix */
154 iapdc = (struct iapd_conf *)iac;
155 if (update_prefix(ia, &siav->val_prefix6,
156 &iapdc->iapd_pif_list, ifp, &ia->ctl,
157 callback)) {
158 dprintf(LOG_NOTICE, FNAME,
159 "failed to update a prefix %s/%d",
160 in6addr2str(&siav->val_prefix6.addr, 0),
161 siav->val_prefix6.plen);
163 break;
164 case DHCP6_LISTVAL_STATEFULADDR6:
165 ianac = (struct iana_conf *)iac;
166 if (update_address(ia, &siav->val_statefuladdr6,
167 ifp, &ia->ctl, callback)) {
168 dprintf(LOG_NOTICE, FNAME,
169 "failed to update an address %s",
170 in6addr2str(&siav->val_statefuladdr6.addr, 0));
172 break;
173 case DHCP6_LISTVAL_STCODE:
174 dprintf(LOG_INFO, FNAME,
175 "status code for %s-%lu: %s",
176 iastr(iatype), iav->val_ia.iaid,
177 dhcp6_stcodestr(siav->val_num16));
178 if ((ia->state == IAS_RENEW ||
179 ia->state == IAS_REBIND) &&
180 siav->val_num16 == DH6OPT_STCODE_NOBINDING) {
182 * For each IA in the original Renew or
183 * Rebind message, the client
184 * sends a Request message if the IA
185 * contained a Status Code option
186 * with the NoBinding status.
187 * [RFC3315 18.1.8]
188 * XXX: what about the PD case?
190 dprintf(LOG_INFO, FNAME,
191 "receive NoBinding against "
192 "renew/rebind for %s-%lu",
193 iastr(ia->conf->type),
194 ia->conf->iaid);
195 reestablish_ia(ia);
196 goto nextia;
198 break;
199 default:
200 dprintf(LOG_ERR, FNAME, "impossible case");
201 goto nextia;
205 /* see if this IA is still valid. if not, remove it. */
206 if (ia->ctl == NULL || !(*ia->ctl->isvalid)(ia->ctl)) {
207 dprintf(LOG_DEBUG, FNAME, "IA %s-%lu is invalidated",
208 iastr(ia->conf->type), ia->conf->iaid);
209 remove_ia(ia);
210 continue;
213 /* if T1 or T2 is 0, determine appropriate values locally. */
214 if (ia->t1 == 0 || ia->t2 == 0) {
215 u_int32_t duration;
217 if (ia->ctl && ia->ctl->duration)
218 duration = (*ia->ctl->duration)(ia->ctl);
219 else
220 duration = 1800; /* 30min. XXX: no rationale */
222 if (ia->t1 == 0) {
223 if (duration == DHCP6_DURATION_INFINITE)
224 ia->t1 = DHCP6_DURATION_INFINITE;
225 else
226 ia->t1 = duration / 2;
228 if (ia->t2 == 0) {
229 if (duration == DHCP6_DURATION_INFINITE)
230 ia->t2 = DHCP6_DURATION_INFINITE;
231 else
232 ia->t2 = duration * 4 / 5;
235 /* make sure T1 <= T2 */
236 if (ia->t1 > ia->t2)
237 ia->t1 = ia->t2 * 5 / 8;
239 dprintf(LOG_INFO, FNAME, "T1(%lu) and/or T2(%lu) "
240 "is locally determined", ia->t1, ia->t2);
244 * Be proactive for too-small timeout values. Note that
245 * the adjusted values may make some information expire
246 * without renewal.
248 if (ia->t2 < DHCP6_DURATION_MIN) {
249 dprintf(LOG_INFO, FNAME, "T1 (%lu) or T2 (%lu) "
250 "is too small", ia->t1, ia->t2);
251 ia->t2 = DHCP6_DURATION_MIN;
252 ia->t1 = ia->t2 * 5 / 8;
253 dprintf(LOG_INFO, "", " adjusted to %lu and %lu",
254 ia->t1, ia->t2);
257 /* set up a timer for this IA. */
258 if (ia->t1 == DHCP6_DURATION_INFINITE) {
259 if (ia->timer)
260 dhcp6_remove_timer(&ia->timer);
261 } else {
262 if (ia->timer == NULL)
263 ia->timer = dhcp6_add_timer(ia_timo, ia);
264 if (ia->timer == NULL) {
265 dprintf(LOG_ERR, FNAME,
266 "failed to add IA timer");
267 remove_ia(ia); /* XXX */
268 continue;
270 timo.tv_sec = ia->t1;
271 timo.tv_usec = 0;
272 dhcp6_set_timer(&timo, ia->timer);
275 ia->state = IAS_ACTIVE;
277 nextia:
282 static int
283 update_authparam(ia, authparam)
284 struct ia *ia;
285 struct authparam *authparam;
287 if (authparam == NULL)
288 return (0);
290 if (ia->authparam == NULL) {
291 if ((ia->authparam = copy_authparam(authparam)) == NULL) {
292 dprintf(LOG_WARNING, FNAME,
293 "failed to copy authparam");
294 return (-1);
296 return (0);
299 /* update the previous RD value and flags */
300 ia->authparam->prevrd = authparam->prevrd;
301 ia->authparam->flags = authparam->flags;
303 return (0);
306 static void
307 reestablish_ia(ia)
308 struct ia *ia;
310 struct dhcp6_ia iaparam;
311 struct dhcp6_event *ev;
312 struct dhcp6_eventdata *evd;
314 dprintf(LOG_DEBUG, FNAME, "re-establishing IA: %s-%lu",
315 iastr(ia->conf->type), ia->conf->iaid);
317 if (ia->state != IAS_RENEW && ia->state != IAS_REBIND) {
318 dprintf(LOG_ERR, FNAME, "internal error (invalid IA status)");
319 exit(1); /* XXX */
322 /* cancel the current event for the prefix. */
323 if (ia->evdata) {
324 TAILQ_REMOVE(&ia->evdata->event->data_list, ia->evdata, link);
325 if (ia->evdata->destructor)
326 ia->evdata->destructor(ia->evdata);
327 free(ia->evdata);
328 ia->evdata = NULL;
331 /* we don't need a timer for the IA (see comments in ia_timo()) */
332 if (ia->timer)
333 dhcp6_remove_timer(&ia->timer);
335 if ((ev = dhcp6_create_event(ia->ifp, DHCP6S_REQUEST)) == NULL) {
336 dprintf(LOG_NOTICE, FNAME, "failed to create a new event");
337 goto fail;
339 TAILQ_INSERT_TAIL(&ia->ifp->event_list, ev, link);
341 if ((ev->timer = dhcp6_add_timer(client6_timo, ev)) == NULL) {
342 dprintf(LOG_NOTICE, FNAME,
343 "failed to create a new event timer");
344 goto fail;
347 if ((evd = malloc(sizeof(*evd))) == NULL) {
348 dprintf(LOG_NOTICE, FNAME,
349 "failed to create a new event data");
350 goto fail;
352 memset(evd, 0, sizeof(*evd));
353 evd->event = ev;
354 TAILQ_INSERT_TAIL(&ev->data_list, evd, link);
356 if (duidcpy(&ev->serverid, &ia->serverid)) {
357 dprintf(LOG_NOTICE, FNAME, "failed to copy server ID");
358 goto fail;
361 iaparam.iaid = ia->conf->iaid;
362 iaparam.t1 = ia->t1;
363 iaparam.t2 = ia->t2;
365 if (ia->ctl && ia->ctl->reestablish_data) {
366 if ((*ia->ctl->reestablish_data)(ia->ctl, &iaparam,
367 &ia->evdata, evd)) {
368 dprintf(LOG_NOTICE, FNAME,
369 "failed to make reestablish data");
370 goto fail;
374 if (ia->authparam != NULL) {
375 if ((ev->authparam = copy_authparam(ia->authparam)) == NULL) {
376 dprintf(LOG_WARNING, FNAME,
377 "failed to copy authparam");
378 goto fail;
382 ev->timeouts = 0;
383 dhcp6_set_timeoparam(ev);
384 dhcp6_reset_timer(ev);
386 ia->evdata = evd;
388 client6_send(ev);
390 return;
392 fail:
393 if (ev)
394 dhcp6_remove_event(ev);
396 return;
399 static void
400 callback(ia)
401 struct ia *ia;
403 /* see if this IA is still valid. if not, remove it. */
404 if (ia->ctl == NULL || !(*ia->ctl->isvalid)(ia->ctl)) {
405 dprintf(LOG_DEBUG, FNAME, "IA %s-%lu is invalidated",
406 iastr(ia->conf->type), ia->conf->iaid);
407 remove_ia(ia);
411 void
412 release_all_ia(ifp)
413 struct dhcp6_if *ifp;
415 struct ia_conf *iac;
416 struct ia *ia, *ia_next;
418 for (iac = TAILQ_FIRST(&ifp->iaconf_list); iac;
419 iac = TAILQ_NEXT(iac, link)) {
420 for (ia = TAILQ_FIRST(&iac->iadata); ia; ia = ia_next) {
421 ia_next = TAILQ_NEXT(ia, link);
423 (void)release_ia(ia);
426 * The client MUST stop using all of the addresses
427 * being released as soon as the client begins the
428 * Release message exchange process.
429 * [RFC3315 Section 18.1.6]
431 remove_ia(ia);
436 static int
437 release_ia(ia)
438 struct ia *ia;
440 struct dhcp6_ia iaparam;
441 struct dhcp6_event *ev;
442 struct dhcp6_eventdata *evd;
444 dprintf(LOG_DEBUG, FNAME, "release an IA: %s-%lu",
445 iastr(ia->conf->type), ia->conf->iaid);
447 if ((ev = dhcp6_create_event(ia->ifp, DHCP6S_RELEASE))
448 == NULL) {
449 dprintf(LOG_NOTICE, FNAME, "failed to create a new event");
450 goto fail;
452 TAILQ_INSERT_TAIL(&ia->ifp->event_list, ev, link);
455 if ((ev->timer = dhcp6_add_timer(client6_timo, ev)) == NULL) {
456 dprintf(LOG_NOTICE, FNAME,
457 "failed to create a new event timer");
458 goto fail;
461 if (duidcpy(&ev->serverid, &ia->serverid)) {
462 dprintf(LOG_NOTICE, FNAME, "failed to copy server ID");
463 goto fail;
466 if ((evd = malloc(sizeof(*evd))) == NULL) {
467 dprintf(LOG_NOTICE, FNAME,
468 "failed to create a new event data");
469 goto fail;
471 memset(evd, 0, sizeof(*evd));
472 iaparam.iaid = ia->conf->iaid;
473 /* XXX: should we set T1/T2 to 0? spec is silent on this. */
474 iaparam.t1 = ia->t1;
475 iaparam.t2 = ia->t2;
477 if (ia->ctl && ia->ctl->release_data) {
478 if ((*ia->ctl->release_data)(ia->ctl, &iaparam, NULL, evd)) {
479 dprintf(LOG_NOTICE, FNAME,
480 "failed to make release data");
481 goto fail;
484 TAILQ_INSERT_TAIL(&ev->data_list, evd, link);
486 ev->timeouts = 0;
487 dhcp6_set_timeoparam(ev);
488 dhcp6_reset_timer(ev);
490 if (ia->authparam != NULL) {
491 if ((ev->authparam = copy_authparam(ia->authparam)) == NULL) {
492 dprintf(LOG_WARNING, FNAME,
493 "failed to copy authparam");
494 goto fail;
498 client6_send(ev);
500 return (0);
502 fail:
503 if (ev)
504 dhcp6_remove_event(ev);
506 return (-1);
509 static void
510 remove_ia(ia)
511 struct ia *ia;
513 struct ia_conf *iac = ia->conf;
514 struct dhcp6_if *ifp = ia->ifp;
516 dprintf(LOG_DEBUG, FNAME, "remove an IA: %s-%lu",
517 iastr(ia->conf->type), ia->conf->iaid);
519 TAILQ_REMOVE(&iac->iadata, ia, link);
521 duidfree(&ia->serverid);
523 if (ia->timer)
524 dhcp6_remove_timer(&ia->timer);
526 if (ia->evdata) {
527 TAILQ_REMOVE(&ia->evdata->event->data_list, ia->evdata, link);
528 if (ia->evdata->destructor)
529 ia->evdata->destructor(ia->evdata);
530 free(ia->evdata);
531 ia->evdata = NULL;
534 if (ia->ctl && ia->ctl->cleanup)
535 (*ia->ctl->cleanup)(ia->ctl);
537 if (ia->authparam != NULL)
538 free(ia->authparam);
540 free(ia);
542 (void)client6_start(ifp);
545 static struct dhcp6_timer *
546 ia_timo(arg)
547 void *arg;
549 struct ia *ia = (struct ia *)arg;
550 struct dhcp6_ia iaparam;
551 struct dhcp6_event *ev;
552 struct dhcp6_eventdata *evd;
553 struct timeval timo;
554 int dhcpstate;
556 dprintf(LOG_DEBUG, FNAME, "IA timeout for %s-%lu, state=%s",
557 iastr(ia->conf->type), ia->conf->iaid, statestr(ia->state));
559 /* cancel the current event for the prefix. */
560 if (ia->evdata) {
561 TAILQ_REMOVE(&ia->evdata->event->data_list, ia->evdata, link);
562 if (ia->evdata->destructor)
563 ia->evdata->destructor(ia->evdata);
564 free(ia->evdata);
565 ia->evdata = NULL;
568 switch (ia->state) {
569 case IAS_ACTIVE:
570 ia->state = IAS_RENEW;
571 dhcpstate = DHCP6S_RENEW;
572 timo.tv_sec = ia->t1 < ia->t2 ? ia->t2 - ia->t1 : 0;
573 timo.tv_usec = 0;
574 dhcp6_set_timer(&timo, ia->timer);
575 break;
576 case IAS_RENEW:
577 ia->state = IAS_REBIND;
578 dhcpstate = DHCP6S_REBIND;
581 * We need keep DUID for sending Release in this state.
582 * But we don't need a timer for the IA. We'll just wait for a
583 * reply for the REBIND until all associated configuration
584 * parameters for this IA expire.
586 dhcp6_remove_timer(&ia->timer);
587 break;
588 default:
589 dprintf(LOG_ERR, FNAME, "invalid IA state (%d)",
590 (int)ia->state);
591 return (NULL); /* XXX */
594 if ((ev = dhcp6_create_event(ia->ifp, dhcpstate)) == NULL) {
595 dprintf(LOG_NOTICE, FNAME, "failed to create a new event");
596 goto fail;
598 TAILQ_INSERT_TAIL(&ia->ifp->event_list, ev, link);
600 if ((ev->timer = dhcp6_add_timer(client6_timo, ev)) == NULL) {
601 dprintf(LOG_NOTICE, FNAME,
602 "failed to create a new event timer");
603 goto fail;
606 if ((evd = malloc(sizeof(*evd))) == NULL) {
607 dprintf(LOG_NOTICE, FNAME,
608 "failed to create a new event data");
609 goto fail;
611 memset(evd, 0, sizeof(*evd));
612 evd->event = ev;
613 TAILQ_INSERT_TAIL(&ev->data_list, evd, link);
615 if (ia->state == IAS_RENEW) {
616 if (duidcpy(&ev->serverid, &ia->serverid)) {
617 dprintf(LOG_NOTICE, FNAME, "failed to copy server ID");
618 goto fail;
622 iaparam.iaid = ia->conf->iaid;
623 iaparam.t1 = ia->t1;
624 iaparam.t2 = ia->t2;
625 switch(ia->state) {
626 case IAS_RENEW:
627 if (ia->ctl && ia->ctl->renew_data) {
628 if ((*ia->ctl->renew_data)(ia->ctl, &iaparam,
629 &ia->evdata, evd)) {
630 dprintf(LOG_NOTICE, FNAME,
631 "failed to make renew data");
632 goto fail;
635 break;
636 case IAS_REBIND:
637 if (ia->ctl && ia->ctl->rebind_data) {
638 if ((*ia->ctl->rebind_data)(ia->ctl, &iaparam,
639 &ia->evdata, evd)) {
640 dprintf(LOG_NOTICE, FNAME,
641 "failed to make rebind data");
642 goto fail;
645 break;
646 default:
647 break;
650 ev->timeouts = 0;
651 dhcp6_set_timeoparam(ev);
652 dhcp6_reset_timer(ev);
654 if (ia->authparam != NULL) {
655 if ((ev->authparam = copy_authparam(ia->authparam)) == NULL) {
656 dprintf(LOG_WARNING, FNAME,
657 "failed to copy authparam");
658 goto fail;
662 ia->evdata = evd;
664 switch(ia->state) {
665 case IAS_RENEW:
666 case IAS_REBIND:
667 client6_send(ev);
668 break;
669 case IAS_ACTIVE:
670 /* what to do? */
671 break;
674 return (ia->timer);
676 fail:
677 if (ev)
678 dhcp6_remove_event(ev);
680 return (NULL);
683 static struct ia *
684 get_ia(type, ifp, iac, iaparam, serverid)
685 iatype_t type;
686 struct dhcp6_if *ifp;
687 struct ia_conf *iac;
688 struct dhcp6_listval *iaparam;
689 struct duid *serverid;
691 struct ia *ia;
692 struct duid newserver;
693 int create = 0;
695 if (duidcpy(&newserver, serverid)) {
696 dprintf(LOG_NOTICE, FNAME, "failed to copy server ID");
697 return (NULL);
700 if ((ia = find_ia(iac, type, iaparam->val_ia.iaid)) == NULL) {
701 if ((ia = malloc(sizeof(*ia))) == NULL) {
702 dprintf(LOG_NOTICE, FNAME, "memory allocation failed");
703 duidfree(&newserver); /* XXX */
704 return (NULL);
706 memset(ia, 0, sizeof(*ia));
707 ia->state = IAS_ACTIVE;
709 TAILQ_INSERT_TAIL(&iac->iadata, ia, link);
710 ia->conf = iac;
712 create = 1;
713 } else
714 duidfree(&ia->serverid);
716 ia->t1 = iaparam->val_ia.t1;
717 ia->t2 = iaparam->val_ia.t2;
718 ia->ifp = ifp;
719 ia->serverid = newserver;
721 dprintf(LOG_DEBUG, FNAME, "%s an IA: %s-%lu",
722 create ? "make" : "update", iastr(type), ia->conf->iaid);
724 return (ia);
727 static struct ia *
728 find_ia(iac, type, iaid)
729 struct ia_conf *iac;
730 iatype_t type;
731 u_int32_t iaid;
733 struct ia *ia;
735 for (ia = TAILQ_FIRST(&iac->iadata); ia;
736 ia = TAILQ_NEXT(ia, link)) {
737 if (ia->conf->type == type && ia->conf->iaid == iaid)
738 return (ia);
741 return (NULL);
744 static char *
745 iastr(type)
746 iatype_t type;
748 switch (type) {
749 case IATYPE_PD:
750 return ("PD");
751 case IATYPE_NA:
752 return ("NA");
753 default:
754 return ("???"); /* should be a bug */
758 static char *
759 statestr(state)
760 iastate_t state;
762 switch (state) {
763 case IAS_ACTIVE:
764 return "ACTIVE";
765 case IAS_RENEW:
766 return "RENEW";
767 case IAS_REBIND:
768 return "REBIND";
769 default:
770 return "???"; /* should be a bug */