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

Line Branch Exec Source
1
/*	$OpenBSD: npppd_ctl.c,v 1.16 2017/08/11 16:25:59 goda 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
#include <sys/socket.h>
29
#include <sys/ioctl.h>
30
#include <net/if.h>
31
#include <netinet/in.h>
32
#include <net/pipex.h>
33
34
#include <errno.h>
35
#include <event.h>
36
#include <stddef.h>
37
#include <stdio.h>
38
#include <stdlib.h>
39
#include <string.h>
40
41
#include "radish.h"
42
#include "npppd_local.h"
43
#include "npppd.h"
44
#include "log.h"
45
46
struct stopped_ppp {
47
	struct npppd_who          ppp_who;
48
	TAILQ_ENTRY(stopped_ppp)  entry;
49
};
50
51
struct npppd_ctl {
52
	u_int                     *started_ppp;
53
	int                        started_ppp_pos;
54
	int                        started_ppp_siz;
55
	TAILQ_HEAD(, stopped_ppp)  stopped_ppps;
56
	npppd                     *npppd;
57
	bool                       is_monitoring;
58
	bool                       responding;
59
};
60
61
static int npppd_ctl_who_walk_rd(struct radish *, void *);
62
static int npppd_ctl_who0 (struct npppd_ctl *, bool);
63
static void npppd_who_init (struct npppd_who *, npppd_ppp *);
64
#ifdef USE_NPPPD_PIPEX
65
static int npppd_ppp_get_pipex_stat(struct npppd_who *_this, npppd_ppp *ppp);
66
#endif
67
68
struct npppd_ctl *
69
npppd_ctl_create(npppd *_this)
70
{
71
	struct npppd_ctl *ctl;
72
73
	if ((ctl = calloc(1, sizeof(struct npppd_ctl))) == NULL)
74
		return (NULL);
75
	ctl->npppd = _this;
76
	TAILQ_INIT(&ctl->stopped_ppps);
77
78
	return (ctl);
79
}
80
81
void
82
npppd_ctl_destroy(struct npppd_ctl *_this)
83
{
84
	if (_this != NULL) {
85
		free(_this->started_ppp);
86
		free(_this);
87
	}
88
}
89
90
int
91
npppd_ctl_who(struct npppd_ctl *_this)
92
{
93
	return (npppd_ctl_who0(_this, false));
94
}
95
96
int
97
npppd_ctl_monitor(struct npppd_ctl *_this)
98
{
99
	_this->is_monitoring = true;
100
	return (0);
101
}
102
103
int
104
npppd_ctl_who_and_monitor(struct npppd_ctl *_this)
105
{
106
	return (npppd_ctl_who0(_this, true));
107
}
108
109
static int
110
npppd_ctl_who0(struct npppd_ctl *_this, bool is_monitoring)
111
{
112
	_this->is_monitoring = is_monitoring;
113
	_this->responding = true;
114
	if (rd_walktree(_this->npppd->rd, npppd_ctl_who_walk_rd, _this) != 0)
115
		return (-1);
116
	return (0);
117
}
118
119
int
120
npppd_ctl_add_started_ppp_id(struct npppd_ctl *_this, u_int ppp_id)
121
{
122
	int    started_ppp_siz;
123
	u_int *started_ppp;
124
125
	if (!_this->is_monitoring && !_this->responding)
126
		return (-1);
127
	if (_this->started_ppp_pos + 1 >= _this->started_ppp_siz) {
128
		started_ppp_siz = _this->started_ppp_siz + 128;
129
		started_ppp = reallocarray(_this->started_ppp,
130
		    started_ppp_siz, sizeof(u_int));
131
		if (started_ppp == NULL)
132
			return (-1);
133
		_this->started_ppp = started_ppp;
134
		_this->started_ppp_siz = started_ppp_siz;
135
	}
136
	_this->started_ppp[_this->started_ppp_pos++] = ppp_id;
137
138
	/* reset the event */
139
140
	return (0);
141
}
142
143
int
144
npppd_ctl_add_stopped_ppp(struct npppd_ctl *_this, npppd_ppp *ppp)
145
{
146
	struct stopped_ppp *stopped;
147
148
	if (!_this->is_monitoring)
149
		return (-1);
150
	if ((stopped = malloc(sizeof(struct stopped_ppp))) == NULL) {
151
		log_warn("malloc() failed in %s()", __func__);
152
		return (-1);
153
	}
154
	npppd_who_init(&stopped->ppp_who, ppp);
155
	TAILQ_INSERT_TAIL(&_this->stopped_ppps, stopped, entry);
156
157
	return (0);
158
}
159
160
static int
161
npppd_ctl_who_walk_rd(struct radish *rd, void *ctx)
162
{
163
	struct npppd_ctl *_this = ctx;
164
	struct sockaddr_npppd *snp;
165
	npppd_ppp             *ppp;
166
167
	snp = rd->rd_rtent;
168
	if (snp->snp_type == SNP_PPP) {
169
		ppp = snp->snp_data_ptr;
170
		if (npppd_ctl_add_started_ppp_id(_this, ppp->id) != 0)
171
			return (-1);
172
	}
173
174
	return (0);
175
}
176
177
int
178
npppd_ctl_disconnect(struct npppd_ctl *_this, u_int *ppp_id, int count)
179
{
180
	int        i, n;
181
	npppd_ppp *ppp;
182
183
	for (n = 0, i = 0; i < count; i++) {
184
		if ((ppp = npppd_get_ppp_by_id(_this->npppd, ppp_id[i]))
185
		    != NULL) {
186
			ppp_stop(ppp, NULL);
187
			n++;
188
		}
189
	}
190
191
	return (n);
192
}
193
194
int
195
npppd_ctl_imsg_compose(struct npppd_ctl *_this, struct imsgbuf *ibuf)
196
{
197
	int                    i, cnt;
198
	u_char                 pktbuf[MAX_IMSGSIZE - IMSG_HEADER_SIZE];
199
	struct npppd_who_list *who_list;
200
	npppd_ppp             *ppp;
201
	struct stopped_ppp    *e, *t;
202
203
	if (ibuf->w.queued)
204
		return (0);
205
206
	cnt = 0;
207
	if (!TAILQ_EMPTY(&_this->stopped_ppps)) {
208
		who_list = (struct npppd_who_list *)pktbuf;
209
		who_list->more_data = 0;
210
		TAILQ_FOREACH_SAFE(e, &_this->stopped_ppps, entry, t) {
211
			if (offsetof(struct npppd_who_list, entry[cnt + 1])
212
			    > sizeof(pktbuf)) {
213
				who_list->more_data = 1;
214
				break;
215
			}
216
			TAILQ_REMOVE(&_this->stopped_ppps, e, entry);
217
			memcpy(&who_list->entry[cnt], &e->ppp_who,
218
			    sizeof(who_list->entry[0]));
219
			cnt++;
220
			free(e);
221
		}
222
		who_list->entry_count = cnt;
223
		if (imsg_compose(ibuf, IMSG_PPP_STOP, 0, 0, -1, pktbuf,
224
		    offsetof(struct npppd_who_list, entry[cnt])) == -1)
225
			return (-1);
226
227
		return (0);
228
	}
229
	if (_this->responding || _this->started_ppp_pos > 0) {
230
		who_list = (struct npppd_who_list *)pktbuf;
231
		who_list->more_data = 0;
232
		for (cnt = 0, i = 0; i < _this->started_ppp_pos; i++) {
233
			if (offsetof(struct npppd_who_list, entry[cnt + 1])
234
			    > sizeof(pktbuf)) {
235
				who_list->more_data = 1;
236
				break;
237
			}
238
			if ((ppp = npppd_get_ppp_by_id(_this->npppd,
239
			    _this->started_ppp[i])) == NULL)
240
				/* may be disconnected */
241
				continue;
242
			npppd_who_init(&who_list->entry[cnt], ppp);
243
			cnt++;
244
		}
245
		who_list->entry_count = cnt;
246
		if (imsg_compose(ibuf, IMSG_PPP_START, 0, 0, -1, pktbuf,
247
		    offsetof(struct npppd_who_list, entry[cnt])) == -1)
248
			return (-1);
249
250
		if (_this->started_ppp_pos > i)
251
			memmove(&_this->started_ppp[0],
252
			    &_this->started_ppp[i],
253
			    sizeof(u_int) *
254
				    (_this->started_ppp_pos - i));
255
		_this->started_ppp_pos -= i;
256
		if (who_list->more_data == 0)
257
			_this->responding = false;
258
		return (0);
259
	}
260
261
	return (0);
262
}
263
264
static void
265
npppd_who_init(struct npppd_who *_this, npppd_ppp *ppp)
266
{
267
	struct timespec  curr_time;
268
	npppd_auth_base *realm = ppp->realm;
269
	npppd_iface     *iface = ppp_iface(ppp);
270
271
	strlcpy(_this->username, ppp->username, sizeof(_this->username));
272
	_this->time = ppp->start_time;
273
	clock_gettime(CLOCK_MONOTONIC, &curr_time);
274
	_this->duration_sec = curr_time.tv_sec - ppp->start_monotime;
275
	strlcpy(_this->tunnel_proto, npppd_ppp_tunnel_protocol_name(
276
	    ppp->pppd, ppp), sizeof(_this->tunnel_proto));
277
278
	_this->tunnel_peer.peer_in4.sin_family = AF_UNSPEC;
279
	if (((struct sockaddr *)&ppp->phy_info)->sa_len > 0) {
280
		memcpy(&_this->tunnel_peer, &ppp->phy_info,
281
		    MINIMUM(sizeof(_this->tunnel_peer),
282
			((struct sockaddr *)&ppp->phy_info)->sa_len));
283
	}
284
285
	strlcpy(_this->ifname, iface->ifname, sizeof(_this->ifname));
286
	if (realm == NULL)
287
		_this->rlmname[0] = '\0';
288
	else
289
		strlcpy(_this->rlmname, npppd_auth_get_name(realm),
290
		    sizeof(_this->rlmname));
291
292
	_this->framed_ip_address = ppp->acct_framed_ip_address;
293
	_this->ipackets = ppp->ipackets;
294
	_this->opackets = ppp->opackets;
295
	_this->ierrors = ppp->ierrors;
296
	_this->oerrors = ppp->oerrors;
297
	_this->ibytes = ppp->ibytes;
298
	_this->obytes = ppp->obytes;
299
	_this->ppp_id = ppp->id;
300
	_this->mru = ppp->peer_mru;
301
302
#ifdef USE_NPPPD_PIPEX
303
	if (ppp->pipex_enabled != 0) {
304
		if (npppd_ppp_get_pipex_stat(_this, ppp) != 0) {
305
			log_warn(
306
			    "npppd_ppp_get_pipex_stat() failed in %s",
307
			    __func__);
308
		}
309
	}
310
#endif
311
}
312
313
#ifdef USE_NPPPD_PIPEX
314
static int
315
npppd_ppp_get_pipex_stat(struct npppd_who *_this, npppd_ppp *ppp)
316
{
317
	npppd_iface                   *iface = ppp_iface(ppp);
318
	struct pipex_session_stat_req  req;
319
#ifdef USE_NPPPD_PPPOE
320
	pppoe_session                 *pppoe;
321
#endif
322
#ifdef USE_NPPPD_PPTP
323
	pptp_call                     *pptp;
324
#endif
325
#ifdef USE_NPPPD_L2TP
326
	l2tp_call                     *l2tp;
327
#endif
328
329
	if (ppp->pipex_enabled == 0)
330
		return 0;
331
332
	memset(&req, 0, sizeof(req));
333
	switch(ppp->tunnel_type) {
334
#ifdef	USE_NPPPD_PPPOE
335
	case NPPPD_TUNNEL_PPPOE:
336
		pppoe = (pppoe_session *)ppp->phy_context;
337
338
		/* PPPOE specific information */
339
		req.psr_protocol = PIPEX_PROTO_PPPOE;
340
		req.psr_session_id = pppoe->session_id;
341
		break;
342
#endif
343
#ifdef	USE_NPPPD_PPTP
344
	case NPPPD_TUNNEL_PPTP:
345
		pptp = (pptp_call *)ppp->phy_context;
346
347
		/* PPTP specific information */
348
		req.psr_session_id = pptp->id;
349
		req.psr_protocol = PIPEX_PROTO_PPTP;
350
		break;
351
#endif
352
#ifdef USE_NPPPD_L2TP
353
	case NPPPD_TUNNEL_L2TP:
354
		l2tp = (l2tp_call *)ppp->phy_context;
355
356
		/* L2TP specific information */
357
		req.psr_session_id = l2tp->session_id;
358
		req.psr_protocol = PIPEX_PROTO_L2TP;
359
		break;
360
#endif
361
	default:
362
		errno = EINVAL;
363
		return 1;
364
	}
365
366
	/* update statistics in kernel */
367
	if (ioctl(iface->devf, PIPEXGSTAT, &req) != 0)
368
		return 1;
369
370
	_this->ipackets += req.psr_stat.ipackets;
371
	_this->opackets += req.psr_stat.opackets;
372
	_this->ierrors += req.psr_stat.ierrors;
373
	_this->oerrors += req.psr_stat.oerrors;
374
	_this->ibytes += req.psr_stat.ibytes;
375
	_this->obytes += req.psr_stat.obytes;
376
377
	return 0;
378
}
379
#endif