Commit | Line | Data |
---|---|---|
9319b3c3 C |
1 | /* udp.c - MIB realization of the UDP group */ |
2 | ||
3 | #ifndef lint | |
4 | static 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 | ||
72 | static 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 | ||
86 | static int o_udp (oi, v, offset) | |
87 | OI oi; | |
88 | register struct type_SNMP_VarBind *v; | |
89 | int 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 | ||
160 | struct 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 | ||
171 | static struct udptab *uts = NULL; | |
172 | ||
173 | static int flush_udp_cache = 0; | |
174 | ||
175 | ||
176 | struct 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 | ||
188 | static int o_udp_listen (oi, v, offset) | |
189 | OI oi; | |
190 | register struct type_SNMP_VarBind *v; | |
191 | int 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 | ||
298 | static int ut_compar (a, b) | |
299 | struct udptab **a, | |
300 | **b; | |
301 | { | |
302 | return elem_cmp ((*a) -> ut_instance, UT_SIZE, | |
303 | (*b) -> ut_instance, UT_SIZE); | |
304 | } | |
305 | ||
306 | ||
307 | static int get_listeners (offset) | |
308 | int 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 | ||
429 | static struct udptab *get_udpent (ip, isnext) | |
430 | register unsigned int *ip; | |
431 | int 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 | ||
448 | out: ; | |
449 | flush_udp_cache = 1; | |
450 | ||
451 | return NULL; | |
452 | } | |
453 | ||
454 | /* \f */ | |
455 | ||
456 | init_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 | } |