snmp.c revision 1.2 1 /* $NetBSD: snmp.c,v 1.2 1995/10/09 03:51:58 thorpej Exp $ */
2
3 /*
4 * snmp.c
5 *
6 * Code written by David Thaler <thalerd (at) eecs.umich.edu>
7 * Moved to a seperate file by Bill Fenner <fenner (at) parc.xerox.com>
8 */
9
10
11 #include "defs.h"
12 #include <string.h>
13 #include "snmp.h"
14
15 #define NUMMIBS 2
16 #define SNMPD_RETRY_INTERVAL 300 /* periodic snmpd probe interval */
17
18 char *mibs[]={ "ipMRouteMIB", "dvmrpMIB" };
19
20 extern int o_ipMRouteTable();
21 extern int o_ipMRouteNextHopTable();
22 extern int o_dvmrpRouteTable();
23 extern int o_dvmrpRouteNextHopTable();
24
25 int smux_fd = NOTOK;
26 int rock_and_roll = 0;
27 int dont_bother_anymore = 0;
28 int quantum = 0;
29 static OID subtree[NUMMIBS] = NULLOID;
30 static struct smuxEntry *se = NULL;
31 extern int smux_errno;
32 extern char smux_info[BUFSIZ];
33
34 /*
35 * Place an IP address into an OID starting at element n
36 */
37 void
38 put_address(oid, addr, n)
39 OID oid;
40 u_long addr;
41 int n;
42 {
43 int i;
44
45 for (i=n+3; i>=n+0; i--) {
46 oid->oid_elements[i] = addr & 0xFF;
47 addr >>= 8;
48 }
49 }
50
51 /* Get an IP address from an OID starting at element n */
52 int
53 get_address(oid, addr, n)
54 OID oid;
55 u_long *addr;
56 int n;
57 {
58 int i;
59 int ok = 1;
60
61 (*addr) = 0;
62
63 if (oid -> oid_nelem < n+4)
64 return 0;
65
66 for (i=n; i<n+4; i++) {
67 (*addr) <<= 8;
68 if (i >= oid->oid_nelem)
69 ok = 0;
70 else
71 (*addr) |= oid->oid_elements[i];
72 }
73
74 return ok;
75 }
76
77 /*
78 * Attempt to start up SMUX protocol
79 */
80 void
81 try_smux_init()
82 {
83 if (smux_fd != NOTOK || dont_bother_anymore)
84 return;
85 if ((smux_fd = smux_init(debug)) == NOTOK) {
86 log(LOG_WARNING, 0,"smux_init: %s [%s]", smux_error(smux_errno),
87 smux_info);
88 } else
89 rock_and_roll = 0;
90 }
91
92 /*
93 * Implements scalar objects from both MIBs
94 */
95 static int
96 o_scalar(oi, v, offset)
97 OI oi;
98 register struct type_SNMP_VarBind *v;
99 int offset;
100 {
101 int ifvar;
102 register OID oid = oi -> oi_name;
103 register OT ot = oi -> oi_type;
104
105 ifvar = (int) ot -> ot_info;
106 switch (offset) {
107 case type_SNMP_SMUX__PDUs_get__request:
108 if (oid -> oid_nelem !=
109 ot -> ot_name -> oid_nelem + 1
110 || oid -> oid_elements[oid -> oid_nelem - 1]
111 != 0)
112 return int_SNMP_error__status_noSuchName;
113 break;
114
115 case type_SNMP_SMUX__PDUs_get__next__request:
116 if (oid -> oid_nelem
117 == ot -> ot_name -> oid_nelem) {
118 OID new;
119
120 if ((new = oid_extend (oid, 1)) == NULLOID)
121 return int_SNMP_error__status_genErr;
122 new -> oid_elements[new -> oid_nelem - 1] = 0;
123
124 if (v -> name)
125 free_SNMP_ObjectName (v -> name);
126 v -> name = new;
127 }
128 else
129 return NOTOK;
130 break;
131
132 default:
133 return int_SNMP_error__status_genErr;
134 }
135
136 switch (ifvar) {
137 case ipMRouteEnable:
138 return o_integer (oi, v, 1);
139
140 case dvmrpVersion: {
141 static char buff[15];
142
143 sprintf(buff, "mrouted%d.%d", PROTOCOL_VERSION, MROUTED_VERSION);
144 return o_string (oi, v, buff, strlen (buff));
145 }
146
147 case dvmrpGenerationId:
148 return o_integer (oi, v, dvmrp_genid);
149
150 default:
151 return int_SNMP_error__status_noSuchName;
152 }
153 }
154
155 /*
156 * Find if a specific scoped boundary exists on a Vif
157 */
158 struct vif_acl *
159 find_boundary(vifi, addr, mask)
160 int vifi;
161 int addr;
162 int mask;
163 {
164 struct vif_acl *n;
165
166 for (n = uvifs[vifi].uv_acl; n != NULL; n = n->acl_next) {
167 if (addr == n->acl_addr && mask==n->acl_mask)
168 return n;
169 }
170 return NULL;
171 }
172
173 /*
174 * Find the next scoped boundary in order after a given spec
175 */
176 struct vif_acl *
177 next_boundary(vifi, addr, mask)
178 int *vifi;
179 int addr;
180 int mask;
181 {
182 struct vif_acl *bestn, *n;
183 int i;
184
185 for (i = *vifi; i < numvifs; i++) {
186 bestn = NULL;
187 for (n = uvifs[i].uv_acl; n; n=n->acl_next) {
188 if ((i > *vifi || n->acl_addr > addr
189 || (n->acl_addr==addr && n->acl_mask>mask))
190 && (!bestn || n->acl_addr < bestn->acl_addr
191 || (n->acl_addr==bestn->acl_addr && n->acl_mask<bestn->acl_mask)))
192 bestn = n;
193 }
194 if (bestn) {
195 *vifi = i;
196 return bestn;
197 }
198 }
199 return NULL;
200 }
201
202 /*
203 * Implements the Boundary Table portion of the DVMRP MIB
204 */
205 static int
206 o_dvmrpBoundaryTable (oi, v, offset)
207 OI oi;
208 register struct type_SNMP_VarBind *v;
209 {
210 int ifvar, vifi,
211 addr, mask;
212 register OID oid = oi -> oi_name;
213 register OT ot = oi -> oi_type;
214 struct vif_acl *bound;
215
216 ifvar = (int) ot -> ot_info;
217 switch (offset) {
218 case type_SNMP_SMUX__PDUs_get__request:
219 if (oid->oid_nelem != ot->ot_name->oid_nelem + 9)
220 return int_SNMP_error__status_noSuchName;
221
222 if ((vifi = oid -> oid_elements[ot-> ot_name->oid_nelem]) >= numvifs)
223 return int_SNMP_error__status_noSuchName;
224
225 if (!get_address(oid, &addr, ot->ot_name->oid_nelem+1)
226 || !get_address(oid, &mask, ot->ot_name->oid_nelem+5))
227 return int_SNMP_error__status_noSuchName;
228
229 if (!(bound = find_boundary(vifi, addr, mask)))
230 return int_SNMP_error__status_noSuchName;
231 break;
232
233 case type_SNMP_SMUX__PDUs_get__next__request:
234 if (oid->oid_nelem < ot->ot_name->oid_nelem + 9) {
235 OID new;
236
237 if (oid->oid_nelem == ot->ot_name->oid_nelem) {
238 vifi = addr = mask = 0;
239 } else {
240 vifi = oid->oid_elements[ot->ot_name->oid_nelem];
241 get_address(oid, &addr, ot->ot_name->oid_nelem+1);
242 get_address(oid, &mask, ot->ot_name->oid_nelem+5);
243 }
244
245 bound = next_boundary(&vifi,addr,mask);
246 if (!bound)
247 return NOTOK;
248
249 new = oid_extend (oid, ot->ot_name->oid_nelem+9-oid->oid_nelem);
250 if (new == NULLOID)
251 return NOTOK;
252 new -> oid_elements[ot->ot_name->oid_nelem] = vifi;
253 put_address(new, bound->acl_addr, ot->ot_name->oid_nelem+1);
254 put_address(new, bound->acl_mask, ot->ot_name->oid_nelem+5);
255
256 if (v -> name)
257 free_SNMP_ObjectName (v -> name);
258 v -> name = new;
259 } else { /* get next entry given previous */
260 int i = ot -> ot_name -> oid_nelem;
261
262 vifi = oid->oid_elements[i];
263 get_address(oid, &addr, ot->ot_name->oid_nelem+1);
264 get_address(oid, &mask, ot->ot_name->oid_nelem+5);
265 if (!(bound = next_boundary(&vifi,addr,mask+1)))
266 return NOTOK;
267
268 put_address(oid, bound->acl_addr, ot->ot_name->oid_nelem+1);
269 put_address(oid, bound->acl_mask, ot->ot_name->oid_nelem+5);
270 oid->oid_elements[i] = vifi;
271 oid->oid_nelem = i + 9;
272 }
273 break;
274
275 default:
276 return int_SNMP_error__status_genErr;
277 }
278
279 switch (ifvar) {
280
281 case dvmrpBoundaryVifIndex:
282 return o_integer (oi, v, vifi);
283
284 default:
285 return int_SNMP_error__status_noSuchName;
286 }
287 }
288
289 /*
290 * Given a vif index and address, return the next greater neighbor entry
291 */
292 struct listaddr *
293 next_neighbor(vifi, addr)
294 int *vifi;
295 int addr;
296 {
297 struct listaddr *bestn, *n;
298 int i;
299
300 for (i = *vifi; i < numvifs; i++) {
301 bestn = NULL;
302 for (n = uvifs[i].uv_neighbors; n; n=n->al_next) {
303 if ((i > *vifi || n->al_addr > addr)
304 && (!bestn || n->al_addr < bestn->al_addr))
305 bestn = n;
306 }
307 if (bestn) {
308 *vifi = i;
309 return bestn;
310 }
311 }
312 return NULL;
313 }
314
315 /*
316 * Find a neighbor, if it exists off a given Vif
317 */
318 struct listaddr *
319 find_neighbor(vifi, addr)
320 int vifi;
321 int addr;
322 {
323 struct listaddr *n;
324
325 for (n = uvifs[vifi].uv_neighbors; n != NULL; n = n->al_next) {
326 if (addr == n->al_addr)
327 return n;
328 }
329 return NULL;
330 }
331
332 /*
333 * Implements the Neighbor Table portion of the DVMRP MIB
334 */
335 static int
336 o_dvmrpNeighborTable (oi, v, offset)
337 OI oi;
338 register struct type_SNMP_VarBind *v;
339 {
340 int ifvar, vifi,
341 addr;
342 register OID oid = oi -> oi_name;
343 register OT ot = oi -> oi_type;
344 struct listaddr *neighbor;
345
346 ifvar = (int) ot -> ot_info;
347 switch (offset) {
348 case type_SNMP_SMUX__PDUs_get__request:
349 if (oid->oid_nelem != ot->ot_name->oid_nelem + 5)
350 return int_SNMP_error__status_noSuchName;
351
352 if ((vifi = oid -> oid_elements[ot-> ot_name->oid_nelem]) >= numvifs)
353 return int_SNMP_error__status_noSuchName;
354
355 if (!get_address(oid, &addr, ot->ot_name->oid_nelem+1))
356 return int_SNMP_error__status_noSuchName;
357
358 if (!(neighbor = find_neighbor(vifi, addr)))
359 return int_SNMP_error__status_noSuchName;
360 break;
361
362 case type_SNMP_SMUX__PDUs_get__next__request:
363 if (oid->oid_nelem < ot->ot_name->oid_nelem + 5) {
364 OID new;
365
366 if (oid->oid_nelem == ot->ot_name->oid_nelem) {
367 vifi = addr = 0;
368 } else {
369 vifi = oid->oid_elements[ot->ot_name->oid_nelem];
370 get_address(oid, &addr, ot->ot_name->oid_nelem+1);
371 }
372
373 neighbor = next_neighbor(&vifi,addr); /* Get first entry */
374 if (!neighbor)
375 return NOTOK;
376
377 new = oid_extend (oid, ot->ot_name->oid_nelem+5-oid->oid_nelem);
378 if (new == NULLOID)
379 return NOTOK;
380 new -> oid_elements[ot->ot_name->oid_nelem] = vifi;
381 put_address(new, neighbor->al_addr, ot->ot_name->oid_nelem+1);
382
383 if (v -> name)
384 free_SNMP_ObjectName (v -> name);
385 v -> name = new;
386
387 } else { /* get next entry given previous */
388 int i = ot -> ot_name -> oid_nelem;
389
390 vifi = oid->oid_elements[i];
391 get_address(oid, &addr, ot->ot_name->oid_nelem+1);
392 if (!(neighbor = next_neighbor(&vifi,addr+1)))
393 return NOTOK;
394
395 put_address(oid, neighbor->al_addr, ot->ot_name->oid_nelem+1);
396 oid->oid_elements[i] = vifi;
397 oid->oid_nelem = i + 5;
398 }
399 break;
400
401 default:
402 return int_SNMP_error__status_genErr;
403 }
404
405 switch (ifvar) {
406
407 case dvmrpNeighborUpTime: {
408 time_t currtime;
409 time(&currtime);
410 return o_integer (oi, v, (currtime - neighbor->al_ctime)*100);
411 }
412
413 case dvmrpNeighborExpiryTime:
414 return o_integer (oi, v, (NEIGHBOR_EXPIRE_TIME-neighbor->al_timer) * 100);
415
416 case dvmrpNeighborVersion: {
417 static char buff[15];
418
419 sprintf(buff, "%d.%d", neighbor->al_pv, neighbor->al_mv);
420 return o_string (oi, v, buff, strlen (buff));
421 }
422
423 case dvmrpNeighborGenerationId:
424 return o_integer (oi, v, neighbor->al_genid);
425
426 default:
427 return int_SNMP_error__status_noSuchName;
428 }
429 }
430
431 /*
432 * Given a virtual interface number, make sure we have the current
433 * kernel information for that Vif.
434 */
435 refresh_vif(v_req, ifnum)
436 struct sioc_vif_req *v_req;
437 int ifnum;
438 {
439 static int lastq = -1;
440
441 if (quantum!=lastq || v_req->vifi != ifnum) {
442 lastq = quantum;
443 v_req->vifi = ifnum;
444 if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)v_req) < 0)
445 v_req->icount = v_req->ocount = v_req->ibytes = v_req->obytes = 0;
446 }
447 }
448
449 /*
450 * Implements the Multicast Routing Interface Table portion of the Multicast MIB
451 */
452 static int
453 o_ipMRouteInterfaceTable (oi, v, offset)
454 OI oi;
455 register struct type_SNMP_VarBind *v;
456 int offset;
457 {
458 int ifnum,
459 ifvar;
460 register OID oid = oi -> oi_name;
461 register OT ot = oi -> oi_type;
462 static struct sioc_vif_req v_req;
463
464 ifvar = (int) ot -> ot_info;
465 switch (offset) {
466 case type_SNMP_SMUX__PDUs_get__request:
467 if (oid -> oid_nelem != ot -> ot_name -> oid_nelem + 1)
468 return int_SNMP_error__status_noSuchName;
469 if ((ifnum = oid -> oid_elements[oid -> oid_nelem - 1]) >= numvifs)
470 return int_SNMP_error__status_noSuchName;
471 break;
472
473 case type_SNMP_SMUX__PDUs_get__next__request:
474 if (oid -> oid_nelem == ot -> ot_name -> oid_nelem) {
475 OID new;
476
477 ifnum = 0;
478
479 if ((new = oid_extend (oid, 1)) == NULLOID)
480 return NOTOK;
481 new -> oid_elements[new -> oid_nelem - 1] = ifnum;
482
483 if (v -> name)
484 free_SNMP_ObjectName (v -> name);
485 v -> name = new;
486
487 } else {
488 int i = ot -> ot_name -> oid_nelem;
489
490 if ((ifnum = oid -> oid_elements[i] + 1) >= numvifs)
491 return NOTOK;
492
493 oid -> oid_elements[i] = ifnum;
494 oid -> oid_nelem = i + 1;
495 }
496 break;
497
498 default:
499 return int_SNMP_error__status_genErr;
500 }
501
502 switch (ifvar) {
503 case ipMRouteInterfaceTtl:
504 return o_integer (oi, v, uvifs[ifnum].uv_threshold);
505
506 case dvmrpVInterfaceType:
507 if (uvifs[ifnum].uv_flags & VIFF_SRCRT)
508 return o_integer (oi, v, 2);
509 else if (uvifs[ifnum].uv_flags & VIFF_TUNNEL)
510 return o_integer (oi, v, 1);
511 else if (uvifs[ifnum].uv_flags & VIFF_QUERIER)
512 return o_integer (oi, v, 3);
513 else /* SUBNET */
514 return o_integer (oi, v, 4);
515
516 case dvmrpVInterfaceState:
517 if (uvifs[ifnum].uv_flags & VIFF_DISABLED)
518 return o_integer (oi, v, 3);
519 else if (uvifs[ifnum].uv_flags & VIFF_DOWN)
520 return o_integer (oi, v, 2);
521 else /* UP */
522 return o_integer (oi, v, 1);
523
524 case dvmrpVInterfaceLocalAddress: {
525 struct sockaddr_in tmp;
526 tmp.sin_addr.s_addr = uvifs[ifnum].uv_lcl_addr;
527 return o_ipaddr (oi, v, &tmp);
528 }
529
530 case dvmrpVInterfaceRemoteAddress: {
531 struct sockaddr_in tmp;
532 tmp.sin_addr.s_addr = (uvifs[ifnum].uv_flags & VIFF_TUNNEL) ?
533 uvifs[ifnum].uv_rmt_addr :
534 uvifs[ifnum].uv_subnet;
535 return o_ipaddr (oi, v, &tmp);
536 }
537
538 case dvmrpVInterfaceRemoteSubnetMask: {
539 struct sockaddr_in tmp;
540 tmp.sin_addr.s_addr = uvifs[ifnum].uv_subnetmask;
541 return o_ipaddr (oi, v, &tmp);
542 }
543
544 case dvmrpVInterfaceMetric:
545 return o_integer (oi, v, uvifs[ifnum].uv_metric);
546
547 case dvmrpVInterfaceRateLimit:
548 return o_integer (oi, v, uvifs[ifnum].uv_rate_limit);
549
550 case dvmrpVInterfaceInPkts:
551 refresh_vif(&v_req, ifnum);
552 return o_integer(oi, v, v_req.icount);
553
554 case dvmrpVInterfaceOutPkts:
555 refresh_vif(&v_req, ifnum);
556 return o_integer(oi, v, v_req.ocount);
557
558 case dvmrpVInterfaceInOctets:
559 refresh_vif(&v_req, ifnum);
560 return o_integer(oi, v, v_req.ibytes);
561
562 case dvmrpVInterfaceOutOctets:
563 refresh_vif(&v_req, ifnum);
564 return o_integer(oi, v, v_req.obytes);
565
566 default:
567 return int_SNMP_error__status_noSuchName;
568 }
569 }
570
571 struct mib_variable {
572 char *name; /* MIB variable name */
573 int (*function)(); /* Function to call */
574 int info; /* Which variable */
575 } mib_vars[] = {
576 "ipMRouteEnable", o_scalar, ipMRouteEnable,
577 "ipMRouteUpstreamNeighbor", o_ipMRouteTable, ipMRouteUpstreamNeighbor,
578 "ipMRouteInIfIndex", o_ipMRouteTable, ipMRouteInIfIndex,
579 "ipMRouteUpTime", o_ipMRouteTable, ipMRouteUpTime,
580 "ipMRouteExpiryTime", o_ipMRouteTable, ipMRouteExpiryTime,
581 "ipMRoutePkts", o_ipMRouteTable, ipMRoutePkts,
582 "ipMRouteDifferentInIfIndexes", o_ipMRouteTable, ipMRouteDifferentInIfIndexes,
583 "ipMRouteOctets", o_ipMRouteTable, ipMRouteOctets,
584 "ipMRouteProtocol", o_ipMRouteTable, ipMRouteProtocol,
585 "ipMRouteNextHopState", o_ipMRouteNextHopTable, ipMRouteNextHopState,
586 "ipMRouteNextHopUpTime", o_ipMRouteNextHopTable, ipMRouteNextHopUpTime,
587 "ipMRouteNextHopExpiryTime", o_ipMRouteNextHopTable, ipMRouteNextHopExpiryTime,
588 "ipMRouteNextHopClosestMemberHops", o_ipMRouteNextHopTable, ipMRouteNextHopClosestMemberHops,
589 "ipMRouteNextHopProtocol", o_ipMRouteNextHopTable, ipMRouteNextHopProtocol,
590 "ipMRouteInterfaceTtl", o_ipMRouteInterfaceTable, ipMRouteInterfaceTtl,
591 "dvmrpVersion", o_scalar, dvmrpVersion,
592 "dvmrpGenerationId", o_scalar, dvmrpGenerationId,
593 "dvmrpVInterfaceType", o_ipMRouteInterfaceTable, dvmrpVInterfaceType,
594 "dvmrpVInterfaceState", o_ipMRouteInterfaceTable, dvmrpVInterfaceState,
595 "dvmrpVInterfaceLocalAddress", o_ipMRouteInterfaceTable, dvmrpVInterfaceLocalAddress,
596 "dvmrpVInterfaceRemoteAddress", o_ipMRouteInterfaceTable, dvmrpVInterfaceRemoteAddress,
597 "dvmrpVInterfaceRemoteSubnetMask", o_ipMRouteInterfaceTable, dvmrpVInterfaceRemoteSubnetMask,
598 "dvmrpVInterfaceMetric", o_ipMRouteInterfaceTable, dvmrpVInterfaceMetric,
599 "dvmrpVInterfaceRateLimit", o_ipMRouteInterfaceTable, dvmrpVInterfaceRateLimit,
600 "dvmrpVInterfaceInPkts", o_ipMRouteInterfaceTable, dvmrpVInterfaceInPkts,
601 "dvmrpVInterfaceOutPkts", o_ipMRouteInterfaceTable, dvmrpVInterfaceOutPkts,
602 "dvmrpVInterfaceInOctets", o_ipMRouteInterfaceTable, dvmrpVInterfaceInOctets,
603 "dvmrpVInterfaceOutOctets", o_ipMRouteInterfaceTable, dvmrpVInterfaceOutOctets,
604 "dvmrpNeighborUpTime", o_dvmrpNeighborTable, dvmrpNeighborUpTime,
605 "dvmrpNeighborExpiryTime", o_dvmrpNeighborTable, dvmrpNeighborExpiryTime,
606 "dvmrpNeighborVersion", o_dvmrpNeighborTable, dvmrpNeighborVersion,
607 "dvmrpNeighborGenerationId",o_dvmrpNeighborTable, dvmrpNeighborGenerationId,
608 "dvmrpRouteUpstreamNeighbor", o_dvmrpRouteTable, dvmrpRouteUpstreamNeighbor,
609 "dvmrpRouteInVifIndex", o_dvmrpRouteTable, dvmrpRouteInVifIndex,
610 "dvmrpRouteMetric", o_dvmrpRouteTable, dvmrpRouteMetric,
611 "dvmrpRouteExpiryTime", o_dvmrpRouteTable, dvmrpRouteExpiryTime,
612 "dvmrpRouteNextHopType", o_dvmrpRouteNextHopTable, dvmrpRouteNextHopType,
613 "dvmrpBoundaryVifIndex", o_dvmrpBoundaryTable, dvmrpBoundaryVifIndex,
614 0, 0, 0
615 };
616
617 /*
618 * Register variables as part of the MIBs
619 */
620 void
621 init_mib()
622 {
623 register OT ot;
624 int i;
625
626 for (i=0; mib_vars[i].name; i++)
627 if (ot=text2obj(mib_vars[i].name)) {
628 ot->ot_getfnx = mib_vars[i].function;
629 ot->ot_info = (caddr_t)mib_vars[i].info;
630 }
631 }
632
633 /*
634 * Initialize the SNMP part of mrouted
635 */
636 void
637 snmp_init()
638 {
639 OT ot;
640 int i;
641
642 if (readobjects("mrouted.defs") == NOTOK)
643 log(LOG_ERR, 0, "readobjects: %s", PY_pepy);
644 for (i=0; i < NUMMIBS; i++) {
645 if ((ot = text2obj(mibs[i])) == NULL)
646 log(LOG_ERR, 0, "object \"%s\" not in \"%s\"",
647 mibs[i], "mrouted.defs");
648 subtree[i] = ot -> ot_name;
649 }
650 init_mib();
651 try_smux_init();
652 }
653
654 /*
655 * Process an SNMP "get" or "get-next" request
656 */
657 static
658 get_smux (pdu, offset)
659 register struct type_SNMP_GetRequest__PDU *pdu;
660 int offset;
661 {
662 int idx,
663 status;
664 object_instance ois;
665 register struct type_SNMP_VarBindList *vp;
666 IFP method;
667
668 quantum = pdu -> request__id;
669 idx = 0;
670 for (vp = pdu -> variable__bindings; vp; vp = vp -> next) {
671 register OI oi;
672 register OT ot;
673 register struct type_SNMP_VarBind *v = vp -> VarBind;
674
675 idx++;
676
677 if (offset == type_SNMP_SMUX__PDUs_get__next__request) {
678 if ((oi = name2inst (v -> name)) == NULLOI
679 && (oi = next2inst (v -> name)) == NULLOI)
680 goto no_name;
681
682 if ((ot = oi -> oi_type) -> ot_getfnx == NULLIFP)
683 goto get_next;
684 }
685 else
686 if ((oi = name2inst (v -> name)) == NULLOI
687 || (ot = oi -> oi_type) -> ot_getfnx
688 == NULLIFP) {
689 no_name: ;
690 pdu -> error__status =
691 int_SNMP_error__status_noSuchName;
692 goto out;
693 }
694
695 try_again: ;
696 switch (offset) {
697 case type_SNMP_SMUX__PDUs_get__request:
698 if (!(method = ot -> ot_getfnx))
699 goto no_name;
700 break;
701
702 case type_SNMP_SMUX__PDUs_get__next__request:
703 if (!(method = ot -> ot_getfnx))
704 goto get_next;
705 break;
706
707 case type_SNMP_SMUX__PDUs_set__request:
708 if (!(method = ot -> ot_setfnx))
709 goto no_name;
710 break;
711
712 default:
713 goto no_name;
714 }
715
716 switch (status = (*ot -> ot_getfnx) (oi, v, offset)) {
717 case NOTOK: /* get-next wants a bump */
718 get_next: ;
719 oi = &ois;
720 for (;;) {
721 if ((ot = ot -> ot_next) == NULLOT) {
722 pdu -> error__status =
723 int_SNMP_error__status_noSuchName;
724 goto out;
725 }
726 oi -> oi_name =
727 (oi -> oi_type = ot) -> ot_name;
728 if (ot -> ot_getfnx)
729 goto try_again;
730 }
731
732 case int_SNMP_error__status_noError:
733 break;
734
735 default:
736 pdu -> error__status = status;
737 goto out;
738 }
739 }
740 idx = 0;
741
742 out: ;
743 pdu -> error__index = idx;
744
745 if (smux_response (pdu) == NOTOK) {
746 log(LOG_WARNING,0,"smux_response: %s [%s]",
747 smux_error (smux_errno), smux_info);
748 smux_fd = NOTOK;
749 }
750 }
751
752 /*
753 * Handle SNMP "set" request by replying that it is illegal
754 */
755 static
756 set_smux(event)
757 struct type_SNMP_SMUX__PDUs *event;
758 {
759 switch (event -> offset) {
760 case type_SNMP_SMUX__PDUs_set__request:
761 {
762 register struct type_SNMP_GetResponse__PDU *pdu =
763 event -> un.get__response;
764
765 pdu -> error__status = int_SNMP_error__status_noSuchName;
766 pdu -> error__index = pdu -> variable__bindings ? 1 : 0;
767
768 if (smux_response (pdu) == NOTOK) {
769 log(LOG_WARNING, 0,
770 "smux_response: %s [%s]",
771 smux_error (smux_errno),
772 smux_info);
773 smux_fd = NOTOK;
774 }
775 }
776 break;
777
778 case type_SNMP_SMUX__PDUs_commitOrRollback:
779 {
780 struct type_SNMP_SOutPDU *cor =
781 event -> un.commitOrRollback;
782
783 if (cor -> parm == int_SNMP_SOutPDU_commit) {
784 /* "should not happen" */
785 (void) smux_close (protocolError);
786 smux_fd = NOTOK;
787 }
788 }
789 break;
790 }
791 }
792
793 /*
794 * Handle an incoming SNMP message
795 */
796 void
797 doit_smux()
798 {
799 struct type_SNMP_SMUX__PDUs *event;
800
801 if (smux_wait(&event, NOTOK)==NOTOK) {
802 if (smux_errno==inProgress)
803 return;
804 log(LOG_WARNING, 0, "smux_wait: %s [%s]", smux_error(smux_errno),
805 smux_info);
806 smux_fd = NOTOK;
807 return;
808 }
809
810 switch (event -> offset) {
811 case type_SNMP_SMUX__PDUs_registerResponse:
812 {
813 struct type_SNMP_RRspPDU *rsp =
814 event -> un.registerResponse;
815
816 if (rsp -> parm == int_SNMP_RRspPDU_failure) {
817 log(LOG_WARNING,0,"SMUX registration of subtree failed");
818 dont_bother_anymore = 1;
819 (void) smux_close (goingDown);
820 break;
821 }
822 }
823 if (smux_trap(NULLOID, int_SNMP_generic__trap_coldStart, 0,
824 (struct type_SNMP_VarBindList *)0) == NOTOK) {
825 log(LOG_WARNING,0,"smux_trap: %s [%s]", smux_error (smux_errno),
826 smux_info);
827 break;
828 }
829 return;
830
831 case type_SNMP_SMUX__PDUs_get__request:
832 case type_SNMP_SMUX__PDUs_get__next__request:
833 get_smux (event -> un.get__request, event -> offset);
834 return;
835
836 case type_SNMP_SMUX__PDUs_close:
837 log(LOG_WARNING, 0, "SMUX close: %s",
838 smux_error (event -> un.close -> parm));
839 break;
840
841 case type_SNMP_SMUX__PDUs_set__request:
842 case type_SNMP_SMUX__PDUs_commitOrRollback:
843 set_smux (event);
844 return;
845
846 default:
847 log(LOG_WARNING,0,"bad SMUX operation: %d", event -> offset);
848 (void) smux_close (protocolError);
849 break;
850 }
851 smux_fd = NOTOK;
852 }
853
854 /*
855 * Inform snmpd that we are here and handling our MIBs
856 */
857 void
858 start_smux()
859 {
860 int i;
861
862 for (i=0; i<NUMMIBS; i++) {
863 if ((se = getsmuxEntrybyname (mibs[i])) == NULL) {
864 log(LOG_WARNING,0,"no SMUX entry for \"%s\"", mibs[i]);
865 return;
866 }
867
868 /* Only open a new connection the first time through */
869 if (!i) {
870 if (smux_simple_open(&se->se_identity, mibs[i],
871 se->se_password, strlen(se->se_password))==NOTOK) {
872 if (smux_errno == inProgress)
873 return;
874
875 log(LOG_WARNING, 0,"smux_simple_open: %s [%s]",
876 smux_error(smux_errno), smux_info);
877 smux_fd = NOTOK;
878 return;
879 }
880 log(LOG_NOTICE,0, "SMUX open: %s \"%s\"",
881 oid2ode (&se->se_identity), se->se_name);
882 rock_and_roll = 1;
883 }
884
885 if (smux_register(subtree[i], -1, readWrite)==NOTOK) {
886 log(LOG_WARNING, 0,"smux_register: %s [%s]", smux_error(smux_errno),
887 smux_info);
888 smux_fd = NOTOK;
889 return;
890 }
891 }
892 log(LOG_NOTICE, 0, "SMUX registered");
893 }
894
895 /*
896 * Implements the DVMRP Route Table portion of the DVMRP MIB
897 */
898 int
899 o_dvmrpRouteTable (oi, v, offset)
900 OI oi;
901 register struct type_SNMP_VarBind *v;
902 int offset;
903 {
904 u_long src, mask;
905 int ifvar;
906 register OID oid = oi -> oi_name;
907 register OT ot = oi -> oi_type;
908 struct rtentry *rt = NULL;
909
910 ifvar = (int) ot -> ot_info;
911 switch (offset) {
912 case type_SNMP_SMUX__PDUs_get__request:
913 if (!get_address(oid, &src, ot->ot_name->oid_nelem)
914 || !get_address(oid, &mask, ot->ot_name->oid_nelem+4)
915 || !(rt = snmp_find_route(src,mask)))
916 return int_SNMP_error__status_noSuchName;
917 break;
918
919 case type_SNMP_SMUX__PDUs_get__next__request:
920
921 /* Check if we're requesting the first row */
922 if (oid->oid_nelem < ot->ot_name->oid_nelem+8) {
923 OID new;
924
925 /* Get partial specification (if any) */
926 get_address(oid, &src, ot->ot_name->oid_nelem);
927 get_address(oid, &mask, ot->ot_name->oid_nelem+4);
928
929 if (!next_route(&rt,src,mask)) /* Get first entry */
930 return NOTOK;
931
932 /* Extend by 8 more ints to hold index columns */
933 new = oid_extend (oid, ot->ot_name->oid_nelem+8-oid->oid_nelem);
934 if (new == NULLOID)
935 return NOTOK;
936
937 put_address(new, rt->rt_origin, ot->ot_name->oid_nelem);
938 put_address(new, rt->rt_originmask, ot->ot_name->oid_nelem+4);
939
940 if (v -> name)
941 free_SNMP_ObjectName (v -> name);
942 v -> name = new;
943
944 /* Else we start from a previous row */
945 } else {
946 int i = ot -> ot_name -> oid_nelem;
947
948 /* Get the lowest entry in the table > the given grp/src/mask */
949 get_address(oid, &src, ot->ot_name->oid_nelem);
950 get_address(oid, &mask, ot->ot_name->oid_nelem+4);
951 if (!next_route(&rt, src,mask))
952 return NOTOK;
953
954 put_address(oid, rt->rt_origin, ot->ot_name->oid_nelem);
955 put_address(oid, rt->rt_originmask, ot->ot_name->oid_nelem+4);
956 }
957 break;
958
959 default:
960 return int_SNMP_error__status_genErr;
961 }
962
963 switch (ifvar) {
964 case dvmrpRouteUpstreamNeighbor: {
965 struct sockaddr_in tmp;
966 tmp.sin_addr.s_addr = rt->rt_gateway;
967 return o_ipaddr (oi, v, &tmp);
968 }
969
970 case dvmrpRouteInVifIndex:
971 return o_integer (oi, v, rt->rt_parent);
972
973 case dvmrpRouteMetric:
974 return o_integer (oi, v, rt->rt_metric);
975
976 case dvmrpRouteExpiryTime:
977 return o_integer (oi, v, rt->rt_timer*100);
978
979 default:
980 return int_SNMP_error__status_noSuchName;
981 }
982 }
983
984 /*
985 * Implements the DVMRP Routing Next Hop Table portion of the DVMRP MIB
986 */
987 int
988 o_dvmrpRouteNextHopTable (oi, v, offset)
989 OI oi;
990 register struct type_SNMP_VarBind *v;
991 int offset;
992 {
993 u_long src, mask;
994 vifi_t vifi;
995 int ifvar;
996 register OID oid = oi -> oi_name;
997 register OT ot = oi -> oi_type;
998 struct rtentry *rt = NULL;
999
1000 ifvar = (int) ot -> ot_info;
1001 switch (offset) {
1002 case type_SNMP_SMUX__PDUs_get__request:
1003 if (oid->oid_nelem != ot->ot_name->oid_nelem+9)
1004 return int_SNMP_error__status_noSuchName;
1005
1006 if (!get_address(oid, &src, ot->ot_name->oid_nelem)
1007 || !get_address(oid, &mask, ot->ot_name->oid_nelem+4)
1008 || (!(rt=snmp_find_route(src,mask))))
1009 return int_SNMP_error__status_noSuchName;
1010
1011 vifi = oid->oid_elements[ot->ot_name->oid_nelem+8];
1012 if (!(VIFM_ISSET(vifi, rt->rt_children)))
1013 return int_SNMP_error__status_noSuchName;
1014 break;
1015
1016 case type_SNMP_SMUX__PDUs_get__next__request:
1017
1018 /* Check if we're requesting the first row */
1019 if (oid->oid_nelem < ot->ot_name->oid_nelem+9) {
1020 OID new;
1021
1022 get_address(oid, &src, ot->ot_name->oid_nelem);
1023 get_address(oid, &mask, ot->ot_name->oid_nelem+4);
1024
1025 /* Find first child vif */
1026 vifi=0;
1027 if (!next_route_child(&rt, src, mask, &vifi))
1028 return NOTOK;
1029
1030 /* Extend by 9 more ints to hold index columns */
1031 new = oid_extend (oid, ot->ot_name->oid_nelem+9-oid->oid_nelem);
1032 if (new == NULLOID)
1033 return NOTOK;
1034
1035 put_address(new, rt->rt_origin, ot->ot_name->oid_nelem);
1036 put_address(new, rt->rt_originmask, ot->ot_name->oid_nelem+4);
1037 new->oid_elements[ot->ot_name->oid_nelem+8] = vifi;
1038
1039 if (v -> name)
1040 free_SNMP_ObjectName (v -> name);
1041 v -> name = new;
1042
1043 /* Else we start from a previous row */
1044 } else {
1045 int i = ot -> ot_name -> oid_nelem;
1046
1047 /* Get the lowest entry in the table > the given grp/src/mask */
1048 vifi = oid->oid_elements[oid->oid_nelem-1] + 1;
1049 if (!get_address(oid, &src, ot->ot_name->oid_nelem)
1050 || !get_address(oid, &mask, ot->ot_name->oid_nelem+4)
1051 || !next_route_child(&rt, src, mask, &vifi))
1052 return NOTOK;
1053
1054 put_address(oid, rt->rt_origin, ot->ot_name->oid_nelem);
1055 put_address(oid, rt->rt_originmask, ot->ot_name->oid_nelem+4);
1056 oid->oid_elements[ot->ot_name->oid_nelem+8] = vifi;
1057 }
1058 break;
1059
1060 default:
1061 return int_SNMP_error__status_genErr;
1062 }
1063
1064 switch (ifvar) {
1065
1066 case dvmrpRouteNextHopType:
1067 return o_integer (oi, v, (VIFM_ISSET(vifi, rt->rt_leaves))? 1 : 2);
1068
1069 default:
1070 return int_SNMP_error__status_noSuchName;
1071 }
1072 }
1073
1074 /*
1075 * Implements the IP Multicast Route Table portion of the Multicast MIB
1076 */
1077 int
1078 o_ipMRouteTable (oi, v, offset)
1079 OI oi;
1080 register struct type_SNMP_VarBind *v;
1081 int offset;
1082 {
1083 u_long src, grp, mask;
1084 int ifvar;
1085 register OID oid = oi -> oi_name;
1086 register OT ot = oi -> oi_type;
1087 struct gtable *gt = NULL;
1088 struct stable *st = NULL;
1089 static struct sioc_sg_req sg_req;
1090
1091 ifvar = (int) ot -> ot_info;
1092 switch (offset) {
1093 case type_SNMP_SMUX__PDUs_get__request:
1094 if (!get_address(oid, &grp, ot->ot_name->oid_nelem)
1095 || !get_address(oid, &src, ot->ot_name->oid_nelem+4)
1096 || !get_address(oid, &mask, ot->ot_name->oid_nelem+8)
1097 || (mask != 0xFFFFFFFF) /* we keep sources now, not subnets */
1098 || !(gt = find_grp(grp))
1099 || !(st = find_grp_src(gt,src)))
1100 return int_SNMP_error__status_noSuchName;
1101 break;
1102
1103 case type_SNMP_SMUX__PDUs_get__next__request:
1104
1105 /* Check if we're requesting the first row */
1106 if (oid->oid_nelem < ot->ot_name->oid_nelem+12) {
1107 OID new;
1108
1109 /* Get partial specification (if any) */
1110 get_address(oid, &grp, ot->ot_name->oid_nelem);
1111 get_address(oid, &src, ot->ot_name->oid_nelem+4);
1112 get_address(oid, &mask, ot->ot_name->oid_nelem+8);
1113
1114 if (!next_grp_src_mask(>,&st,grp,src,mask)) /* Get first entry */
1115 return NOTOK;
1116
1117 /* Extend by 12 more ints to hold index columns */
1118 new = oid_extend (oid, ot->ot_name->oid_nelem+12-oid->oid_nelem);
1119 if (new == NULLOID)
1120 return NOTOK;
1121
1122 put_address(new, gt->gt_mcastgrp, ot->ot_name->oid_nelem);
1123 put_address(new, st->st_origin, ot->ot_name->oid_nelem+4);
1124 put_address(new, 0xFFFFFFFF, ot->ot_name->oid_nelem+8);
1125
1126 if (v -> name)
1127 free_SNMP_ObjectName (v -> name);
1128 v -> name = new;
1129
1130 /* Else we start from a previous row */
1131 } else {
1132 int i = ot -> ot_name -> oid_nelem;
1133
1134 /* Get the lowest entry in the table > the given grp/src/mask */
1135 get_address(oid, &grp, ot->ot_name->oid_nelem);
1136 get_address(oid, &src, ot->ot_name->oid_nelem+4);
1137 get_address(oid, &mask, ot->ot_name->oid_nelem+8);
1138 if (!next_grp_src_mask(>, &st, grp,src,mask))
1139 return NOTOK;
1140
1141 put_address(oid, gt->gt_mcastgrp, ot->ot_name->oid_nelem);
1142 put_address(oid, st->st_origin, ot->ot_name->oid_nelem+4);
1143 put_address(oid, 0xFFFFFFFF, ot->ot_name->oid_nelem+8);
1144 }
1145 break;
1146
1147 default:
1148 return int_SNMP_error__status_genErr;
1149 }
1150
1151 switch (ifvar) {
1152 case ipMRouteUpstreamNeighbor: {
1153 struct sockaddr_in tmp;
1154 tmp.sin_addr.s_addr = gt->gt_route->rt_gateway;
1155 return o_ipaddr (oi, v, &tmp);
1156 }
1157
1158 case ipMRouteInIfIndex:
1159 return o_integer (oi, v, gt->gt_route->rt_parent);
1160
1161 case ipMRouteUpTime: {
1162 time_t currtime;
1163 time(&currtime);
1164 return o_integer (oi, v, (currtime - gt->gt_ctime)*100);
1165 }
1166
1167 case ipMRouteExpiryTime:
1168 return o_integer (oi, v, gt->gt_timer*100);
1169
1170 case ipMRoutePkts:
1171 refresh_sg(&sg_req, gt, st);
1172 return o_integer (oi, v, sg_req.pktcnt);
1173
1174 case ipMRouteOctets:
1175 refresh_sg(&sg_req, gt, st);
1176 return o_integer (oi, v, sg_req.bytecnt);
1177
1178 case ipMRouteDifferentInIfIndexes:
1179 refresh_sg(&sg_req, gt, st);
1180 return o_integer (oi, v, sg_req.wrong_if);
1181
1182 case ipMRouteProtocol:
1183 return o_integer (oi, v, 4);
1184
1185 default:
1186 return int_SNMP_error__status_noSuchName;
1187 }
1188 }
1189
1190 /*
1191 * Implements the IP Multicast Routing Next Hop Table portion of the Multicast
1192 * MIB
1193 */
1194 int
1195 o_ipMRouteNextHopTable (oi, v, offset)
1196 OI oi;
1197 register struct type_SNMP_VarBind *v;
1198 int offset;
1199 {
1200 u_long src, grp, mask, addr;
1201 vifi_t vifi;
1202 int ifvar;
1203 register OID oid = oi -> oi_name;
1204 register OT ot = oi -> oi_type;
1205 struct gtable *gt;
1206 struct stable *st;
1207
1208 ifvar = (int) ot -> ot_info;
1209 switch (offset) {
1210 case type_SNMP_SMUX__PDUs_get__request:
1211 if (oid->oid_nelem != ot->ot_name->oid_nelem+17)
1212 return int_SNMP_error__status_noSuchName;
1213
1214 if (!get_address(oid, &grp, ot->ot_name->oid_nelem)
1215 || !get_address(oid, &src, ot->ot_name->oid_nelem+4)
1216 || !get_address(oid, &mask, ot->ot_name->oid_nelem+8)
1217 || !get_address(oid, &addr, ot->ot_name->oid_nelem+13)
1218 || grp!=addr
1219 || mask!=0xFFFFFFFF
1220 || (!(gt=find_grp(grp)))
1221 || (!(st=find_grp_src(gt,src))))
1222 return int_SNMP_error__status_noSuchName;
1223
1224 vifi = oid->oid_elements[ot->ot_name->oid_nelem+12];
1225 if (!(VIFM_ISSET(vifi, gt->gt_route->rt_children)))
1226 return int_SNMP_error__status_noSuchName;
1227 break;
1228
1229 case type_SNMP_SMUX__PDUs_get__next__request:
1230
1231 /* Check if we're requesting the first row */
1232 if (oid->oid_nelem < ot->ot_name->oid_nelem+17) {
1233 OID new;
1234
1235 get_address(oid, &grp, ot->ot_name->oid_nelem);
1236 get_address(oid, &src, ot->ot_name->oid_nelem+4);
1237 get_address(oid, &mask, ot->ot_name->oid_nelem+8);
1238
1239 /* Find first child vif */
1240 vifi=0;
1241 if (!next_child(>, &st, grp, src, mask, &vifi))
1242 return NOTOK;
1243
1244 /* Extend by 17 more ints to hold index columns */
1245 new = oid_extend (oid, ot->ot_name->oid_nelem+17-oid->oid_nelem);
1246 if (new == NULLOID)
1247 return NOTOK;
1248
1249 put_address(new, gt->gt_mcastgrp, ot->ot_name->oid_nelem);
1250 put_address(new, st->st_origin, ot->ot_name->oid_nelem+4);
1251 put_address(new, 0xFFFFFFFF, ot->ot_name->oid_nelem+8);
1252 new->oid_elements[ot->ot_name->oid_nelem+12] = vifi;
1253 put_address(new, gt->gt_mcastgrp, ot->ot_name->oid_nelem+13);
1254
1255 if (v -> name)
1256 free_SNMP_ObjectName (v -> name);
1257 v -> name = new;
1258
1259 /* Else we start from a previous row */
1260 } else {
1261 int i = ot -> ot_name -> oid_nelem;
1262
1263 /* Get the lowest entry in the table > the given grp/src/mask */
1264 vifi = oid->oid_elements[oid->oid_nelem-1] + 1;
1265 if (!get_address(oid, &grp, ot->ot_name->oid_nelem)
1266 || !get_address(oid, &src, ot->ot_name->oid_nelem+4)
1267 || !get_address(oid, &mask, ot->ot_name->oid_nelem+8)
1268 || !next_child(>, &st, grp, src, mask, &vifi))
1269 return NOTOK;
1270
1271 put_address(oid, gt->gt_mcastgrp, ot->ot_name->oid_nelem);
1272 put_address(oid, st->st_origin, ot->ot_name->oid_nelem+4);
1273 put_address(oid, 0xFFFFFFFF, ot->ot_name->oid_nelem+8);
1274 oid->oid_elements[ot->ot_name->oid_nelem+12] = vifi;
1275 put_address(oid, gt->gt_mcastgrp, ot->ot_name->oid_nelem+13);
1276 }
1277 break;
1278
1279 default:
1280 return int_SNMP_error__status_genErr;
1281 }
1282
1283 switch (ifvar) {
1284
1285 case ipMRouteNextHopState:
1286 return o_integer (oi, v, (VIFM_ISSET(vifi, gt->gt_grpmems))? 2 : 1);
1287
1288 /* Currently equal to ipMRouteUpTime */
1289 case ipMRouteNextHopUpTime: {
1290 time_t currtime;
1291 time(&currtime);
1292 return o_integer (oi, v, (currtime - gt->gt_ctime)*100);
1293 }
1294
1295 case ipMRouteNextHopExpiryTime:
1296 return o_integer (oi, v, gt->gt_prsent_timer);
1297
1298 case ipMRouteNextHopClosestMemberHops:
1299 return o_integer (oi, v, 0);
1300
1301 case ipMRouteNextHopProtocol:
1302 return o_integer (oi, v, 4);
1303
1304 default:
1305 return int_SNMP_error__status_noSuchName;
1306 }
1307 }
1308