]> git.saurik.com Git - apple/network_cmds.git/blob - racoon.tproj/handler.c
1ca5b5cb655ffa63f27c134ced99552e6dd7a6a1
[apple/network_cmds.git] / racoon.tproj / handler.c
1 /* $KAME: handler.c,v 1.56 2002/01/02 09:05:25 jinmei Exp $ */
2
3 /*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
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.
18 *
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.
30 */
31
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/socket.h>
35
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <time.h>
40 #include <errno.h>
41
42 #include "var.h"
43 #include "misc.h"
44 #include "vmbuf.h"
45 #include "plog.h"
46 #include "sockmisc.h"
47 #include "debug.h"
48
49 #include "schedule.h"
50 #include "grabmyaddr.h"
51 #include "algorithm.h"
52 #include "crypto_openssl.h"
53 #include "policy.h"
54 #include "proposal.h"
55 #include "isakmp_var.h"
56 #include "isakmp.h"
57 #include "isakmp_inf.h"
58 #include "oakley.h"
59 #include "remoteconf.h"
60 #include "localconf.h"
61 #include "handler.h"
62 #include "gcmalloc.h"
63
64 #ifdef HAVE_GSSAPI
65 #include "gssapi.h"
66 #endif
67
68 static LIST_HEAD(_ph1tree_, ph1handle) ph1tree;
69 static LIST_HEAD(_ph2tree_, ph2handle) ph2tree;
70 static LIST_HEAD(_ctdtree_, contacted) ctdtree;
71 static LIST_HEAD(_rcptree_, recvdpkt) rcptree;
72
73 static void del_recvdpkt __P((struct recvdpkt *));
74 static void rem_recvdpkt __P((struct recvdpkt *));
75 static void sweep_recvdpkt __P((void *));
76
77 /*
78 * functions about management of the isakmp status table
79 */
80 /* %%% management phase 1 handler */
81 /*
82 * search for isakmpsa handler with isakmp index.
83 */
84
85 extern caddr_t val2str(const char *, size_t);
86
87 struct ph1handle *
88 getph1byindex(index)
89 isakmp_index *index;
90 {
91 struct ph1handle *p;
92
93 LIST_FOREACH(p, &ph1tree, chain) {
94 if (p->status == PHASE1ST_EXPIRED)
95 continue;
96 if (memcmp(&p->index, index, sizeof(*index)) == 0)
97 return p;
98 }
99
100 return NULL;
101 }
102
103 /*
104 * search for isakmp handler by i_ck in index.
105 */
106 struct ph1handle *
107 getph1byindex0(index)
108 isakmp_index *index;
109 {
110 struct ph1handle *p;
111
112 LIST_FOREACH(p, &ph1tree, chain) {
113 if (p->status == PHASE1ST_EXPIRED)
114 continue;
115 if (memcmp(&p->index, index, sizeof(cookie_t)) == 0)
116 return p;
117 }
118
119 return NULL;
120 }
121
122 /*
123 * search for isakmpsa handler by remote address.
124 * don't use port number to search because this function search
125 * with phase 2's destinaion.
126 */
127 struct ph1handle *
128 getph1byaddr(local, remote)
129 struct sockaddr *local, *remote;
130 {
131 struct ph1handle *p;
132
133 LIST_FOREACH(p, &ph1tree, chain) {
134 if (p->status == PHASE1ST_EXPIRED)
135 continue;
136 if (cmpsaddrwop(local, p->local) == 0
137 && cmpsaddrwop(remote, p->remote) == 0)
138 return p;
139 }
140
141 return NULL;
142 }
143
144 /*
145 * dump isakmp-sa
146 */
147 vchar_t *
148 dumpph1()
149 {
150 struct ph1handle *iph1;
151 struct ph1dump *pd;
152 int cnt = 0;
153 vchar_t *buf;
154
155 /* get length of buffer */
156 LIST_FOREACH(iph1, &ph1tree, chain)
157 cnt++;
158
159 buf = vmalloc(cnt * sizeof(struct ph1dump));
160 if (buf == NULL) {
161 plog(LLV_ERROR, LOCATION, NULL,
162 "failed to get buffer\n");
163 return NULL;
164 }
165 pd = (struct ph1dump *)buf->v;
166
167 LIST_FOREACH(iph1, &ph1tree, chain) {
168 memcpy(&pd->index, &iph1->index, sizeof(iph1->index));
169 pd->status = iph1->status;
170 pd->side = iph1->side;
171 memcpy(&pd->remote, iph1->remote, iph1->remote->sa_len);
172 memcpy(&pd->local, iph1->local, iph1->local->sa_len);
173 pd->version = iph1->version;
174 pd->etype = iph1->etype;
175 pd->created = iph1->created;
176 pd->ph2cnt = iph1->ph2cnt;
177 pd++;
178 }
179
180 return buf;
181 }
182
183 /*
184 * create new isakmp Phase 1 status record to handle isakmp in Phase1
185 */
186 struct ph1handle *
187 newph1()
188 {
189 struct ph1handle *iph1;
190
191 /* create new iph1 */
192 iph1 = racoon_calloc(1, sizeof(*iph1));
193 if (iph1 == NULL)
194 return NULL;
195
196 iph1->status = PHASE1ST_SPAWN;
197
198 return iph1;
199 }
200
201 /*
202 * delete new isakmp Phase 1 status record to handle isakmp in Phase1
203 */
204 void
205 delph1(iph1)
206 struct ph1handle *iph1;
207 {
208 if (iph1->remote) {
209 racoon_free(iph1->remote);
210 iph1->remote = NULL;
211 }
212 if (iph1->local) {
213 racoon_free(iph1->local);
214 iph1->local = NULL;
215 }
216
217 VPTRINIT(iph1->authstr);
218
219 sched_scrub_param(iph1);
220 iph1->sce = NULL;
221 iph1->scr = NULL;
222
223 VPTRINIT(iph1->sendbuf);
224
225 VPTRINIT(iph1->dhpriv);
226 VPTRINIT(iph1->dhpub);
227 VPTRINIT(iph1->dhpub_p);
228 VPTRINIT(iph1->dhgxy);
229 VPTRINIT(iph1->nonce);
230 VPTRINIT(iph1->nonce_p);
231 VPTRINIT(iph1->skeyid);
232 VPTRINIT(iph1->skeyid_d);
233 VPTRINIT(iph1->skeyid_a);
234 VPTRINIT(iph1->skeyid_e);
235 VPTRINIT(iph1->key);
236 VPTRINIT(iph1->hash);
237 VPTRINIT(iph1->sig);
238 VPTRINIT(iph1->sig_p);
239 oakley_delcert(iph1->cert);
240 iph1->cert = NULL;
241 oakley_delcert(iph1->cert_p);
242 iph1->cert_p = NULL;
243 oakley_delcert(iph1->crl_p);
244 iph1->crl_p = NULL;
245 oakley_delcert(iph1->cr_p);
246 iph1->cr_p = NULL;
247 VPTRINIT(iph1->id);
248 VPTRINIT(iph1->id_p);
249
250 if (iph1->ivm) {
251 oakley_delivm(iph1->ivm);
252 iph1->ivm = NULL;
253 }
254
255 VPTRINIT(iph1->sa);
256 VPTRINIT(iph1->sa_ret);
257
258 #ifdef HAVE_GSSAPI
259 VPTRINIT(iph1->gi_i);
260 VPTRINIT(iph1->gi_r);
261
262 gssapi_free_state(iph1);
263 #endif
264
265 racoon_free(iph1);
266 }
267
268 /*
269 * create new isakmp Phase 1 status record to handle isakmp in Phase1
270 */
271 int
272 insph1(iph1)
273 struct ph1handle *iph1;
274 {
275 /* validity check */
276 if (iph1->remote == NULL) {
277 plog(LLV_ERROR, LOCATION, NULL,
278 "invalid isakmp SA handler. no remote address.\n");
279 return -1;
280 }
281 LIST_INSERT_HEAD(&ph1tree, iph1, chain);
282
283 return 0;
284 }
285
286 void
287 remph1(iph1)
288 struct ph1handle *iph1;
289 {
290 LIST_REMOVE(iph1, chain);
291 }
292
293 /*
294 * flush isakmp-sa
295 */
296 void
297 flushph1()
298 {
299 struct ph1handle *p, *next;
300
301 for (p = LIST_FIRST(&ph1tree); p; p = next) {
302 next = LIST_NEXT(p, chain);
303
304 /* send delete information */
305 if (p->status == PHASE1ST_ESTABLISHED)
306 isakmp_info_send_d1(p);
307
308 remph1(p);
309 delph1(p);
310 }
311 }
312
313 void
314 initph1tree()
315 {
316 LIST_INIT(&ph1tree);
317 }
318
319 /* %%% management phase 2 handler */
320 /*
321 * search ph2handle with policy id.
322 */
323 struct ph2handle *
324 getph2byspid(spid)
325 u_int32_t spid;
326 {
327 struct ph2handle *p;
328
329 LIST_FOREACH(p, &ph2tree, chain) {
330 /*
331 * there are ph2handle independent on policy
332 * such like informational exchange.
333 */
334 if (p->spid == spid)
335 return p;
336 }
337
338 return NULL;
339 }
340
341 /*
342 * search ph2handle with sequence number.
343 */
344 struct ph2handle *
345 getph2byseq(seq)
346 u_int32_t seq;
347 {
348 struct ph2handle *p;
349
350 LIST_FOREACH(p, &ph2tree, chain) {
351 if (p->seq == seq)
352 return p;
353 }
354
355 return NULL;
356 }
357
358 /*
359 * search ph2handle with message id.
360 */
361 struct ph2handle *
362 getph2bymsgid(iph1, msgid)
363 struct ph1handle *iph1;
364 u_int32_t msgid;
365 {
366 struct ph2handle *p;
367
368 LIST_FOREACH(p, &ph2tree, chain) {
369 if (p->msgid == msgid)
370 return p;
371 }
372
373 return NULL;
374 }
375
376 /*
377 * call by pk_recvexpire().
378 */
379 struct ph2handle *
380 getph2bysaidx(src, dst, proto_id, spi)
381 struct sockaddr *src, *dst;
382 u_int proto_id;
383 u_int32_t spi;
384 {
385 struct ph2handle *iph2;
386 struct saproto *pr;
387
388 LIST_FOREACH(iph2, &ph2tree, chain) {
389 if (iph2->proposal == NULL && iph2->approval == NULL)
390 continue;
391 if (iph2->approval != NULL) {
392 for (pr = iph2->approval->head; pr != NULL;
393 pr = pr->next) {
394 if (proto_id != pr->proto_id)
395 break;
396 if (spi == pr->spi || spi == pr->spi_p)
397 return iph2;
398 }
399 } else if (iph2->proposal != NULL) {
400 for (pr = iph2->proposal->head; pr != NULL;
401 pr = pr->next) {
402 if (proto_id != pr->proto_id)
403 break;
404 if (spi == pr->spi)
405 return iph2;
406 }
407 }
408 }
409
410 return NULL;
411 }
412
413 /*
414 * create new isakmp Phase 2 status record to handle isakmp in Phase2
415 */
416 struct ph2handle *
417 newph2()
418 {
419 struct ph2handle *iph2 = NULL;
420
421 /* create new iph2 */
422 iph2 = racoon_calloc(1, sizeof(*iph2));
423 if (iph2 == NULL)
424 return NULL;
425
426 iph2->status = PHASE1ST_SPAWN;
427
428 return iph2;
429 }
430
431 /*
432 * initialize ph2handle
433 * NOTE: don't initialize src/dst.
434 * SPI in the proposal is cleared.
435 */
436 void
437 initph2(iph2)
438 struct ph2handle *iph2;
439 {
440 sched_scrub_param(iph2);
441 iph2->sce = NULL;
442 iph2->scr = NULL;
443
444 VPTRINIT(iph2->sendbuf);
445 VPTRINIT(iph2->msg1);
446
447 /* clear spi, keep variables in the proposal */
448 if (iph2->proposal) {
449 struct saproto *pr;
450 for (pr = iph2->proposal->head; pr != NULL; pr = pr->next)
451 pr->spi = 0;
452 }
453
454 /* clear approval */
455 if (iph2->approval) {
456 flushsaprop(iph2->approval);
457 iph2->approval = NULL;
458 }
459
460 /* clear the generated policy */
461 if (iph2->spidx_gen) {
462 delsp_bothdir((struct policyindex *)iph2->spidx_gen);
463 racoon_free(iph2->spidx_gen);
464 iph2->spidx_gen = NULL;
465 }
466
467 if (iph2->pfsgrp) {
468 oakley_dhgrp_free(iph2->pfsgrp);
469 iph2->pfsgrp = NULL;
470 }
471
472 VPTRINIT(iph2->dhpriv);
473 VPTRINIT(iph2->dhpub);
474 VPTRINIT(iph2->dhpub_p);
475 VPTRINIT(iph2->dhgxy);
476 VPTRINIT(iph2->id);
477 VPTRINIT(iph2->id_p);
478 VPTRINIT(iph2->nonce);
479 VPTRINIT(iph2->nonce_p);
480 VPTRINIT(iph2->sa);
481 VPTRINIT(iph2->sa_ret);
482
483 if (iph2->ivm) {
484 oakley_delivm(iph2->ivm);
485 iph2->ivm = NULL;
486 }
487 }
488
489 /*
490 * delete new isakmp Phase 2 status record to handle isakmp in Phase2
491 */
492 void
493 delph2(iph2)
494 struct ph2handle *iph2;
495 {
496 initph2(iph2);
497
498 if (iph2->src) {
499 racoon_free(iph2->src);
500 iph2->src = NULL;
501 }
502 if (iph2->dst) {
503 racoon_free(iph2->dst);
504 iph2->dst = NULL;
505 }
506 if (iph2->src_id) {
507 racoon_free(iph2->src_id);
508 iph2->src_id = NULL;
509 }
510 if (iph2->dst_id) {
511 racoon_free(iph2->dst_id);
512 iph2->dst_id = NULL;
513 }
514
515 if (iph2->proposal) {
516 flushsaprop(iph2->proposal);
517 iph2->proposal = NULL;
518 }
519
520 racoon_free(iph2);
521 }
522
523 /*
524 * create new isakmp Phase 2 status record to handle isakmp in Phase2
525 */
526 int
527 insph2(iph2)
528 struct ph2handle *iph2;
529 {
530 LIST_INSERT_HEAD(&ph2tree, iph2, chain);
531
532 return 0;
533 }
534
535 void
536 remph2(iph2)
537 struct ph2handle *iph2;
538 {
539 LIST_REMOVE(iph2, chain);
540 }
541
542 void
543 initph2tree()
544 {
545 LIST_INIT(&ph2tree);
546 }
547
548 void
549 flushph2()
550 {
551 struct ph2handle *p, *next;
552
553 for (p = LIST_FIRST(&ph2tree); p; p = next) {
554 next = LIST_NEXT(p, chain);
555
556 /* send delete information */
557 if (p->status == PHASE2ST_ESTABLISHED)
558 isakmp_info_send_d2(p);
559
560 unbindph12(p);
561 remph2(p);
562 delph2(p);
563 }
564 }
565
566 /*
567 * Delete all Phase 2 handlers for this src/dst/proto. This
568 * is used during INITIAL-CONTACT processing (so no need to
569 * send a message to the peer).
570 */
571 void
572 deleteallph2(src, dst, proto_id)
573 struct sockaddr *src, *dst;
574 u_int proto_id;
575 {
576 struct ph2handle *iph2, *next;
577 struct saproto *pr;
578
579 for (iph2 = LIST_FIRST(&ph2tree); iph2 != NULL; iph2 = next) {
580 next = LIST_NEXT(iph2, chain);
581 if (iph2->proposal == NULL && iph2->approval == NULL)
582 continue;
583 if (iph2->approval != NULL) {
584 for (pr = iph2->approval->head; pr != NULL;
585 pr = pr->next) {
586 if (proto_id == pr->proto_id)
587 goto zap_it;
588 }
589 } else if (iph2->proposal != NULL) {
590 for (pr = iph2->proposal->head; pr != NULL;
591 pr = pr->next) {
592 if (proto_id == pr->proto_id)
593 goto zap_it;
594 }
595 }
596 continue;
597 zap_it:
598 unbindph12(iph2);
599 remph2(iph2);
600 delph2(iph2);
601 }
602 }
603
604 /* %%% */
605 void
606 bindph12(iph1, iph2)
607 struct ph1handle *iph1;
608 struct ph2handle *iph2;
609 {
610 iph2->ph1 = iph1;
611 LIST_INSERT_HEAD(&iph1->ph2tree, iph2, ph1bind);
612 }
613
614 void
615 unbindph12(iph2)
616 struct ph2handle *iph2;
617 {
618 if (iph2->ph1 != NULL) {
619 iph2->ph1 = NULL;
620 LIST_REMOVE(iph2, ph1bind);
621 }
622 }
623
624 /* %%% management contacted list */
625 /*
626 * search contacted list.
627 */
628 struct contacted *
629 getcontacted(remote)
630 struct sockaddr *remote;
631 {
632 struct contacted *p;
633
634 LIST_FOREACH(p, &ctdtree, chain) {
635 if (cmpsaddrstrict(remote, p->remote) == 0)
636 return p;
637 }
638
639 return NULL;
640 }
641
642 /*
643 * create new isakmp Phase 2 status record to handle isakmp in Phase2
644 */
645 int
646 inscontacted(remote)
647 struct sockaddr *remote;
648 {
649 struct contacted *new;
650
651 /* create new iph2 */
652 new = racoon_calloc(1, sizeof(*new));
653 if (new == NULL)
654 return -1;
655
656 new->remote = dupsaddr(remote);
657
658 LIST_INSERT_HEAD(&ctdtree, new, chain);
659
660 return 0;
661 }
662
663 void
664 initctdtree()
665 {
666 LIST_INIT(&ctdtree);
667 }
668
669 /*
670 * check the response has been sent to the peer. when not, simply reply
671 * the buffered packet to the peer.
672 * OUT:
673 * 0: the packet is received at the first time.
674 * 1: the packet was processed before.
675 * 2: the packet was processed before, but the address mismatches.
676 * -1: error happened.
677 */
678 int
679 check_recvdpkt(remote, local, rbuf)
680 struct sockaddr *remote, *local;
681 vchar_t *rbuf;
682 {
683 vchar_t *hash;
684 struct recvdpkt *r;
685 time_t t;
686 int len, s;
687
688 /* set current time */
689 t = time(NULL);
690
691 hash = eay_md5_one(rbuf);
692 if (!hash) {
693 plog(LLV_ERROR, LOCATION, NULL,
694 "failed to allocate buffer.\n");
695 return -1;
696 }
697
698 LIST_FOREACH(r, &rcptree, chain) {
699 if (memcmp(hash->v, r->hash->v, r->hash->l) == 0)
700 break;
701 }
702 vfree(hash);
703
704 /* this is the first time to receive the packet */
705 if (r == NULL)
706 return 0;
707
708 /*
709 * the packet was processed before, but the remote address mismatches.
710 */
711 if (cmpsaddrstrict(remote, r->remote) != 0)
712 return 2;
713
714 /*
715 * it should not check the local address because the packet
716 * may arrive at other interface.
717 */
718
719 /* check the previous time to send */
720 if (t - r->time_send < 1) {
721 plog(LLV_WARNING, LOCATION, NULL,
722 "the packet retransmitted in a short time from %s\n",
723 saddr2str(remote));
724 /*XXX should it be error ? */
725 }
726
727 /* select the socket to be sent */
728 s = getsockmyaddr(r->local);
729 if (s == -1)
730 return -1;
731
732 /* resend the packet if needed */
733 len = sendfromto(s, r->sendbuf->v, r->sendbuf->l,
734 r->local, r->remote, lcconf->count_persend);
735 if (len == -1) {
736 plog(LLV_ERROR, LOCATION, NULL, "sendfromto failed\n");
737 return -1;
738 }
739
740 /* check the retry counter */
741 r->retry_counter--;
742 if (r->retry_counter <= 0) {
743 rem_recvdpkt(r);
744 del_recvdpkt(r);
745 plog(LLV_DEBUG, LOCATION, NULL,
746 "deleted the retransmission packet to %s.\n",
747 saddr2str(remote));
748 } else
749 r->time_send = t;
750
751 return 1;
752 }
753
754 /*
755 * adding a hash of received packet into the received list.
756 */
757 int
758 add_recvdpkt(remote, local, sbuf, rbuf)
759 struct sockaddr *remote, *local;
760 vchar_t *sbuf, *rbuf;
761 {
762 struct recvdpkt *new = NULL;
763
764 if (lcconf->retry_counter == 0) {
765 /* no need to add it */
766 return 0;
767 }
768
769 new = racoon_calloc(1, sizeof(*new));
770 if (!new) {
771 plog(LLV_ERROR, LOCATION, NULL,
772 "failed to allocate buffer.\n");
773 return -1;
774 }
775
776 new->hash = eay_md5_one(rbuf);
777 if (!new->hash) {
778 plog(LLV_ERROR, LOCATION, NULL,
779 "failed to allocate buffer.\n");
780 del_recvdpkt(new);
781 return -1;
782 }
783 new->remote = dupsaddr(remote);
784 if (new->remote == NULL) {
785 plog(LLV_ERROR, LOCATION, NULL,
786 "failed to allocate buffer.\n");
787 del_recvdpkt(new);
788 return -1;
789 }
790 new->local = dupsaddr(local);
791 if (new->local == NULL) {
792 plog(LLV_ERROR, LOCATION, NULL,
793 "failed to allocate buffer.\n");
794 del_recvdpkt(new);
795 return -1;
796 }
797 new->sendbuf = vdup(sbuf);
798 if (new->sendbuf == NULL) {
799 plog(LLV_ERROR, LOCATION, NULL,
800 "failed to allocate buffer.\n");
801 del_recvdpkt(new);
802 return -1;
803 }
804
805 new->retry_counter = lcconf->retry_counter;
806 new->time_send = 0;
807 new->created = time(NULL);
808
809 LIST_INSERT_HEAD(&rcptree, new, chain);
810
811 return 0;
812 }
813
814 void
815 del_recvdpkt(r)
816 struct recvdpkt *r;
817 {
818 if (r->remote)
819 racoon_free(r->remote);
820 if (r->local)
821 racoon_free(r->local);
822 if (r->hash)
823 vfree(r->hash);
824 if (r->sendbuf)
825 vfree(r->sendbuf);
826 racoon_free(r);
827 }
828
829 void
830 rem_recvdpkt(r)
831 struct recvdpkt *r;
832 {
833 LIST_REMOVE(r, chain);
834 }
835
836 void
837 sweep_recvdpkt(dummy)
838 void *dummy;
839 {
840 struct recvdpkt *r, *next;
841 time_t t, lt;
842
843 /* set current time */
844 t = time(NULL);
845
846 /* set the lifetime of the retransmission */
847 lt = lcconf->retry_counter * lcconf->retry_interval;
848
849 for (r = LIST_FIRST(&rcptree); r; r = next) {
850 next = LIST_NEXT(r, chain);
851
852 if (t - r->created > lt) {
853 rem_recvdpkt(r);
854 del_recvdpkt(r);
855 }
856 }
857
858 sched_new(lt, sweep_recvdpkt, NULL);
859 }
860
861 void
862 init_recvdpkt()
863 {
864 time_t lt = lcconf->retry_counter * lcconf->retry_interval;
865
866 LIST_INIT(&rcptree);
867
868 sched_new(lt, sweep_recvdpkt, NULL);
869 }