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