GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/dvmrpd/interface.c Lines: 0 295 0.0 %
Date: 2017-11-07 Branches: 0 114 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: interface.c,v 1.11 2015/09/27 17:29:46 stsp Exp $ */
2
3
/*
4
 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5
 * Copyright (c) 2004, 2005, 2006 Esben Norby <norby@openbsd.org>
6
 *
7
 * Permission to use, copy, modify, and distribute this software for any
8
 * purpose with or without fee is hereby granted, provided that the above
9
 * copyright notice and this permission notice appear in all copies.
10
 *
11
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 */
19
20
#include <sys/types.h>
21
#include <sys/ioctl.h>
22
#include <sys/time.h>
23
#include <sys/socket.h>
24
25
#include <netinet/in.h>
26
#include <netinet/ip_mroute.h>
27
#include <arpa/inet.h>
28
#include <net/if.h>
29
#include <net/if_types.h>
30
31
#include <ctype.h>
32
#include <err.h>
33
#include <stdio.h>
34
#include <stdlib.h>
35
#include <unistd.h>
36
#include <string.h>
37
#include <event.h>
38
39
#include "igmp.h"
40
#include "dvmrpd.h"
41
#include "dvmrp.h"
42
#include "log.h"
43
#include "dvmrpe.h"
44
45
extern struct dvmrpd_conf	*conf;
46
47
void	 if_probe_timer(int, short, void *);
48
int	 if_start_probe_timer(struct iface *);
49
int	 if_stop_probe_timer(struct iface *);
50
void	 if_query_timer(int, short, void *);
51
int	 if_start_query_timer(struct iface *);
52
int	 if_stop_query_timer(struct iface *);
53
void	 if_querier_present_timer(int, short, void *);
54
int	 if_start_querier_present_timer(struct iface *);
55
int	 if_stop_querier_present_timer(struct iface *);
56
int	 if_reset_querier_present_timer(struct iface *);
57
int	 if_act_start(struct iface *);
58
int	 if_act_query_seen(struct iface *);
59
int	 if_act_reset(struct iface *);
60
61
struct {
62
	int			state;
63
	enum iface_event	event;
64
	enum iface_action	action;
65
	int			new_state;
66
} iface_fsm[] = {
67
    /* current state	event that happened	action to take	resulting state */
68
    {IF_STA_DOWN,	IF_EVT_UP,		IF_ACT_STRT,	0},
69
    {IF_STA_ACTIVE,	IF_EVT_QRECVD,		IF_ACT_QPRSNT,	0},
70
    {IF_STA_NONQUERIER, IF_EVT_QPRSNTTMOUT,	IF_ACT_STRT,	0},
71
    {IF_STA_ANY,	IF_EVT_DOWN,		IF_ACT_RST,	IF_STA_DOWN},
72
    {-1,		IF_EVT_NOTHING,		IF_ACT_NOTHING,	0},
73
};
74
75
const char * const if_action_names[] = {
76
	"NOTHING",
77
	"START",
78
	"QPRSNT",
79
	"RESET"
80
};
81
82
static const char * const if_event_names[] = {
83
	"NOTHING",
84
	"UP",
85
	"QTMOUT",
86
	"QRECVD",
87
	"QPRSNTTMOUT",
88
	"DOWN"
89
};
90
91
int
92
if_fsm(struct iface *iface, enum iface_event event)
93
{
94
	int	old_state;
95
	int	new_state = 0;
96
	int	i, ret = 0;
97
98
	old_state = iface->state;
99
100
	for (i = 0; iface_fsm[i].state != -1; i++)
101
		if ((iface_fsm[i].state & old_state) &&
102
		    (iface_fsm[i].event == event)) {
103
			new_state = iface_fsm[i].new_state;
104
			break;
105
		}
106
107
	if (iface_fsm[i].state == -1) {
108
		/* XXX event outside of the defined fsm, ignore it. */
109
		log_debug("fsm_if: interface %s, "
110
		    "event '%s' not expected in state '%s'", iface->name,
111
		    if_event_name(event), if_state_name(old_state));
112
		return (0);
113
	}
114
115
	switch (iface_fsm[i].action) {
116
	case IF_ACT_STRT:
117
		ret = if_act_start(iface);
118
		break;
119
	case IF_ACT_QPRSNT:
120
		ret = if_act_query_seen(iface);
121
		break;
122
	case IF_ACT_RST:
123
		ret = if_act_reset(iface);
124
		break;
125
	case IF_ACT_NOTHING:
126
		/* do nothing */
127
		break;
128
	}
129
130
	if (ret) {
131
		log_debug("fsm_if: error changing state for interface %s, "
132
		    "event '%s', state '%s'", iface->name, if_event_name(event),
133
		    if_state_name(old_state));
134
		return (-1);
135
	}
136
137
	if (new_state != 0)
138
		iface->state = new_state;
139
140
	log_debug("fsm_if: event '%s' resulted in action '%s' and changing "
141
	    "state for interface %s from '%s' to '%s'",
142
	    if_event_name(event), if_action_name(iface_fsm[i].action),
143
	    iface->name, if_state_name(old_state), if_state_name(iface->state));
144
145
	return (ret);
146
}
147
148
struct iface *
149
if_find_index(u_short ifindex)
150
{
151
	struct iface	*iface;
152
153
	LIST_FOREACH(iface, &conf->iface_list, entry) {
154
		if (iface->ifindex == ifindex)
155
			return (iface);
156
	}
157
158
	return (NULL);
159
}
160
161
struct iface *
162
if_new(struct kif *kif)
163
{
164
	struct sockaddr_in	*sain;
165
	struct iface		*iface;
166
	struct ifreq		*ifr;
167
	int			 s;
168
169
	if ((iface = calloc(1, sizeof(*iface))) == NULL)
170
		err(1, "if_new: calloc");
171
172
	iface->state = IF_STA_DOWN;
173
	iface->passive = 1;
174
175
	LIST_INIT(&iface->nbr_list);
176
	TAILQ_INIT(&iface->group_list);
177
	TAILQ_INIT(&iface->rde_group_list);
178
	strlcpy(iface->name, kif->ifname, sizeof(iface->name));
179
180
	if ((ifr = calloc(1, sizeof(*ifr))) == NULL)
181
		err(1, "if_new: calloc");
182
183
	/* set up ifreq */
184
	strlcpy(ifr->ifr_name, kif->ifname, sizeof(ifr->ifr_name));
185
	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
186
		err(1, "if_new: socket");
187
188
	/* get type */
189
	if ((kif->flags & IFF_POINTOPOINT))
190
		iface->type = IF_TYPE_POINTOPOINT;
191
	if ((kif->flags & IFF_BROADCAST) &&
192
	    (kif->flags & IFF_MULTICAST))
193
		iface->type = IF_TYPE_BROADCAST;
194
195
	/* get mtu, index and flags */
196
	iface->mtu = kif->mtu;
197
	iface->ifindex = kif->ifindex;
198
	iface->flags = kif->flags;
199
	iface->linkstate = kif->link_state;
200
	iface->if_type = kif->if_type;
201
	iface->baudrate = kif->baudrate;
202
203
	/* get address */
204
	if (ioctl(s, SIOCGIFADDR, (caddr_t)ifr) < 0)
205
		err(1, "if_new: cannot get address");
206
	sain = (struct sockaddr_in *) &ifr->ifr_addr;
207
	iface->addr = sain->sin_addr;
208
209
	/* get mask */
210
	if (ioctl(s, SIOCGIFNETMASK, (caddr_t)ifr) < 0)
211
		err(1, "if_new: cannot get mask");
212
	sain = (struct sockaddr_in *) &ifr->ifr_addr;
213
	iface->mask = sain->sin_addr;
214
215
	/* get p2p dst address */
216
	if (iface->type == IF_TYPE_POINTOPOINT) {
217
		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)ifr) < 0)
218
			err(1, "if_new: cannot get dst addr");
219
		sain = (struct sockaddr_in *) &ifr->ifr_addr;
220
		iface->dst = sain->sin_addr;
221
	}
222
223
	free(ifr);
224
	close(s);
225
226
	return (iface);
227
}
228
229
void
230
if_init(struct dvmrpd_conf *xconf, struct iface *iface)
231
{
232
	/* set event handlers for interface */
233
	evtimer_set(&iface->probe_timer, if_probe_timer, iface);
234
	evtimer_set(&iface->query_timer, if_query_timer, iface);
235
	evtimer_set(&iface->querier_present_timer, if_querier_present_timer,
236
	    iface);
237
238
	TAILQ_INIT(&iface->rr_list);
239
240
	iface->fd = xconf->dvmrp_socket;
241
	iface->gen_id = xconf->gen_id;
242
}
243
244
int
245
if_del(struct iface *iface)
246
{
247
	struct nbr	*nbr = NULL;
248
249
	/* clear lists etc */
250
	while ((nbr = LIST_FIRST(&iface->nbr_list)) != NULL) {
251
		LIST_REMOVE(nbr, entry);
252
		nbr_del(nbr);
253
	}
254
	group_list_clr(iface);
255
256
	return (-1);
257
}
258
259
int
260
if_nbr_list_empty(struct iface *iface)
261
{
262
	return (LIST_EMPTY(&iface->nbr_list));
263
}
264
265
/* timers */
266
void
267
if_probe_timer(int fd, short event, void *arg)
268
{
269
	struct iface *iface = arg;
270
	struct timeval tv;
271
272
	send_probe(iface);
273
274
	/* reschedule probe_timer */
275
	if (!iface->passive) {
276
		timerclear(&tv);
277
		tv.tv_sec = iface->probe_interval;
278
		evtimer_add(&iface->probe_timer, &tv);
279
	}
280
}
281
282
int
283
if_start_probe_timer(struct iface *iface)
284
{
285
	struct timeval tv;
286
287
	timerclear(&tv);
288
	return (evtimer_add(&iface->probe_timer, &tv));
289
}
290
291
int
292
if_stop_probe_timer(struct iface *iface)
293
{
294
	return (evtimer_del(&iface->probe_timer));
295
}
296
297
void
298
if_query_timer(int fd, short event, void *arg)
299
{
300
	struct iface *iface = arg;
301
	struct timeval tv;
302
303
	/* send a general query */
304
	send_igmp_query(iface, NULL);
305
306
	/* reschedule query_timer */
307
	if (!iface->passive) {
308
		timerclear(&tv);
309
		if (iface->startup_query_counter != 0) {
310
			tv.tv_sec = iface->startup_query_interval;
311
			iface->startup_query_counter--;
312
		} else
313
			tv.tv_sec = iface->query_interval;
314
315
		evtimer_add(&iface->query_timer, &tv);
316
	}
317
}
318
319
int
320
if_start_query_timer(struct iface *iface)
321
{
322
	struct timeval tv;
323
324
	timerclear(&tv);
325
	return (evtimer_add(&iface->query_timer, &tv));
326
}
327
328
int
329
if_stop_query_timer(struct iface *iface)
330
{
331
	return (evtimer_del(&iface->query_timer));
332
}
333
334
void
335
if_querier_present_timer(int fd, short event, void *arg)
336
{
337
	struct iface *iface = arg;
338
339
	if_fsm(iface, IF_EVT_QPRSNTTMOUT);
340
}
341
342
int
343
if_start_querier_present_timer(struct iface *iface)
344
{
345
	struct timeval tv;
346
347
	/* Other Querier Present Interval */
348
	timerclear(&tv);
349
	tv.tv_sec = iface->robustness * iface->query_interval +
350
	    (iface->query_resp_interval / 2);
351
352
	return (evtimer_add(&iface->querier_present_timer, &tv));
353
}
354
355
int
356
if_stop_querier_present_timer(struct iface *iface)
357
{
358
	return (evtimer_del(&iface->querier_present_timer));
359
}
360
361
int
362
if_reset_querier_present_timer(struct iface *iface)
363
{
364
	struct timeval	tv;
365
366
	/* Other Querier Present Interval */
367
	timerclear(&tv);
368
	tv.tv_sec = iface->robustness * iface->query_interval +
369
	    (iface->query_resp_interval / 2);
370
371
	return (evtimer_add(&iface->querier_present_timer, &tv));
372
}
373
374
/* actions */
375
int
376
if_act_start(struct iface *iface)
377
{
378
	struct in_addr	 addr;
379
	struct timeval	 now;
380
381
	if (iface->passive) {
382
		log_debug("if_act_start: cannot start passive interface %s",
383
		    iface->name);
384
		return (-1);
385
	}
386
387
	if (!((iface->flags & IFF_UP) && LINK_STATE_IS_UP(iface->linkstate))) {
388
		log_debug("if_act_start: interface %s link down",
389
		    iface->name);
390
		return (0);
391
	}
392
393
	gettimeofday(&now, NULL);
394
	iface->uptime = now.tv_sec;
395
396
	switch (iface->type) {
397
	case IF_TYPE_POINTOPOINT:
398
	case IF_TYPE_BROADCAST:
399
		inet_aton(AllSystems, &addr);
400
		if (if_join_group(iface, &addr)) {
401
			log_warnx("if_act_start: error joining group %s, "
402
			    "interface %s", inet_ntoa(addr), iface->name);
403
			return (-1);
404
		}
405
		inet_aton(AllRouters, &addr);
406
		if (if_join_group(iface, &addr)) {
407
			log_warnx("if_act_start: error joining group %s, "
408
			    "interface %s", inet_ntoa(addr), iface->name);
409
			return (-1);
410
		}
411
		inet_aton(AllDVMRPRouters, &addr);
412
		if (if_join_group(iface, &addr)) {
413
			log_warnx("if_act_start: error joining group %s, "
414
			    "interface %s", inet_ntoa(addr), iface->name);
415
			return (-1);
416
		}
417
418
		iface->state = IF_STA_QUERIER;
419
		if_start_query_timer(iface);
420
		if_start_probe_timer(iface);
421
		iface->startup_query_counter = iface->startup_query_cnt;
422
		break;
423
	default:
424
		fatalx("if_act_start: unknown type");
425
	}
426
427
	return (0);
428
}
429
430
int
431
if_act_query_seen(struct iface *iface)
432
{
433
	log_debug("if_act_query_seen: interface %s", iface->name);
434
435
	switch (iface->type) {
436
	case IF_TYPE_POINTOPOINT:
437
	case IF_TYPE_BROADCAST:
438
		iface->state = IF_STA_NONQUERIER;
439
		if_stop_query_timer(iface);
440
		if_reset_querier_present_timer(iface);
441
		break;
442
	default:
443
		fatalx("if_act_querier_seen: unknown type");
444
	}
445
446
	return (0);
447
}
448
449
int
450
if_act_reset(struct iface *iface)
451
{
452
	struct in_addr	 addr;
453
	struct nbr	*nbr;
454
455
	switch (iface->type) {
456
	case IF_TYPE_POINTOPOINT:
457
	case IF_TYPE_BROADCAST:
458
		inet_aton(AllSystems, &addr);
459
		if (if_leave_group(iface, &addr)) {
460
			log_warnx("if_act_reset: error leaving group %s, "
461
			    "interface %s", inet_ntoa(addr), iface->name);
462
			return (-1);
463
		}
464
		inet_aton(AllRouters, &addr);
465
		if (if_leave_group(iface, &addr)) {
466
			log_warnx("if_act_reset: error leaving group %s, "
467
			    "interface %s", inet_ntoa(addr), iface->name);
468
			return (-1);
469
		}
470
		inet_aton(AllDVMRPRouters, &addr);
471
		if (if_leave_group(iface, &addr)) {
472
			log_warnx("if_act_reset: error leaving group %s, "
473
			    "interface %s", inet_ntoa(addr), iface->name);
474
			return (-1);
475
		}
476
477
		iface->state = IF_STA_DOWN;
478
		iface->gen_id++;
479
		if_stop_query_timer(iface);
480
		if_stop_querier_present_timer(iface);
481
		/* XXX clear nbr list? */
482
		break;
483
	default:
484
		fatalx("if_act_reset: unknown type");
485
	}
486
487
	LIST_FOREACH(nbr, &iface->nbr_list, entry) {
488
		if (nbr_fsm(nbr, NBR_EVT_KILL_NBR)) {
489
			log_debug("if_act_reset: error killing neighbor %s",
490
			    inet_ntoa(nbr->id));
491
		}
492
	}
493
494
	group_list_clr(iface);	/* XXX clear group list? */
495
496
	return (0);
497
}
498
499
const char *
500
if_event_name(int event)
501
{
502
	return (if_event_names[event]);
503
}
504
505
const char *
506
if_action_name(int action)
507
{
508
	return (if_action_names[action]);
509
}
510
511
/* misc */
512
int
513
if_set_mcast_ttl(int fd, u_int8_t ttl)
514
{
515
	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
516
	    (char *)&ttl, sizeof(ttl)) < 0) {
517
		log_warn("if_set_mcast_ttl: error setting "
518
		    "IP_MULTICAST_TTL to %d", ttl);
519
		return (-1);
520
	}
521
522
	return (0);
523
}
524
525
int
526
if_set_tos(int fd, int tos)
527
{
528
	if (setsockopt(fd, IPPROTO_IP, IP_TOS,
529
	    (int *)&tos, sizeof(tos)) < 0) {
530
		log_warn("if_set_tos: error setting IP_TOS to 0x%x", tos);
531
		return (-1);
532
	}
533
534
	return (0);
535
}
536
537
void
538
if_set_recvbuf(int fd)
539
{
540
	int	bsize;
541
542
	bsize = 65535;
543
	while (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bsize,
544
	    sizeof(bsize)) == -1)
545
		bsize /= 2;
546
}
547
548
int
549
if_join_group(struct iface *iface, struct in_addr *addr)
550
{
551
	struct ip_mreq	 mreq;
552
553
	switch (iface->type) {
554
	case IF_TYPE_POINTOPOINT:
555
	case IF_TYPE_BROADCAST:
556
		mreq.imr_multiaddr.s_addr = addr->s_addr;
557
		mreq.imr_interface.s_addr = iface->addr.s_addr;
558
559
		if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
560
		    (void *)&mreq, sizeof(mreq)) < 0) {
561
			log_debug("if_join_group: error IP_ADD_MEMBERSHIP, "
562
			    "interface %s", iface->name);
563
			return (-1);
564
		}
565
		break;
566
	default:
567
		fatalx("if_join_group: unknown interface type");
568
	}
569
570
	return (0);
571
}
572
573
int
574
if_leave_group(struct iface *iface, struct in_addr *addr)
575
{
576
	struct ip_mreq	 mreq;
577
578
	switch (iface->type) {
579
	case IF_TYPE_POINTOPOINT:
580
	case IF_TYPE_BROADCAST:
581
		mreq.imr_multiaddr.s_addr = addr->s_addr;
582
		mreq.imr_interface.s_addr = iface->addr.s_addr;
583
584
		if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
585
		    (void *)&mreq, sizeof(mreq)) < 0) {
586
			log_debug("if_leave_group: error IP_DROP_MEMBERSHIP, "
587
			    "interface %s", iface->name);
588
			return (-1);
589
		}
590
		break;
591
	default:
592
		fatalx("if_leave_group: unknown interface type");
593
	}
594
595
	return (0);
596
}
597
598
int
599
if_set_mcast(struct iface *iface)
600
{
601
	switch (iface->type) {
602
	case IF_TYPE_POINTOPOINT:
603
	case IF_TYPE_BROADCAST:
604
		if (setsockopt(iface->fd, IPPROTO_IP, IP_MULTICAST_IF,
605
		    (char *)&iface->addr.s_addr,
606
		    sizeof(iface->addr.s_addr)) < 0) {
607
			log_debug("if_set_mcast: error setting "
608
			    "IP_MULTICAST_IF, interface %s", iface->name);
609
			return (-1);
610
		}
611
		break;
612
	default:
613
		fatalx("if_set_mcast: unknown interface type");
614
	}
615
616
	return (0);
617
}
618
619
int
620
if_set_mcast_loop(int fd)
621
{
622
	u_int8_t	loop = 0;
623
624
	if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
625
	    (char *)&loop, sizeof(loop)) < 0) {
626
		log_warn("if_set_mcast_loop: error setting IP_MULTICAST_LOOP");
627
		return (-1);
628
	}
629
630
	return (0);
631
}
632
633
struct ctl_iface *
634
if_to_ctl(struct iface *iface)
635
{
636
	static struct ctl_iface	 ictl;
637
	struct timeval		 tv, now, res;
638
639
	memcpy(ictl.name, iface->name, sizeof(ictl.name));
640
	memcpy(&ictl.addr, &iface->addr, sizeof(ictl.addr));
641
	memcpy(&ictl.mask, &iface->mask, sizeof(ictl.mask));
642
	memcpy(&ictl.querier, &iface->querier, sizeof(ictl.querier));
643
644
	ictl.ifindex = iface->ifindex;
645
	ictl.state = iface->state;
646
	ictl.mtu = iface->mtu;
647
	ictl.nbr_cnt = iface->nbr_cnt;
648
	ictl.adj_cnt = iface->adj_cnt;
649
650
	ictl.gen_id = iface->gen_id;
651
	ictl.group_cnt = iface->group_cnt;
652
	ictl.probe_interval = iface->probe_interval;
653
	ictl.query_interval = iface->query_interval;
654
	ictl.query_resp_interval = iface->query_resp_interval;
655
	ictl.recv_query_resp_interval = iface->recv_query_resp_interval;
656
	ictl.group_member_interval = iface->group_member_interval;
657
	ictl.querier_present_interval = iface->querier_present_interval;
658
	ictl.startup_query_interval = iface->startup_query_interval;
659
	ictl.startup_query_cnt = iface->startup_query_cnt;
660
	ictl.last_member_query_interval = iface->last_member_query_interval;
661
	ictl.last_member_query_cnt = iface->last_member_query_cnt;
662
	ictl.last_member_query_time = iface->last_member_query_time;
663
	ictl.v1_querier_present_tmout = iface->v1_querier_present_tmout;
664
	ictl.v1_host_present_interval = iface->v1_host_present_interval;
665
	ictl.dead_interval = iface->dead_interval;
666
667
	ictl.baudrate = iface->baudrate;
668
	ictl.flags = iface->flags;
669
	ictl.metric = iface->metric;
670
	ictl.type = iface->type;
671
	ictl.robustness = iface->robustness;
672
	ictl.linkstate = iface->linkstate;
673
	ictl.passive = iface->passive;
674
	ictl.igmp_version = iface->igmp_version;
675
	ictl.if_type = iface->if_type;
676
677
	gettimeofday(&now, NULL);
678
	if (evtimer_pending(&iface->probe_timer, &tv)) {
679
		timersub(&tv, &now, &res);
680
		ictl.probe_timer = res.tv_sec;
681
	} else
682
		ictl.probe_timer = -1;
683
684
	if (evtimer_pending(&iface->query_timer, &tv)) {
685
		timersub(&tv, &now, &res);
686
		ictl.query_timer = res.tv_sec;
687
	} else
688
		ictl.query_timer = -1;
689
690
	if (evtimer_pending(&iface->querier_present_timer, &tv)) {
691
		timersub(&tv, &now, &res);
692
		ictl.querier_present_timer = res.tv_sec;
693
	} else
694
		ictl.querier_present_timer = -1;
695
696
	if (iface->state != IF_STA_DOWN) {
697
		ictl.uptime = now.tv_sec - iface->uptime;
698
	} else
699
		ictl.uptime = 0;
700
701
	return (&ictl);
702
}