mibII_udp.c revision 122394
1/*
2 * Copyright (c) 2001-2003
3 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4 *	All rights reserved.
5 *
6 * Author: Harti Brandt <harti@freebsd.org>
7 *
8 * Redistribution of this software and documentation and use in source and
9 * binary forms, with or without modification, are permitted provided that
10 * the following conditions are met:
11 *
12 * 1. Redistributions of source code or documentation must retain the above
13 *    copyright notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
22 * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
25 * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
28 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
31 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Begemot: bsnmp/snmp_mibII/mibII_udp.c,v 1.4 2003/01/28 13:44:35 hbb Exp $
34 *
35 * udp
36 */
37#include "mibII.h"
38#include "mibII_oid.h"
39#include <sys/socketvar.h>
40#include <netinet/in_pcb.h>
41#include <netinet/udp.h>
42#include <netinet/ip_var.h>
43#include <netinet/udp_var.h>
44
45struct udp_index {
46	struct asn_oid	index;
47	struct xinpcb	*inp;
48};
49
50static u_int32_t udp_tick;
51static struct udpstat udpstat;
52static struct xinpgen *xinpgen;
53static size_t xinpgen_len;
54static u_int udp_total;
55
56static u_int oidnum;
57static struct udp_index *udpoids;
58
59static int
60udp_compare(const void *p1, const void *p2)
61{
62	const struct udp_index *t1 = p1;
63	const struct udp_index *t2 = p2;
64
65	return (asn_compare_oid(&t1->index, &t2->index));
66}
67
68static int
69fetch_udp(void)
70{
71	size_t len;
72	struct xinpgen *ptr;
73	struct xinpcb *inp;
74	struct udp_index *oid;
75	in_addr_t inaddr;
76
77	len = sizeof(udpstat);
78	if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, NULL, 0) == -1) {
79		syslog(LOG_ERR, "net.inet.udp.stats: %m");
80		return (-1);
81	}
82	if (len != sizeof(udpstat)) {
83		syslog(LOG_ERR, "net.inet.udp.stats: wrong size");
84		return (-1);
85	}
86
87	udp_tick = get_ticks();
88
89	len = 0;
90	if (sysctlbyname("net.inet.udp.pcblist", NULL, &len, NULL, 0) == -1) {
91		syslog(LOG_ERR, "net.inet.udp.pcblist: %m");
92		return (-1);
93	}
94	if (len > xinpgen_len) {
95		if ((ptr = realloc(xinpgen, len)) == NULL) {
96			syslog(LOG_ERR, "%zu: %m", len);
97			return (-1);
98		}
99		xinpgen = ptr;
100		xinpgen_len = len;
101	}
102	if (sysctlbyname("net.inet.udp.pcblist", xinpgen, &len, NULL, 0) == -1) {
103		syslog(LOG_ERR, "net.inet.udp.pcblist: %m");
104		return (-1);
105	}
106
107	udp_total = 0;
108	for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len);
109	     ptr->xig_len > sizeof(struct xinpgen);
110             ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) {
111		inp = (struct xinpcb *)ptr;
112		if (inp->xi_inp.inp_gencnt > xinpgen->xig_gen ||
113		    (inp->xi_inp.inp_vflag & INP_IPV4) == 0)
114			continue;
115
116		udp_total++;
117	}
118
119	if (oidnum < udp_total) {
120		oid = realloc(udpoids, udp_total * sizeof(udpoids[0]));
121		if (oid == NULL) {
122			free(udpoids);
123			oidnum = 0;
124			return (0);
125		}
126		udpoids = oid;
127		oidnum = udp_total;
128	}
129
130	oid = udpoids;
131	for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len);
132	     ptr->xig_len > sizeof(struct xinpgen);
133             ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) {
134		inp = (struct xinpcb *)ptr;
135		if (inp->xi_inp.inp_gencnt > xinpgen->xig_gen ||
136		    (inp->xi_inp.inp_vflag & INP_IPV4) == 0)
137			continue;
138		oid->inp = inp;
139		oid->index.len = 5;
140		inaddr = ntohl(inp->xi_inp.inp_laddr.s_addr);
141		oid->index.subs[0] = (inaddr >> 24) & 0xff;
142		oid->index.subs[1] = (inaddr >> 16) & 0xff;
143		oid->index.subs[2] = (inaddr >>  8) & 0xff;
144		oid->index.subs[3] = (inaddr >>  0) & 0xff;
145		oid->index.subs[4] = ntohs(inp->xi_inp.inp_lport);
146		oid++;
147	}
148
149	qsort(udpoids, udp_total, sizeof(udpoids[0]), udp_compare);
150
151	return (0);
152}
153
154int
155op_udp(struct snmp_context *ctx __unused, struct snmp_value *value,
156    u_int sub, u_int iidx __unused, enum snmp_op op)
157{
158	switch (op) {
159
160	  case SNMP_OP_GETNEXT:
161		abort();
162
163	  case SNMP_OP_GET:
164		break;
165
166	  case SNMP_OP_SET:
167		return (SNMP_ERR_NOT_WRITEABLE);
168
169	  case SNMP_OP_ROLLBACK:
170	  case SNMP_OP_COMMIT:
171		abort();
172	}
173
174	if (udp_tick < this_tick)
175		if (fetch_udp() == -1)
176			return (SNMP_ERR_GENERR);
177
178	switch (value->var.subs[sub - 1]) {
179
180	  case LEAF_udpInDatagrams:
181		value->v.uint32 = udpstat.udps_ipackets;
182		break;
183
184	  case LEAF_udpNoPorts:
185		value->v.uint32 = udpstat.udps_noport +
186		    udpstat.udps_noportbcast +
187		    udpstat.udps_noportmcast;
188		break;
189
190	  case LEAF_udpInErrors:
191		value->v.uint32 = udpstat.udps_hdrops +
192		    udpstat.udps_badsum +
193		    udpstat.udps_badlen +
194		    udpstat.udps_fullsock;
195		break;
196
197	  case LEAF_udpOutDatagrams:
198		value->v.uint32 = udpstat.udps_opackets;
199		break;
200	}
201	return (SNMP_ERR_NOERROR);
202}
203
204int
205op_udptable(struct snmp_context *ctx __unused, struct snmp_value *value,
206    u_int sub, u_int iidx __unused, enum snmp_op op)
207{
208	u_int i;
209
210	if (udp_tick < this_tick)
211		if (fetch_udp() == -1)
212			return (SNMP_ERR_GENERR);
213
214	switch (op) {
215
216	  case SNMP_OP_GETNEXT:
217		for (i = 0; i < udp_total; i++)
218			if (index_compare(&value->var, sub, &udpoids[i].index) < 0)
219				break;
220		if (i == udp_total)
221			return (SNMP_ERR_NOSUCHNAME);
222		index_append(&value->var, sub, &udpoids[i].index);
223		break;
224
225	  case SNMP_OP_GET:
226		for (i = 0; i < udp_total; i++)
227			if (index_compare(&value->var, sub, &udpoids[i].index) == 0)
228				break;
229		if (i == udp_total)
230			return (SNMP_ERR_NOSUCHNAME);
231		break;
232
233	  case SNMP_OP_SET:
234		return (SNMP_ERR_NOT_WRITEABLE);
235
236	  case SNMP_OP_ROLLBACK:
237	  case SNMP_OP_COMMIT:
238	  default:
239		abort();
240	}
241
242	switch (value->var.subs[sub - 1]) {
243
244	  case LEAF_udpLocalAddress:
245		value->v.ipaddress[0] = udpoids[i].index.subs[0];
246		value->v.ipaddress[1] = udpoids[i].index.subs[1];
247		value->v.ipaddress[2] = udpoids[i].index.subs[2];
248		value->v.ipaddress[3] = udpoids[i].index.subs[3];
249		break;
250
251	  case LEAF_udpLocalPort:
252		value->v.integer = udpoids[i].index.subs[4];
253		break;
254
255	}
256	return (SNMP_ERR_NOERROR);
257}
258