GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/npppd/npppd/npppd_iface.c Lines: 0 235 0.0 %
Date: 2017-11-07 Branches: 0 134 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: npppd_iface.c,v 1.13 2015/12/05 16:10:31 yasuoka Exp $ */
2
3
/*-
4
 * Copyright (c) 2009 Internet Initiative Japan Inc.
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
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 */
28
/* $Id: npppd_iface.c,v 1.13 2015/12/05 16:10:31 yasuoka Exp $ */
29
/**@file
30
 * The interface of npppd and kernel.
31
 * This is an implementation to use tun(4) or pppx(4).
32
 */
33
#include <sys/types.h>
34
#include <sys/ioctl.h>
35
#include <sys/socket.h>
36
#include <sys/uio.h>
37
#include <sys/sockio.h>
38
#include <netinet/in.h>
39
#include <netinet/ip.h>
40
#include <arpa/inet.h>
41
#include <net/if_dl.h>
42
#include <net/if_tun.h>
43
#include <net/if_types.h>
44
#include <net/if.h>
45
#include <net/pipex.h>
46
47
#include <fcntl.h>
48
49
#include <syslog.h>
50
#include <stdio.h>
51
#include <stdlib.h>
52
#include <string.h>
53
#include <unistd.h>
54
#include <errno.h>
55
#include <stdarg.h>
56
57
#include <time.h>
58
#include <event.h>
59
#include "radish.h"
60
61
#include "npppd_defs.h"
62
#include "npppd_local.h"
63
#include "npppd_subr.h"
64
#include "debugutil.h"
65
#include "npppd_iface.h"
66
67
#ifdef USE_NPPPD_PIPEX
68
#include <net/if.h>
69
#if defined(__NetBSD__)
70
#include <net/if_ether.h>
71
#else
72
#include <netinet/if_ether.h>
73
#endif
74
#include <net/pipex.h>
75
#endif /* USE_NPPPD_PIPEX */
76
77
#ifdef	NPPPD_IFACE_DEBUG
78
#define	NPPPD_IFACE_DBG(x)	npppd_iface_log x
79
#define	NPPPD_IFACE_ASSERT(cond)				\
80
	if (!(cond)) {						\
81
	    fprintf(stderr,					\
82
		"\nASSERT(" #cond ") failed on %s() at %s:%d.\n"\
83
		, __func__, __FILE__, __LINE__);		\
84
	    abort(); 						\
85
	}
86
#else
87
#define	NPPPD_IFACE_ASSERT(cond)
88
#define	NPPPD_IFACE_DBG(x)
89
#endif
90
91
static void  npppd_iface_network_input_ipv4(npppd_iface *, struct pppx_hdr *,
92
		u_char *, int);
93
static void  npppd_iface_network_input(npppd_iface *, u_char *, int);
94
static int   npppd_iface_setup_ip(npppd_iface *);
95
static void  npppd_iface_io_event_handler (int, short, void *);
96
static int   npppd_iface_log (npppd_iface *, int, const char *, ...)
97
		__printflike(3,4);
98
99
#ifdef USE_NPPPD_PIPEX
100
static int npppd_iface_pipex_enable(npppd_iface *_this);
101
static int npppd_iface_pipex_disable(npppd_iface *_this);
102
#endif /* USE_NPPPD_PIPEX */
103
104
105
/** initialize npppd_iface */
106
void
107
npppd_iface_init(npppd *npppd, npppd_iface *_this, struct iface *iface)
108
{
109
110
	NPPPD_IFACE_ASSERT(_this != NULL);
111
	memset(_this, 0, sizeof(npppd_iface));
112
113
	_this->npppd = npppd;
114
	strlcpy(_this->ifname, iface->name, sizeof(_this->ifname));
115
	_this->using_pppx = iface->is_pppx;
116
	_this->set_ip4addr = 1;
117
	_this->ip4addr = iface->ip4addr;
118
	_this->ipcpconf = iface->ipcpconf;
119
	_this->devf = -1;
120
	_this->initialized = 1;
121
}
122
123
static int
124
npppd_iface_setup_ip(npppd_iface *_this)
125
{
126
	int sock, if_flags, changed;
127
	struct in_addr gw, assigned;
128
	struct sockaddr_in *sin0;
129
	struct ifreq ifr;
130
	struct ifaliasreq ifra;
131
	npppd_ppp *ppp;
132
133
	NPPPD_IFACE_ASSERT(_this != NULL);
134
135
	sock = -1;
136
	changed = 0;
137
	memset(&ifr, 0, sizeof(ifr));
138
139
	/* get address which was assigned to interface */
140
	assigned.s_addr = INADDR_NONE;
141
	memset(&ifr, 0, sizeof(ifr));
142
	memset(&ifra, 0, sizeof(ifra));
143
	strlcpy(ifr.ifr_name, _this->ifname, sizeof(ifr.ifr_name));
144
	strlcpy(ifra.ifra_name, _this->ifname, sizeof(ifra.ifra_name));
145
	sin0 = (struct sockaddr_in *)&ifr.ifr_addr;
146
147
	if (priv_get_if_addr(_this->ifname, &assigned) != 0) {
148
		if (errno != EADDRNOTAVAIL) {
149
			npppd_iface_log(_this, LOG_ERR,
150
			    "get ip address failed: %m");
151
			goto fail;
152
		}
153
		assigned.s_addr = 0;
154
	}
155
156
	if (assigned.s_addr != _this->ip4addr.s_addr)
157
		changed = 1;
158
159
	if (priv_get_if_flags(_this->ifname, &if_flags) != 0) {
160
		npppd_iface_log(_this, LOG_ERR,
161
		    "ioctl(,SIOCGIFFLAGS) failed: %m");
162
		goto fail;
163
	}
164
	if_flags = ifr.ifr_flags;
165
	if (_this->set_ip4addr != 0 && changed) {
166
		do {
167
			struct in_addr dummy;
168
			if (priv_delete_if_addr(_this->ifname) != 0) {
169
				if (errno == EADDRNOTAVAIL)
170
					break;
171
				npppd_iface_log(_this, LOG_ERR,
172
				    "delete ipaddress %s failed: %m",
173
				    _this->ifname);
174
				goto fail;
175
			}
176
			if (priv_get_if_addr(_this->ifname, &dummy) != 0) {
177
				if (errno == EADDRNOTAVAIL)
178
					break;
179
				npppd_iface_log(_this, LOG_ERR,
180
				    "cannot get ipaddress %s failed: %m",
181
				    _this->ifname);
182
				goto fail;
183
			}
184
		} while (1);
185
186
		/* ifconfig tun1 down */
187
		if (priv_set_if_flags(_this->ifname,
188
		    if_flags & ~(IFF_UP | IFF_BROADCAST)) != 0) {
189
			npppd_iface_log(_this, LOG_ERR,
190
			    "disabling %s failed: %m", _this->ifname);
191
			goto fail;
192
		}
193
		if (priv_set_if_addr(_this->ifname, &_this->ip4addr) != 0 &&
194
		    errno != EEXIST) {
195
			npppd_iface_log(_this, LOG_ERR,
196
			    "Cannot assign tun device ip address: %m");
197
			goto fail;
198
		}
199
		/* erase old route */
200
		if (assigned.s_addr != 0) {
201
			gw.s_addr = htonl(INADDR_LOOPBACK);
202
			in_host_route_delete(&assigned, &gw);
203
		}
204
205
		assigned.s_addr = _this->ip4addr.s_addr;
206
207
	}
208
	_this->ip4addr.s_addr = assigned.s_addr;
209
	if (npppd_iface_ip_is_ready(_this)) {
210
		if (changed) {
211
			/*
212
			 * If there is a PPP session which was assigned
213
			 * interface IP address, disconnect it.
214
			 */
215
			ppp = npppd_get_ppp_by_ip(_this->npppd, _this->ip4addr);
216
			if (ppp != NULL) {
217
				npppd_iface_log(_this, LOG_ERR,
218
				    "Assigning %s, but ppp=%d is using "
219
				    "the address. Requested the ppp to stop",
220
				    inet_ntoa(_this->ip4addr), ppp->id);
221
				ppp_stop(ppp, "Administrative reason");
222
			}
223
		}
224
		/* ifconfig tun1 up */
225
		if (priv_set_if_flags(_this->ifname,
226
		    if_flags | IFF_UP | IFF_MULTICAST) != 0) {
227
			npppd_iface_log(_this, LOG_ERR,
228
			    "enabling %s failed: %m", _this->ifname);
229
			goto fail;
230
		}
231
		/*
232
		 * Add routing entry to communicate from host itself to
233
		 * _this->ip4addr.
234
		 */
235
		gw.s_addr = htonl(INADDR_LOOPBACK);
236
		in_host_route_add(&_this->ip4addr, &gw, LOOPBACK_IFNAME, 0);
237
	}
238
	close(sock); sock = -1;
239
240
	return 0;
241
fail:
242
	if (sock >= 0)
243
		close(sock);
244
245
	return 1;
246
}
247
248
/** set tunnel end address */
249
int
250
npppd_iface_reinit(npppd_iface *_this, struct iface *iface)
251
{
252
	int rval;
253
	struct in_addr backup;
254
	char buf0[128], buf1[128];
255
256
	_this->ipcpconf = iface->ipcpconf;
257
	backup = _this->ip4addr;
258
	_this->ip4addr = iface->ip4addr;
259
260
	if (_this->using_pppx)
261
		return 0;
262
	if ((rval = npppd_iface_setup_ip(_this)) != 0)
263
		return rval;
264
265
	if (backup.s_addr != _this->ip4addr.s_addr) {
266
		npppd_iface_log(_this, LOG_INFO, "Reinited ip4addr %s=>%s",
267
			(backup.s_addr != INADDR_ANY)
268
			    ?  inet_ntop(AF_INET, &backup, buf0, sizeof(buf0))
269
			    : "(not assigned)",
270
			(_this->ip4addr.s_addr != INADDR_ANY)
271
			    ?  inet_ntop(AF_INET, &_this->ip4addr, buf1,
272
				    sizeof(buf1))
273
			    : "(not assigned)");
274
	}
275
276
	return 0;
277
}
278
279
/** start npppd_iface */
280
int
281
npppd_iface_start(npppd_iface *_this)
282
{
283
	int             x;
284
	char            buf[PATH_MAX];
285
286
	NPPPD_IFACE_ASSERT(_this != NULL);
287
288
	/* open device file */
289
	snprintf(buf, sizeof(buf), "/dev/%s", _this->ifname);
290
	if ((_this->devf = priv_open(buf, O_RDWR | O_NONBLOCK)) < 0) {
291
		npppd_iface_log(_this, LOG_ERR, "open(%s) failed: %m", buf);
292
		goto fail;
293
	}
294
295
	if (_this->using_pppx == 0) {
296
		x = IFF_BROADCAST;
297
		if (ioctl(_this->devf, TUNSIFMODE, &x) != 0) {
298
			npppd_iface_log(_this, LOG_ERR,
299
			    "ioctl(TUNSIFMODE=IFF_BROADCAST) failed "
300
			    "in %s(): %m", __func__);
301
			goto fail;
302
		}
303
	}
304
305
	event_set(&_this->ev, _this->devf, EV_READ | EV_PERSIST,
306
	    npppd_iface_io_event_handler, _this);
307
	event_add(&_this->ev, NULL);
308
309
	if (_this->using_pppx == 0) {
310
		if (npppd_iface_setup_ip(_this) != 0)
311
			goto fail;
312
	}
313
314
#ifdef USE_NPPPD_PIPEX
315
	if (npppd_iface_pipex_enable(_this) != 0) {
316
		log_printf(LOG_WARNING,
317
		    "npppd_iface_pipex_enable() failed: %m");
318
	}
319
#else
320
	if (_this->using_pppx) {
321
		npppd_iface_log(_this, LOG_ERR,
322
		    "pipex is required when using pppx interface");
323
		goto fail;
324
	}
325
#endif /* USE_NPPPD_PIPEX */
326
327
	if (_this->using_pppx) {
328
		npppd_iface_log(_this, LOG_INFO, "Started pppx");
329
	} else {
330
		npppd_iface_log(_this, LOG_INFO, "Started ip4addr=%s",
331
			(npppd_iface_ip_is_ready(_this))?
332
			    inet_ntop(AF_INET, &_this->ip4addr, buf,
333
			    sizeof(buf)) : "(not assigned)");
334
	}
335
	_this->started = 1;
336
337
	return 0;
338
fail:
339
	if (_this->devf >= 0) {
340
		event_del(&_this->ev);
341
		close(_this->devf);
342
	}
343
	_this->devf = -1;
344
345
	return -1;
346
}
347
348
/** stop to use npppd_iface */
349
void
350
npppd_iface_stop(npppd_iface *_this)
351
{
352
	struct in_addr gw;
353
354
	NPPPD_IFACE_ASSERT(_this != NULL);
355
	if (_this->using_pppx == 0) {
356
		priv_delete_if_addr(_this->ifname);
357
		gw.s_addr = htonl(INADDR_LOOPBACK);
358
		in_host_route_delete(&_this->ip4addr, &gw);
359
	}
360
	if (_this->devf >= 0) {
361
#ifdef USE_NPPPD_PIPEX
362
		if (npppd_iface_pipex_disable(_this) != 0) {
363
			log_printf(LOG_CRIT,
364
			    "npppd_iface_pipex_disable() failed: %m");
365
		}
366
#endif /* USE_NPPPD_PIPEX */
367
368
		event_del(&_this->ev);
369
		close(_this->devf);
370
		npppd_iface_log(_this, LOG_INFO, "Stopped");
371
	}
372
	_this->devf = -1;
373
	_this->started = 0;
374
	event_del(&_this->ev);
375
}
376
377
/** finalize npppd_iface */
378
void
379
npppd_iface_fini(npppd_iface *_this)
380
{
381
	NPPPD_IFACE_ASSERT(_this != NULL);
382
	_this->initialized = 0;
383
}
384
385
386
/***********************************************************************
387
 * PIPEX related functions
388
 ***********************************************************************/
389
#ifdef USE_NPPPD_PIPEX
390
391
/** enable PIPEX on PPPAC interface */
392
int
393
npppd_iface_pipex_enable(npppd_iface *_this)
394
{
395
	int enable = 1;
396
397
	return ioctl(_this->devf, PIPEXSMODE, &enable);
398
}
399
400
/** disable PIPEX on PPPAC interface */
401
int
402
npppd_iface_pipex_disable(npppd_iface *_this)
403
{
404
	int disable = 0;
405
406
	return ioctl(_this->devf, PIPEXSMODE, &disable);
407
}
408
409
#endif /* USE_NPPPD_PIPEX */
410
411
412
/***********************************************************************
413
 * I/O related functions
414
 ***********************************************************************/
415
/** I/O event handler */
416
static void
417
npppd_iface_io_event_handler(int fd, short evtype, void *data)
418
{
419
	int sz;
420
	u_char buffer[8192];
421
	npppd_iface *_this;
422
423
	NPPPD_IFACE_ASSERT((evtype & EV_READ) != 0);
424
425
	_this = data;
426
	NPPPD_IFACE_ASSERT(_this->devf >= 0);
427
	do {
428
		sz = read(_this->devf, buffer, sizeof(buffer));
429
		if (sz <= 0) {
430
			if (sz == 0)
431
				npppd_iface_log(_this, LOG_ERR,
432
				    "file is closed");
433
			else if (errno == EAGAIN)
434
				break;
435
			else
436
				npppd_iface_log(_this, LOG_ERR,
437
				    "read failed: %m");
438
			npppd_iface_stop(_this);
439
			return;
440
		}
441
		npppd_iface_network_input(_this, buffer, sz);
442
443
	} while (1 /* CONSTCOND */);
444
445
	return;
446
}
447
448
/** structure of argument of npppd_iface_network_input_delegate */
449
struct npppd_iface_network_input_arg{
450
	npppd_iface *_this;
451
	u_char *pktp;
452
	int lpktp;
453
};
454
455
/** callback function which works for each PPP session */
456
static int
457
npppd_iface_network_input_delegate(struct radish *radish, void *args0)
458
{
459
	npppd_ppp *ppp;
460
	struct sockaddr_npppd *snp;
461
	struct npppd_iface_network_input_arg *args;
462
463
	snp = radish->rd_rtent;
464
465
	if (snp->snp_type == SNP_PPP) {
466
		args = args0;
467
		ppp = snp->snp_data_ptr;
468
		if (ppp_iface(ppp) != args->_this)
469
			return 0;
470
#ifdef	USE_NPPPD_MPPE
471
		if (MPPE_SEND_READY(ppp)) {
472
			/* output via MPPE if MPPE started */
473
			mppe_pkt_output(&ppp->mppe, PPP_PROTO_IP, args->pktp,
474
			    args->lpktp);
475
		} else if (MPPE_IS_REQUIRED(ppp)) {
476
			/* in case MPPE not started but MPPE is mandatory, */
477
			/* it is not necessary to log because of multicast. */
478
			return 0;
479
		}
480
#endif
481
		ppp_output(ppp, PPP_PROTO_IP, 0, 0, args->pktp, args->lpktp);
482
	}
483
484
	return 0;
485
}
486
487
static void
488
npppd_iface_network_input_ipv4(npppd_iface *_this, struct pppx_hdr *pppx,
489
    u_char *pktp, int lpktp)
490
{
491
	struct ip *iphdr;
492
	npppd *_npppd;
493
	npppd_ppp *ppp;
494
	struct npppd_iface_network_input_arg input_arg;
495
496
	NPPPD_IFACE_ASSERT(_this != NULL);
497
	NPPPD_IFACE_ASSERT(pktp != NULL);
498
499
	iphdr = (struct ip *)pktp;
500
	_npppd = _this->npppd;
501
502
	if (lpktp < sizeof(iphdr)) {
503
		npppd_iface_log(_this, LOG_ERR, "Received short packet.");
504
		return;
505
	}
506
	if (_this->using_pppx)
507
		ppp = npppd_get_ppp_by_id(_npppd, pppx->pppx_id);
508
	else {
509
		if (IN_MULTICAST(ntohl(iphdr->ip_dst.s_addr))) {
510
			NPPPD_IFACE_ASSERT(
511
			    ((npppd *)(_this->npppd))->rd != NULL);
512
			input_arg._this = _this;
513
			input_arg.pktp = pktp;
514
			input_arg.lpktp = lpktp;
515
			/* delegate */
516
			rd_walktree(((npppd *)(_this->npppd))->rd,
517
			    npppd_iface_network_input_delegate, &input_arg);
518
			return;
519
		}
520
		ppp = npppd_get_ppp_by_ip(_npppd, iphdr->ip_dst);
521
	}
522
523
	if (ppp == NULL) {
524
#ifdef NPPPD_DEBUG
525
		log_printf(LOG_INFO, "%s received a packet to unknown "
526
		    "%s.", _this->ifname, inet_ntoa(iphdr->ip_dst));
527
#endif
528
		return;
529
	}
530
#ifndef NO_ADJUST_MSS
531
	if (ppp->adjust_mss) {
532
		adjust_tcp_mss(pktp, lpktp, MRU_IPMTU(ppp->peer_mru));
533
	}
534
#endif
535
	if (ppp->timeout_sec > 0 && !ip_is_idle_packet(iphdr, lpktp))
536
		ppp_reset_idle_timeout(ppp);
537
538
#ifdef	USE_NPPPD_MPPE
539
	if (MPPE_SEND_READY(ppp)) {
540
		/* output via MPPE if MPPE started */
541
		mppe_pkt_output(&ppp->mppe, PPP_PROTO_IP, pktp, lpktp);
542
		return;
543
	} else if (MPPE_IS_REQUIRED(ppp)) {
544
		/* in case MPPE not started but MPPE is mandatory */
545
		ppp_log(ppp, LOG_WARNING, "A packet received from network, "
546
		    "but MPPE is not started.");
547
		return;
548
	}
549
#endif
550
	ppp_output(ppp, PPP_PROTO_IP, 0, 0, pktp, lpktp);
551
}
552
553
/**
554
 * This function is called when an input packet come from network(tun).
555
 * Currently, it assumes that it input IPv4 packet.
556
 */
557
static void
558
npppd_iface_network_input(npppd_iface *_this, u_char *pktp, int lpktp)
559
{
560
	uint32_t af;
561
	struct pppx_hdr *pppx = NULL;
562
563
	if (_this->using_pppx) {
564
		if (lpktp < sizeof(struct pppx_hdr)) {
565
			npppd_iface_log(_this, LOG_ERR,
566
			    "Received short packet.");
567
			return;
568
		}
569
		pppx = (struct pppx_hdr *)pktp;
570
		pktp += sizeof(struct pppx_hdr);
571
		lpktp -= sizeof(struct pppx_hdr);
572
	}
573
574
	if (lpktp < sizeof(uint32_t)) {
575
		npppd_iface_log(_this, LOG_ERR, "Received short packet.");
576
		return;
577
	}
578
	GETLONG(af, pktp);
579
	lpktp -= sizeof(uint32_t);
580
581
	switch (af) {
582
	case AF_INET:
583
		npppd_iface_network_input_ipv4(_this, pppx, pktp, lpktp);
584
		break;
585
586
	default:
587
		NPPPD_IFACE_ASSERT(0);
588
		break;
589
590
	}
591
}
592
593
/** write to tunnel device */
594
void
595
npppd_iface_write(npppd_iface *_this, npppd_ppp *ppp, int proto, u_char *pktp,
596
    int lpktp)
597
{
598
	int niov = 0, tlen;
599
	uint32_t th;
600
	struct iovec iov[3];
601
	struct pppx_hdr pppx;
602
	NPPPD_IFACE_ASSERT(_this != NULL);
603
	NPPPD_IFACE_ASSERT(_this->devf >= 0);
604
605
	tlen = 0;
606
	th = htonl(proto);
607
	if (_this->using_pppx) {
608
		pppx.pppx_proto = npppd_pipex_proto(ppp->tunnel_type);
609
		pppx.pppx_id = ppp->tunnel_session_id;
610
		iov[niov].iov_base = &pppx;
611
		iov[niov++].iov_len = sizeof(pppx);
612
		tlen += sizeof(pppx);
613
	}
614
	iov[niov].iov_base = &th;
615
	iov[niov++].iov_len = sizeof(th);
616
	tlen += sizeof(th);
617
	iov[niov].iov_base = pktp;
618
	iov[niov++].iov_len = lpktp;
619
	tlen += lpktp;
620
621
	if (writev(_this->devf, iov, niov) != tlen)
622
		npppd_iface_log(_this, LOG_ERR, "write failed: %m");
623
}
624
625
/***********************************************************************
626
 * misc functions
627
 ***********************************************************************/
628
/** Log it which starts the label based on this instance. */
629
static int
630
npppd_iface_log(npppd_iface *_this, int prio, const char *fmt, ...)
631
{
632
	int status;
633
	char logbuf[BUFSIZ];
634
	va_list ap;
635
636
	NPPPD_IFACE_ASSERT(_this != NULL);
637
638
	va_start(ap, fmt);
639
	snprintf(logbuf, sizeof(logbuf), "%s %s", _this->ifname, fmt);
640
	status = vlog_printf(prio, logbuf, ap);
641
	va_end(ap);
642
643
	return status;
644
}