BSD 4_3_Net_2 development
[unix-history] / usr / src / contrib / isode / snmp / udp.c
CommitLineData
9319b3c3
C
1/* udp.c - MIB realization of the UDP group */
2
3#ifndef lint
4static char *rcsid = "$Header: /f/osi/snmp/RCS/udp.c,v 7.7 91/02/22 09:44:50 mrose Interim $";
5#endif
6
7/*
8 * $Header: /f/osi/snmp/RCS/udp.c,v 7.7 91/02/22 09:44:50 mrose Interim $
9 *
10 * Contributed by NYSERNet Inc. This work was partially supported by the
11 * U.S. Defense Advanced Research Projects Agency and the Rome Air Development
12 * Center of the U.S. Air Force Systems Command under contract number
13 * F30602-88-C-0016.
14 *
15 *
16 * $Log: udp.c,v $
17 * Revision 7.7 91/02/22 09:44:50 mrose
18 * Interim 6.8
19 *
20 * Revision 7.6 91/01/08 12:48:51 mrose
21 * update
22 *
23 * Revision 7.5 90/12/18 10:14:19 mrose
24 * update
25 *
26 * Revision 7.4 90/10/02 09:55:03 mrose
27 * normalize again
28 *
29 * Revision 7.3 90/04/23 00:08:20 mrose
30 * touch-up
31 *
32 * Revision 7.2 90/04/18 08:52:09 mrose
33 * oid_normalize
34 *
35 * Revision 7.1 90/02/27 18:50:10 mrose
36 * unix stuff
37 *
38 * Revision 7.0 89/11/23 22:23:38 mrose
39 * Release 6.0
40 *
41 */
42
43/*
44 * NOTICE
45 *
46 * Acquisition, use, and distribution of this module and related
47 * materials are subject to the restrictions of a license agreement.
48 * Consult the Preface in the User's Manual for the full terms of
49 * this agreement.
50 *
51 */
52
53
54#include <stdio.h>
55#include "mib.h"
56
57#include "internet.h"
58#ifdef BSD44
59#include <sys/param.h>
60#endif
61#include <net/route.h>
62#include <sys/socketvar.h>
63#include <netinet/in_systm.h>
64#include <netinet/ip.h>
65#include <netinet/in_pcb.h>
66#include <netinet/ip_var.h>
67#include <netinet/udp.h>
68#include <netinet/udp_var.h>
69
70/* \f */
71
72static struct udpstat udpstat;
73
74/* \f */
75
76#ifdef BSD44
77#define udpInDatagrams 1
78#define udpNoPorts 2
79#endif
80#define udpInErrors 3
81#ifdef BSD44
82#define udpOutDatagrams 4
83#endif
84
85
86static int o_udp (oi, v, offset)
87OI oi;
88register struct type_SNMP_VarBind *v;
89int offset;
90{
91 int ifvar;
92 register struct udpstat *udps = &udpstat;
93 register OID oid = oi -> oi_name;
94 register OT ot = oi -> oi_type;
95 static int lastq = -1;
96
97 ifvar = (int) ot -> ot_info;
98 switch (offset) {
99 case type_SNMP_PDUs_get__request:
100 if (oid -> oid_nelem != ot -> ot_name -> oid_nelem + 1
101 || oid -> oid_elements[oid -> oid_nelem - 1] != 0)
102 return int_SNMP_error__status_noSuchName;
103 break;
104
105 case type_SNMP_PDUs_get__next__request:
106 if (oid -> oid_nelem == ot -> ot_name -> oid_nelem) {
107 OID new;
108
109 if ((new = oid_extend (oid, 1)) == NULLOID)
110 return NOTOK;
111 new -> oid_elements[new -> oid_nelem - 1] = 0;
112
113 if (v -> name)
114 free_SNMP_ObjectName (v -> name);
115 v -> name = new;
116 }
117 else
118 return NOTOK;
119 break;
120
121 default:
122 return int_SNMP_error__status_genErr;
123 }
124
125 if (quantum != lastq) {
126 lastq = quantum;
127
128 if (getkmem (nl + N_UDPSTAT, (caddr_t) udps, sizeof *udps) == NOTOK)
129 return generr (offset);
130 }
131
132 switch (ifvar) {
133#ifdef udpInDatagrams
134 case udpInDatagrams:
135 return o_integer (oi, v, udps -> udps_ipackets);
136#endif
137
138#ifdef udpNoPorts
139 case udpNoPorts:
140 return o_integer (oi, v, udps -> udps_noport);
141#endif
142
143 case udpInErrors:
144 return o_integer (oi, v, udps -> udps_hdrops
145 + udps -> udps_badsum
146 + udps -> udps_badlen);
147
148#ifdef udpOutDatagrams
149 case udpOutDatagrams:
150 return o_integer (oi, v, udps -> udps_opackets);
151#endif
152
153 default:
154 return int_SNMP_error__status_noSuchName;
155 }
156}
157
158/* \f */
159
160struct udptab {
161#define UT_SIZE 5 /* object instance */
162 unsigned int ut_instance[UT_SIZE];
163
164 struct inpcb ut_pcb; /* protocol control block */
165
166 struct socket ut_socb; /* socket info */
167
168 struct udptab *ut_next;
169};
170
171static struct udptab *uts = NULL;
172
173static int flush_udp_cache = 0;
174
175
176struct udptab *get_udpent ();
177
178/* \f */
179
180#define udpLocalAddress 0
181#define udpLocalPort 1
182#define unixUdpRemAddress 2
183#define unixUdpRemPort 3
184#define unixUdpSendQ 4
185#define unixUdpRecvQ 5
186
187
188static int o_udp_listen (oi, v, offset)
189OI oi;
190register struct type_SNMP_VarBind *v;
191int offset;
192{
193 int ifvar;
194 register int i;
195 register unsigned int *ip,
196 *jp;
197 register struct udptab *ut;
198 struct sockaddr_in netaddr;
199 register OID oid = oi -> oi_name;
200 OID new;
201 register OT ot = oi -> oi_type;
202
203 if (get_listeners (offset) == NOTOK)
204 return generr (offset);
205
206 ifvar = (int) ot -> ot_info;
207 switch (offset) {
208 case type_SNMP_PDUs_get__request:
209 if (oid -> oid_nelem != ot -> ot_name -> oid_nelem + UT_SIZE)
210 return int_SNMP_error__status_noSuchName;
211 if ((ut = get_udpent (oid -> oid_elements + oid -> oid_nelem
212 - UT_SIZE, 0)) == NULL)
213 return int_SNMP_error__status_noSuchName;
214 break;
215
216 case type_SNMP_PDUs_get__next__request:
217 if ((i = oid -> oid_nelem - ot -> ot_name -> oid_nelem) != 0
218 && i < UT_SIZE) {
219 for (jp = (ip = oid -> oid_elements + ot -> ot_name -> oid_nelem - 1) + i;
220 jp > ip;
221 jp--)
222 if (*jp != 0)
223 break;
224 if (jp == ip)
225 oid -> oid_nelem = ot -> ot_name -> oid_nelem;
226 else {
227 if ((new = oid_normalize (oid, UT_SIZE - i, 65536))
228 == NULLOID)
229 return NOTOK;
230 if (v -> name)
231 free_SNMP_ObjectName (v -> name);
232 v -> name = oid = new;
233 }
234 }
235 else
236 if (i > UT_SIZE)
237 oid -> oid_nelem = ot -> ot_name -> oid_nelem + UT_SIZE;
238
239 if (oid -> oid_nelem == ot -> ot_name -> oid_nelem) {
240 if ((ut = uts) == NULL)
241 return NOTOK;
242
243 if ((new = oid_extend (oid, UT_SIZE)) == NULLOID)
244 return NOTOK;
245 ip = new -> oid_elements + new -> oid_nelem - UT_SIZE;
246 jp = ut -> ut_instance;
247 for (i = UT_SIZE; i > 0; i--)
248 *ip++ = *jp++;
249
250 if (v -> name)
251 free_SNMP_ObjectName (v -> name);
252 v -> name = new;
253 }
254 else {
255 if ((ut = get_udpent (ip = oid -> oid_elements
256 + oid -> oid_nelem - UT_SIZE, 1))
257 == NULL)
258 return NOTOK;
259
260 jp = ut -> ut_instance;
261 for (i = UT_SIZE; i > 0; i--)
262 *ip++ = *jp++;
263 }
264 break;
265
266 default:
267 return int_SNMP_error__status_genErr;
268 }
269
270 switch (ifvar) {
271 case udpLocalAddress:
272 netaddr.sin_addr = ut -> ut_pcb.inp_laddr; /* struct copy */
273 return o_ipaddr (oi, v, &netaddr);
274
275 case udpLocalPort:
276 return o_integer (oi, v, ntohs (ut -> ut_pcb.inp_lport) & 0xffff);
277
278 case unixUdpRemAddress:
279 netaddr.sin_addr = ut -> ut_pcb.inp_faddr; /* struct copy */
280 return o_ipaddr (oi, v, &netaddr);
281
282 case unixUdpRemPort:
283 return o_integer (oi, v, ntohs (ut -> ut_pcb.inp_fport) & 0xffff);
284
285 case unixUdpSendQ:
286 return o_integer (oi, v, ut -> ut_socb.so_snd.sb_cc);
287
288 case unixUdpRecvQ:
289 return o_integer (oi, v, ut -> ut_socb.so_rcv.sb_cc);
290
291 default:
292 return int_SNMP_error__status_noSuchName;
293 }
294}
295
296/* \f */
297
298static int ut_compar (a, b)
299struct udptab **a,
300 **b;
301{
302 return elem_cmp ((*a) -> ut_instance, UT_SIZE,
303 (*b) -> ut_instance, UT_SIZE);
304}
305
306
307static int get_listeners (offset)
308int offset;
309{
310 register int i;
311 register unsigned int *cp;
312 register struct udptab *us,
313 *up,
314 **usp;
315 register struct inpcb *ip;
316 struct inpcb *head,
317 udb,
318 zdb;
319 struct nlist nzs;
320 register struct nlist *nz = &nzs;
321 static int first_time = 1;
322 static int lastq = -1;
323
324 if (quantum == lastq)
325 return OK;
326 if (!flush_udp_cache
327 && offset == type_SNMP_PDUs_get__next__request
328 && quantum == lastq + 1) { /* XXX: caching! */
329 lastq = quantum;
330 return OK;
331 }
332 lastq = quantum, flush_udp_cache = 0;
333
334 for (us = uts; us; us = up) {
335 up = us -> ut_next;
336
337 free ((char *) us);
338 }
339 uts = NULL;
340
341 if (getkmem (nl + N_UDB, (char *) &udb, sizeof udb) == NOTOK)
342 return NOTOK;
343 head = (struct inpcb *) nl[N_UDB].n_value;
344
345 usp = &uts, i = 0;
346 ip = &udb;
347 while (ip -> inp_next != head) {
348 register struct udptab *uz;
349 OIDentifier oids;
350
351 if ((us = (struct udptab *) calloc (1, sizeof *us)) == NULL)
352 adios (NULLCP, "out of memory");
353
354 nz -> n_name = "struct inpcb",
355 nz -> n_value = (unsigned long) ip -> inp_next;
356 if (getkmem (nz, (caddr_t) &us -> ut_pcb, sizeof us -> ut_pcb)
357 == NOTOK)
358 return NOTOK;
359 ip = &us -> ut_pcb;
360
361 nz ->n_name = "struct socket",
362 nz -> n_value = (unsigned long) ip -> inp_socket;
363 if (getkmem (nz, (caddr_t) &us -> ut_socb, sizeof us -> ut_socb)
364 == NOTOK)
365 return NOTOK;
366
367 cp = us -> ut_instance;
368 cp += ipaddr2oid (cp, &ip -> inp_laddr);
369 *cp++ = ntohs (ip -> inp_lport) & 0xffff;
370
371 for (uz = uts; uz; uz = uz -> ut_next)
372 if (elem_cmp (uz -> ut_instance, UT_SIZE,
373 us -> ut_instance, UT_SIZE) == 0)
374 break;
375 if (uz) {
376 if (first_time) {
377 oids.oid_elements = us -> ut_instance;
378 oids.oid_nelem = UT_SIZE;
379 advise (LLOG_EXCEPTIONS, NULLCP,
380 "duplicate listeners: %s", sprintoid (&oids));
381 }
382
383 *(ip = &zdb) = us -> ut_pcb; /* struct copy */
384 free ((char *) us);
385 continue;
386 }
387 *usp = us, usp = &us -> ut_next, i++;
388
389 if (debug && first_time) {
390 oids.oid_elements = us -> ut_instance;
391 oids.oid_nelem = UT_SIZE;
392 advise (LLOG_DEBUG, NULLCP,
393 "add listener: %s", sprintoid (&oids));
394 }
395 }
396 first_time = 0;
397
398 if (i > 1) {
399 register struct udptab **base,
400 **use;
401
402 if ((base = (struct udptab **) malloc ((unsigned) (i * sizeof *base)))
403 == NULL)
404 adios (NULLCP, "out of memory");
405
406 use = base;
407 for (us = uts; us; us = us -> ut_next)
408 *use++ = us;
409
410 qsort ((char *) base, i, sizeof *base, ut_compar);
411
412 usp = base;
413 us = uts = *usp++;
414
415 while (usp < use) {
416 us -> ut_next = *usp;
417 us = *usp++;
418 }
419 us -> ut_next = NULL;
420
421 free ((char *) base);
422 }
423
424 return OK;
425}
426
427/* \f */
428
429static struct udptab *get_udpent (ip, isnext)
430register unsigned int *ip;
431int isnext;
432{
433 register struct udptab *ut;
434
435 for (ut = uts; ut; ut = ut -> ut_next)
436 switch (elem_cmp (ut -> ut_instance, UT_SIZE, ip, UT_SIZE)) {
437 case 0:
438 if (!isnext)
439 return ut;
440 if ((ut = ut -> ut_next) == NULL)
441 goto out;
442 /* else fall... */
443
444 case 1:
445 return (isnext ? ut : NULL);
446 }
447
448out: ;
449 flush_udp_cache = 1;
450
451 return NULL;
452}
453
454/* \f */
455
456init_udp () {
457 register OT ot;
458
459#ifdef udpInDatagrams
460 if (ot = text2obj ("udpInDatagrams"))
461 ot -> ot_getfnx = o_udp,
462 ot -> ot_info = (caddr_t) udpInDatagrams;
463#endif
464#ifdef udpNoPorts
465 if (ot = text2obj ("udpNoPorts"))
466 ot -> ot_getfnx = o_udp,
467 ot -> ot_info = (caddr_t) udpNoPorts;
468#endif
469 if (ot = text2obj ("udpInErrors"))
470 ot -> ot_getfnx = o_udp,
471 ot -> ot_info = (caddr_t) udpInErrors;
472#ifdef udpOutDatagrams
473 if (ot = text2obj ("udpOutDatagrams"))
474 ot -> ot_getfnx = o_udp,
475 ot -> ot_info = (caddr_t) udpOutDatagrams;
476#endif
477
478 if (ot = text2obj ("udpLocalAddress"))
479 ot -> ot_getfnx = o_udp_listen,
480 ot -> ot_info = (caddr_t) udpLocalAddress;
481 if (ot = text2obj ("udpLocalPort"))
482 ot -> ot_getfnx = o_udp_listen,
483 ot -> ot_info = (caddr_t) udpLocalPort;
484
485 if (ot = text2obj ("unixUdpRemAddress"))
486 ot -> ot_getfnx = o_udp_listen,
487 ot -> ot_info = (caddr_t) unixUdpRemAddress;
488 if (ot = text2obj ("unixUdpRemPort"))
489 ot -> ot_getfnx = o_udp_listen,
490 ot -> ot_info = (caddr_t) unixUdpRemPort;
491 if (ot = text2obj ("unixUdpSendQ"))
492 ot -> ot_getfnx = o_udp_listen,
493 ot -> ot_info = (caddr_t) unixUdpSendQ;
494 if (ot = text2obj ("unixUdpRecvQ"))
495 ot -> ot_getfnx = o_udp_listen,
496 ot -> ot_info = (caddr_t) unixUdpRecvQ;
497}