/* * snmp.c * * Code written by David Thaler * Moved to a seperate file by Bill Fenner */ #include "defs.h" #include #include "snmp.h" #define NUMMIBS 2 #define SNMPD_RETRY_INTERVAL 300 /* periodic snmpd probe interval */ char *mibs[]={ "ipMRouteMIB", "dvmrpMIB" }; extern int o_ipMRouteTable(); extern int o_ipMRouteNextHopTable(); extern int o_dvmrpRouteTable(); extern int o_dvmrpRouteNextHopTable(); int smux_fd = NOTOK; int rock_and_roll = 0; int dont_bother_anymore = 0; int quantum = 0; static OID subtree[NUMMIBS] = NULLOID; static struct smuxEntry *se = NULL; extern int smux_errno; extern char smux_info[BUFSIZ]; /* * Place an IP address into an OID starting at element n */ void put_address(oid, addr, n) OID oid; u_long addr; int n; { int i; for (i=n+3; i>=n+0; i--) { oid->oid_elements[i] = addr & 0xFF; addr >>= 8; } } /* Get an IP address from an OID starting at element n */ int get_address(oid, addr, n) OID oid; u_long *addr; int n; { int i; int ok = 1; (*addr) = 0; if (oid -> oid_nelem < n+4) return 0; for (i=n; i= oid->oid_nelem) ok = 0; else (*addr) |= oid->oid_elements[i]; } return ok; } /* * Attempt to start up SMUX protocol */ void try_smux_init() { if (smux_fd != NOTOK || dont_bother_anymore) return; if ((smux_fd = smux_init(debug)) == NOTOK) { log(LOG_WARNING, 0,"smux_init: %s [%s]", smux_error(smux_errno), smux_info); } else rock_and_roll = 0; } /* * Implements scalar objects from both MIBs */ static int o_scalar(oi, v, offset) OI oi; register struct type_SNMP_VarBind *v; int offset; { int ifvar; register OID oid = oi -> oi_name; register OT ot = oi -> oi_type; ifvar = (int) ot -> ot_info; switch (offset) { case type_SNMP_SMUX__PDUs_get__request: if (oid -> oid_nelem != ot -> ot_name -> oid_nelem + 1 || oid -> oid_elements[oid -> oid_nelem - 1] != 0) return int_SNMP_error__status_noSuchName; break; case type_SNMP_SMUX__PDUs_get__next__request: if (oid -> oid_nelem == ot -> ot_name -> oid_nelem) { OID new; if ((new = oid_extend (oid, 1)) == NULLOID) return int_SNMP_error__status_genErr; new -> oid_elements[new -> oid_nelem - 1] = 0; if (v -> name) free_SNMP_ObjectName (v -> name); v -> name = new; } else return NOTOK; break; default: return int_SNMP_error__status_genErr; } switch (ifvar) { case ipMRouteEnable: return o_integer (oi, v, 1); case dvmrpVersion: { static char buff[15]; sprintf(buff, "mrouted%d.%d", PROTOCOL_VERSION, MROUTED_VERSION); return o_string (oi, v, buff, strlen (buff)); } case dvmrpGenerationId: return o_integer (oi, v, dvmrp_genid); default: return int_SNMP_error__status_noSuchName; } } /* * Find if a specific scoped boundary exists on a Vif */ struct vif_acl * find_boundary(vifi, addr, mask) int vifi; int addr; int mask; { struct vif_acl *n; for (n = uvifs[vifi].uv_acl; n != NULL; n = n->acl_next) { if (addr == n->acl_addr && mask==n->acl_mask) return n; } return NULL; } /* * Find the next scoped boundary in order after a given spec */ struct vif_acl * next_boundary(vifi, addr, mask) int *vifi; int addr; int mask; { struct vif_acl *bestn, *n; int i; for (i = *vifi; i < numvifs; i++) { bestn = NULL; for (n = uvifs[i].uv_acl; n; n=n->acl_next) { if ((i > *vifi || n->acl_addr > addr || (n->acl_addr==addr && n->acl_mask>mask)) && (!bestn || n->acl_addr < bestn->acl_addr || (n->acl_addr==bestn->acl_addr && n->acl_maskacl_mask))) bestn = n; } if (bestn) { *vifi = i; return bestn; } } return NULL; } /* * Implements the Boundary Table portion of the DVMRP MIB */ static int o_dvmrpBoundaryTable (oi, v, offset) OI oi; register struct type_SNMP_VarBind *v; { int ifvar, vifi, addr, mask; register OID oid = oi -> oi_name; register OT ot = oi -> oi_type; struct vif_acl *bound; ifvar = (int) ot -> ot_info; switch (offset) { case type_SNMP_SMUX__PDUs_get__request: if (oid->oid_nelem != ot->ot_name->oid_nelem + 9) return int_SNMP_error__status_noSuchName; if ((vifi = oid -> oid_elements[ot-> ot_name->oid_nelem]) >= numvifs) return int_SNMP_error__status_noSuchName; if (!get_address(oid, &addr, ot->ot_name->oid_nelem+1) || !get_address(oid, &mask, ot->ot_name->oid_nelem+5)) return int_SNMP_error__status_noSuchName; if (!(bound = find_boundary(vifi, addr, mask))) return int_SNMP_error__status_noSuchName; break; case type_SNMP_SMUX__PDUs_get__next__request: if (oid->oid_nelem < ot->ot_name->oid_nelem + 9) { OID new; if (oid->oid_nelem == ot->ot_name->oid_nelem) { vifi = addr = mask = 0; } else { vifi = oid->oid_elements[ot->ot_name->oid_nelem]; get_address(oid, &addr, ot->ot_name->oid_nelem+1); get_address(oid, &mask, ot->ot_name->oid_nelem+5); } bound = next_boundary(&vifi,addr,mask); if (!bound) return NOTOK; new = oid_extend (oid, ot->ot_name->oid_nelem+9-oid->oid_nelem); if (new == NULLOID) return NOTOK; new -> oid_elements[ot->ot_name->oid_nelem] = vifi; put_address(new, bound->acl_addr, ot->ot_name->oid_nelem+1); put_address(new, bound->acl_mask, ot->ot_name->oid_nelem+5); if (v -> name) free_SNMP_ObjectName (v -> name); v -> name = new; } else { /* get next entry given previous */ int i = ot -> ot_name -> oid_nelem; vifi = oid->oid_elements[i]; get_address(oid, &addr, ot->ot_name->oid_nelem+1); get_address(oid, &mask, ot->ot_name->oid_nelem+5); if (!(bound = next_boundary(&vifi,addr,mask+1))) return NOTOK; put_address(oid, bound->acl_addr, ot->ot_name->oid_nelem+1); put_address(oid, bound->acl_mask, ot->ot_name->oid_nelem+5); oid->oid_elements[i] = vifi; oid->oid_nelem = i + 9; } break; default: return int_SNMP_error__status_genErr; } switch (ifvar) { case dvmrpBoundaryVifIndex: return o_integer (oi, v, vifi); default: return int_SNMP_error__status_noSuchName; } } /* * Given a vif index and address, return the next greater neighbor entry */ struct listaddr * next_neighbor(vifi, addr) int *vifi; int addr; { struct listaddr *bestn, *n; int i; for (i = *vifi; i < numvifs; i++) { bestn = NULL; for (n = uvifs[i].uv_neighbors; n; n=n->al_next) { if ((i > *vifi || n->al_addr > addr) && (!bestn || n->al_addr < bestn->al_addr)) bestn = n; } if (bestn) { *vifi = i; return bestn; } } return NULL; } /* * Find a neighbor, if it exists off a given Vif */ struct listaddr * find_neighbor(vifi, addr) int vifi; int addr; { struct listaddr *n; for (n = uvifs[vifi].uv_neighbors; n != NULL; n = n->al_next) { if (addr == n->al_addr) return n; } return NULL; } /* * Implements the Neighbor Table portion of the DVMRP MIB */ static int o_dvmrpNeighborTable (oi, v, offset) OI oi; register struct type_SNMP_VarBind *v; { int ifvar, vifi, addr; register OID oid = oi -> oi_name; register OT ot = oi -> oi_type; struct listaddr *neighbor; ifvar = (int) ot -> ot_info; switch (offset) { case type_SNMP_SMUX__PDUs_get__request: if (oid->oid_nelem != ot->ot_name->oid_nelem + 5) return int_SNMP_error__status_noSuchName; if ((vifi = oid -> oid_elements[ot-> ot_name->oid_nelem]) >= numvifs) return int_SNMP_error__status_noSuchName; if (!get_address(oid, &addr, ot->ot_name->oid_nelem+1)) return int_SNMP_error__status_noSuchName; if (!(neighbor = find_neighbor(vifi, addr))) return int_SNMP_error__status_noSuchName; break; case type_SNMP_SMUX__PDUs_get__next__request: if (oid->oid_nelem < ot->ot_name->oid_nelem + 5) { OID new; if (oid->oid_nelem == ot->ot_name->oid_nelem) { vifi = addr = 0; } else { vifi = oid->oid_elements[ot->ot_name->oid_nelem]; get_address(oid, &addr, ot->ot_name->oid_nelem+1); } neighbor = next_neighbor(&vifi,addr); /* Get first entry */ if (!neighbor) return NOTOK; new = oid_extend (oid, ot->ot_name->oid_nelem+5-oid->oid_nelem); if (new == NULLOID) return NOTOK; new -> oid_elements[ot->ot_name->oid_nelem] = vifi; put_address(new, neighbor->al_addr, ot->ot_name->oid_nelem+1); if (v -> name) free_SNMP_ObjectName (v -> name); v -> name = new; } else { /* get next entry given previous */ int i = ot -> ot_name -> oid_nelem; vifi = oid->oid_elements[i]; get_address(oid, &addr, ot->ot_name->oid_nelem+1); if (!(neighbor = next_neighbor(&vifi,addr+1))) return NOTOK; put_address(oid, neighbor->al_addr, ot->ot_name->oid_nelem+1); oid->oid_elements[i] = vifi; oid->oid_nelem = i + 5; } break; default: return int_SNMP_error__status_genErr; } switch (ifvar) { case dvmrpNeighborUpTime: { time_t currtime; time(&currtime); return o_integer (oi, v, (currtime - neighbor->al_ctime)*100); } case dvmrpNeighborExpiryTime: return o_integer (oi, v, (NEIGHBOR_EXPIRE_TIME-neighbor->al_timer) * 100); case dvmrpNeighborVersion: { static char buff[15]; sprintf(buff, "%d.%d", neighbor->al_pv, neighbor->al_mv); return o_string (oi, v, buff, strlen (buff)); } case dvmrpNeighborGenerationId: return o_integer (oi, v, neighbor->al_genid); default: return int_SNMP_error__status_noSuchName; } } /* * Given a virtual interface number, make sure we have the current * kernel information for that Vif. */ refresh_vif(v_req, ifnum) struct sioc_vif_req *v_req; int ifnum; { static int lastq = -1; if (quantum!=lastq || v_req->vifi != ifnum) { lastq = quantum; v_req->vifi = ifnum; if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)v_req) < 0) v_req->icount = v_req->ocount = v_req->ibytes = v_req->obytes = 0; } } /* * Implements the Multicast Routing Interface Table portion of the Multicast MIB */ static int o_ipMRouteInterfaceTable (oi, v, offset) OI oi; register struct type_SNMP_VarBind *v; int offset; { int ifnum, ifvar; register OID oid = oi -> oi_name; register OT ot = oi -> oi_type; static struct sioc_vif_req v_req; ifvar = (int) ot -> ot_info; switch (offset) { case type_SNMP_SMUX__PDUs_get__request: if (oid -> oid_nelem != ot -> ot_name -> oid_nelem + 1) return int_SNMP_error__status_noSuchName; if ((ifnum = oid -> oid_elements[oid -> oid_nelem - 1]) >= numvifs) return int_SNMP_error__status_noSuchName; break; case type_SNMP_SMUX__PDUs_get__next__request: if (oid -> oid_nelem == ot -> ot_name -> oid_nelem) { OID new; ifnum = 0; if ((new = oid_extend (oid, 1)) == NULLOID) return NOTOK; new -> oid_elements[new -> oid_nelem - 1] = ifnum; if (v -> name) free_SNMP_ObjectName (v -> name); v -> name = new; } else { int i = ot -> ot_name -> oid_nelem; if ((ifnum = oid -> oid_elements[i] + 1) >= numvifs) return NOTOK; oid -> oid_elements[i] = ifnum; oid -> oid_nelem = i + 1; } break; default: return int_SNMP_error__status_genErr; } switch (ifvar) { case ipMRouteInterfaceTtl: return o_integer (oi, v, uvifs[ifnum].uv_threshold); case dvmrpVInterfaceType: if (uvifs[ifnum].uv_flags & VIFF_SRCRT) return o_integer (oi, v, 2); else if (uvifs[ifnum].uv_flags & VIFF_TUNNEL) return o_integer (oi, v, 1); else if (uvifs[ifnum].uv_flags & VIFF_QUERIER) return o_integer (oi, v, 3); else /* SUBNET */ return o_integer (oi, v, 4); case dvmrpVInterfaceState: if (uvifs[ifnum].uv_flags & VIFF_DISABLED) return o_integer (oi, v, 3); else if (uvifs[ifnum].uv_flags & VIFF_DOWN) return o_integer (oi, v, 2); else /* UP */ return o_integer (oi, v, 1); case dvmrpVInterfaceLocalAddress: { struct sockaddr_in tmp; tmp.sin_addr.s_addr = uvifs[ifnum].uv_lcl_addr; return o_ipaddr (oi, v, &tmp); } case dvmrpVInterfaceRemoteAddress: { struct sockaddr_in tmp; tmp.sin_addr.s_addr = (uvifs[ifnum].uv_flags & VIFF_TUNNEL) ? uvifs[ifnum].uv_rmt_addr : uvifs[ifnum].uv_subnet; return o_ipaddr (oi, v, &tmp); } case dvmrpVInterfaceRemoteSubnetMask: { struct sockaddr_in tmp; tmp.sin_addr.s_addr = uvifs[ifnum].uv_subnetmask; return o_ipaddr (oi, v, &tmp); } case dvmrpVInterfaceMetric: return o_integer (oi, v, uvifs[ifnum].uv_metric); case dvmrpVInterfaceRateLimit: return o_integer (oi, v, uvifs[ifnum].uv_rate_limit); case dvmrpVInterfaceInPkts: refresh_vif(&v_req, ifnum); return o_integer(oi, v, v_req.icount); case dvmrpVInterfaceOutPkts: refresh_vif(&v_req, ifnum); return o_integer(oi, v, v_req.ocount); case dvmrpVInterfaceInOctets: refresh_vif(&v_req, ifnum); return o_integer(oi, v, v_req.ibytes); case dvmrpVInterfaceOutOctets: refresh_vif(&v_req, ifnum); return o_integer(oi, v, v_req.obytes); default: return int_SNMP_error__status_noSuchName; } } struct mib_variable { char *name; /* MIB variable name */ int (*function)(); /* Function to call */ int info; /* Which variable */ } mib_vars[] = { "ipMRouteEnable", o_scalar, ipMRouteEnable, "ipMRouteUpstreamNeighbor", o_ipMRouteTable, ipMRouteUpstreamNeighbor, "ipMRouteInIfIndex", o_ipMRouteTable, ipMRouteInIfIndex, "ipMRouteUpTime", o_ipMRouteTable, ipMRouteUpTime, "ipMRouteExpiryTime", o_ipMRouteTable, ipMRouteExpiryTime, "ipMRoutePkts", o_ipMRouteTable, ipMRoutePkts, "ipMRouteDifferentInIfIndexes", o_ipMRouteTable, ipMRouteDifferentInIfIndexes, "ipMRouteOctets", o_ipMRouteTable, ipMRouteOctets, "ipMRouteProtocol", o_ipMRouteTable, ipMRouteProtocol, "ipMRouteNextHopState", o_ipMRouteNextHopTable, ipMRouteNextHopState, "ipMRouteNextHopUpTime", o_ipMRouteNextHopTable, ipMRouteNextHopUpTime, "ipMRouteNextHopExpiryTime", o_ipMRouteNextHopTable, ipMRouteNextHopExpiryTime, "ipMRouteNextHopClosestMemberHops", o_ipMRouteNextHopTable, ipMRouteNextHopClosestMemberHops, "ipMRouteNextHopProtocol", o_ipMRouteNextHopTable, ipMRouteNextHopProtocol, "ipMRouteInterfaceTtl", o_ipMRouteInterfaceTable, ipMRouteInterfaceTtl, "dvmrpVersion", o_scalar, dvmrpVersion, "dvmrpGenerationId", o_scalar, dvmrpGenerationId, "dvmrpVInterfaceType", o_ipMRouteInterfaceTable, dvmrpVInterfaceType, "dvmrpVInterfaceState", o_ipMRouteInterfaceTable, dvmrpVInterfaceState, "dvmrpVInterfaceLocalAddress", o_ipMRouteInterfaceTable, dvmrpVInterfaceLocalAddress, "dvmrpVInterfaceRemoteAddress", o_ipMRouteInterfaceTable, dvmrpVInterfaceRemoteAddress, "dvmrpVInterfaceRemoteSubnetMask", o_ipMRouteInterfaceTable, dvmrpVInterfaceRemoteSubnetMask, "dvmrpVInterfaceMetric", o_ipMRouteInterfaceTable, dvmrpVInterfaceMetric, "dvmrpVInterfaceRateLimit", o_ipMRouteInterfaceTable, dvmrpVInterfaceRateLimit, "dvmrpVInterfaceInPkts", o_ipMRouteInterfaceTable, dvmrpVInterfaceInPkts, "dvmrpVInterfaceOutPkts", o_ipMRouteInterfaceTable, dvmrpVInterfaceOutPkts, "dvmrpVInterfaceInOctets", o_ipMRouteInterfaceTable, dvmrpVInterfaceInOctets, "dvmrpVInterfaceOutOctets", o_ipMRouteInterfaceTable, dvmrpVInterfaceOutOctets, "dvmrpNeighborUpTime", o_dvmrpNeighborTable, dvmrpNeighborUpTime, "dvmrpNeighborExpiryTime", o_dvmrpNeighborTable, dvmrpNeighborExpiryTime, "dvmrpNeighborVersion", o_dvmrpNeighborTable, dvmrpNeighborVersion, "dvmrpNeighborGenerationId",o_dvmrpNeighborTable, dvmrpNeighborGenerationId, "dvmrpRouteUpstreamNeighbor", o_dvmrpRouteTable, dvmrpRouteUpstreamNeighbor, "dvmrpRouteInVifIndex", o_dvmrpRouteTable, dvmrpRouteInVifIndex, "dvmrpRouteMetric", o_dvmrpRouteTable, dvmrpRouteMetric, "dvmrpRouteExpiryTime", o_dvmrpRouteTable, dvmrpRouteExpiryTime, "dvmrpRouteNextHopType", o_dvmrpRouteNextHopTable, dvmrpRouteNextHopType, "dvmrpBoundaryVifIndex", o_dvmrpBoundaryTable, dvmrpBoundaryVifIndex, 0, 0, 0 }; /* * Register variables as part of the MIBs */ void init_mib() { register OT ot; int i; for (i=0; mib_vars[i].name; i++) if (ot=text2obj(mib_vars[i].name)) { ot->ot_getfnx = mib_vars[i].function; ot->ot_info = (caddr_t)mib_vars[i].info; } } /* * Initialize the SNMP part of mrouted */ void snmp_init() { OT ot; int i; if (readobjects("mrouted.defs") == NOTOK) log(LOG_ERR, 0, "readobjects: %s", PY_pepy); for (i=0; i < NUMMIBS; i++) { if ((ot = text2obj(mibs[i])) == NULL) log(LOG_ERR, 0, "object \"%s\" not in \"%s\"", mibs[i], "mrouted.defs"); subtree[i] = ot -> ot_name; } init_mib(); try_smux_init(); } /* * Process an SNMP "get" or "get-next" request */ static get_smux (pdu, offset) register struct type_SNMP_GetRequest__PDU *pdu; int offset; { int idx, status; object_instance ois; register struct type_SNMP_VarBindList *vp; IFP method; quantum = pdu -> request__id; idx = 0; for (vp = pdu -> variable__bindings; vp; vp = vp -> next) { register OI oi; register OT ot; register struct type_SNMP_VarBind *v = vp -> VarBind; idx++; if (offset == type_SNMP_SMUX__PDUs_get__next__request) { if ((oi = name2inst (v -> name)) == NULLOI && (oi = next2inst (v -> name)) == NULLOI) goto no_name; if ((ot = oi -> oi_type) -> ot_getfnx == NULLIFP) goto get_next; } else if ((oi = name2inst (v -> name)) == NULLOI || (ot = oi -> oi_type) -> ot_getfnx == NULLIFP) { no_name: ; pdu -> error__status = int_SNMP_error__status_noSuchName; goto out; } try_again: ; switch (offset) { case type_SNMP_SMUX__PDUs_get__request: if (!(method = ot -> ot_getfnx)) goto no_name; break; case type_SNMP_SMUX__PDUs_get__next__request: if (!(method = ot -> ot_getfnx)) goto get_next; break; case type_SNMP_SMUX__PDUs_set__request: if (!(method = ot -> ot_setfnx)) goto no_name; break; default: goto no_name; } switch (status = (*ot -> ot_getfnx) (oi, v, offset)) { case NOTOK: /* get-next wants a bump */ get_next: ; oi = &ois; for (;;) { if ((ot = ot -> ot_next) == NULLOT) { pdu -> error__status = int_SNMP_error__status_noSuchName; goto out; } oi -> oi_name = (oi -> oi_type = ot) -> ot_name; if (ot -> ot_getfnx) goto try_again; } case int_SNMP_error__status_noError: break; default: pdu -> error__status = status; goto out; } } idx = 0; out: ; pdu -> error__index = idx; if (smux_response (pdu) == NOTOK) { log(LOG_WARNING,0,"smux_response: %s [%s]", smux_error (smux_errno), smux_info); smux_fd = NOTOK; } } /* * Handle SNMP "set" request by replying that it is illegal */ static set_smux(event) struct type_SNMP_SMUX__PDUs *event; { switch (event -> offset) { case type_SNMP_SMUX__PDUs_set__request: { register struct type_SNMP_GetResponse__PDU *pdu = event -> un.get__response; pdu -> error__status = int_SNMP_error__status_noSuchName; pdu -> error__index = pdu -> variable__bindings ? 1 : 0; if (smux_response (pdu) == NOTOK) { log(LOG_WARNING, 0, "smux_response: %s [%s]", smux_error (smux_errno), smux_info); smux_fd = NOTOK; } } break; case type_SNMP_SMUX__PDUs_commitOrRollback: { struct type_SNMP_SOutPDU *cor = event -> un.commitOrRollback; if (cor -> parm == int_SNMP_SOutPDU_commit) { /* "should not happen" */ (void) smux_close (protocolError); smux_fd = NOTOK; } } break; } } /* * Handle an incoming SNMP message */ void doit_smux() { struct type_SNMP_SMUX__PDUs *event; if (smux_wait(&event, NOTOK)==NOTOK) { if (smux_errno==inProgress) return; log(LOG_WARNING, 0, "smux_wait: %s [%s]", smux_error(smux_errno), smux_info); smux_fd = NOTOK; return; } switch (event -> offset) { case type_SNMP_SMUX__PDUs_registerResponse: { struct type_SNMP_RRspPDU *rsp = event -> un.registerResponse; if (rsp -> parm == int_SNMP_RRspPDU_failure) { log(LOG_WARNING,0,"SMUX registration of subtree failed"); dont_bother_anymore = 1; (void) smux_close (goingDown); break; } } if (smux_trap(NULLOID, int_SNMP_generic__trap_coldStart, 0, (struct type_SNMP_VarBindList *)0) == NOTOK) { log(LOG_WARNING,0,"smux_trap: %s [%s]", smux_error (smux_errno), smux_info); break; } return; case type_SNMP_SMUX__PDUs_get__request: case type_SNMP_SMUX__PDUs_get__next__request: get_smux (event -> un.get__request, event -> offset); return; case type_SNMP_SMUX__PDUs_close: log(LOG_WARNING, 0, "SMUX close: %s", smux_error (event -> un.close -> parm)); break; case type_SNMP_SMUX__PDUs_set__request: case type_SNMP_SMUX__PDUs_commitOrRollback: set_smux (event); return; default: log(LOG_WARNING,0,"bad SMUX operation: %d", event -> offset); (void) smux_close (protocolError); break; } smux_fd = NOTOK; } /* * Inform snmpd that we are here and handling our MIBs */ void start_smux() { int i; for (i=0; ise_identity, mibs[i], se->se_password, strlen(se->se_password))==NOTOK) { if (smux_errno == inProgress) return; log(LOG_WARNING, 0,"smux_simple_open: %s [%s]", smux_error(smux_errno), smux_info); smux_fd = NOTOK; return; } log(LOG_NOTICE,0, "SMUX open: %s \"%s\"", oid2ode (&se->se_identity), se->se_name); rock_and_roll = 1; } if (smux_register(subtree[i], -1, readWrite)==NOTOK) { log(LOG_WARNING, 0,"smux_register: %s [%s]", smux_error(smux_errno), smux_info); smux_fd = NOTOK; return; } } log(LOG_NOTICE, 0, "SMUX registered"); } /* * Implements the DVMRP Route Table portion of the DVMRP MIB */ int o_dvmrpRouteTable (oi, v, offset) OI oi; register struct type_SNMP_VarBind *v; int offset; { u_long src, mask; int ifvar; register OID oid = oi -> oi_name; register OT ot = oi -> oi_type; struct rtentry *rt = NULL; ifvar = (int) ot -> ot_info; switch (offset) { case type_SNMP_SMUX__PDUs_get__request: if (!get_address(oid, &src, ot->ot_name->oid_nelem) || !get_address(oid, &mask, ot->ot_name->oid_nelem+4) || !(rt = snmp_find_route(src,mask))) return int_SNMP_error__status_noSuchName; break; case type_SNMP_SMUX__PDUs_get__next__request: /* Check if we're requesting the first row */ if (oid->oid_nelem < ot->ot_name->oid_nelem+8) { OID new; /* Get partial specification (if any) */ get_address(oid, &src, ot->ot_name->oid_nelem); get_address(oid, &mask, ot->ot_name->oid_nelem+4); if (!next_route(&rt,src,mask)) /* Get first entry */ return NOTOK; /* Extend by 8 more ints to hold index columns */ new = oid_extend (oid, ot->ot_name->oid_nelem+8-oid->oid_nelem); if (new == NULLOID) return NOTOK; put_address(new, rt->rt_origin, ot->ot_name->oid_nelem); put_address(new, rt->rt_originmask, ot->ot_name->oid_nelem+4); if (v -> name) free_SNMP_ObjectName (v -> name); v -> name = new; /* Else we start from a previous row */ } else { int i = ot -> ot_name -> oid_nelem; /* Get the lowest entry in the table > the given grp/src/mask */ get_address(oid, &src, ot->ot_name->oid_nelem); get_address(oid, &mask, ot->ot_name->oid_nelem+4); if (!next_route(&rt, src,mask)) return NOTOK; put_address(oid, rt->rt_origin, ot->ot_name->oid_nelem); put_address(oid, rt->rt_originmask, ot->ot_name->oid_nelem+4); } break; default: return int_SNMP_error__status_genErr; } switch (ifvar) { case dvmrpRouteUpstreamNeighbor: { struct sockaddr_in tmp; tmp.sin_addr.s_addr = rt->rt_gateway; return o_ipaddr (oi, v, &tmp); } case dvmrpRouteInVifIndex: return o_integer (oi, v, rt->rt_parent); case dvmrpRouteMetric: return o_integer (oi, v, rt->rt_metric); case dvmrpRouteExpiryTime: return o_integer (oi, v, rt->rt_timer*100); default: return int_SNMP_error__status_noSuchName; } } /* * Implements the DVMRP Routing Next Hop Table portion of the DVMRP MIB */ int o_dvmrpRouteNextHopTable (oi, v, offset) OI oi; register struct type_SNMP_VarBind *v; int offset; { u_long src, mask; vifi_t vifi; int ifvar; register OID oid = oi -> oi_name; register OT ot = oi -> oi_type; struct rtentry *rt = NULL; ifvar = (int) ot -> ot_info; switch (offset) { case type_SNMP_SMUX__PDUs_get__request: if (oid->oid_nelem != ot->ot_name->oid_nelem+9) return int_SNMP_error__status_noSuchName; if (!get_address(oid, &src, ot->ot_name->oid_nelem) || !get_address(oid, &mask, ot->ot_name->oid_nelem+4) || (!(rt=snmp_find_route(src,mask)))) return int_SNMP_error__status_noSuchName; vifi = oid->oid_elements[ot->ot_name->oid_nelem+8]; if (!(VIFM_ISSET(vifi, rt->rt_children))) return int_SNMP_error__status_noSuchName; break; case type_SNMP_SMUX__PDUs_get__next__request: /* Check if we're requesting the first row */ if (oid->oid_nelem < ot->ot_name->oid_nelem+9) { OID new; get_address(oid, &src, ot->ot_name->oid_nelem); get_address(oid, &mask, ot->ot_name->oid_nelem+4); /* Find first child vif */ vifi=0; if (!next_route_child(&rt, src, mask, &vifi)) return NOTOK; /* Extend by 9 more ints to hold index columns */ new = oid_extend (oid, ot->ot_name->oid_nelem+9-oid->oid_nelem); if (new == NULLOID) return NOTOK; put_address(new, rt->rt_origin, ot->ot_name->oid_nelem); put_address(new, rt->rt_originmask, ot->ot_name->oid_nelem+4); new->oid_elements[ot->ot_name->oid_nelem+8] = vifi; if (v -> name) free_SNMP_ObjectName (v -> name); v -> name = new; /* Else we start from a previous row */ } else { int i = ot -> ot_name -> oid_nelem; /* Get the lowest entry in the table > the given grp/src/mask */ vifi = oid->oid_elements[oid->oid_nelem-1] + 1; if (!get_address(oid, &src, ot->ot_name->oid_nelem) || !get_address(oid, &mask, ot->ot_name->oid_nelem+4) || !next_route_child(&rt, src, mask, &vifi)) return NOTOK; put_address(oid, rt->rt_origin, ot->ot_name->oid_nelem); put_address(oid, rt->rt_originmask, ot->ot_name->oid_nelem+4); oid->oid_elements[ot->ot_name->oid_nelem+8] = vifi; } break; default: return int_SNMP_error__status_genErr; } switch (ifvar) { case dvmrpRouteNextHopType: return o_integer (oi, v, (VIFM_ISSET(vifi, rt->rt_leaves))? 1 : 2); default: return int_SNMP_error__status_noSuchName; } } /* * Implements the IP Multicast Route Table portion of the Multicast MIB */ int o_ipMRouteTable (oi, v, offset) OI oi; register struct type_SNMP_VarBind *v; int offset; { u_long src, grp, mask; int ifvar; register OID oid = oi -> oi_name; register OT ot = oi -> oi_type; struct gtable *gt = NULL; struct stable *st = NULL; static struct sioc_sg_req sg_req; ifvar = (int) ot -> ot_info; switch (offset) { case type_SNMP_SMUX__PDUs_get__request: if (!get_address(oid, &grp, ot->ot_name->oid_nelem) || !get_address(oid, &src, ot->ot_name->oid_nelem+4) || !get_address(oid, &mask, ot->ot_name->oid_nelem+8) || (mask != 0xFFFFFFFF) /* we keep sources now, not subnets */ || !(gt = find_grp(grp)) || !(st = find_grp_src(gt,src))) return int_SNMP_error__status_noSuchName; break; case type_SNMP_SMUX__PDUs_get__next__request: /* Check if we're requesting the first row */ if (oid->oid_nelem < ot->ot_name->oid_nelem+12) { OID new; /* Get partial specification (if any) */ get_address(oid, &grp, ot->ot_name->oid_nelem); get_address(oid, &src, ot->ot_name->oid_nelem+4); get_address(oid, &mask, ot->ot_name->oid_nelem+8); if (!next_grp_src_mask(>,&st,grp,src,mask)) /* Get first entry */ return NOTOK; /* Extend by 12 more ints to hold index columns */ new = oid_extend (oid, ot->ot_name->oid_nelem+12-oid->oid_nelem); if (new == NULLOID) return NOTOK; put_address(new, gt->gt_mcastgrp, ot->ot_name->oid_nelem); put_address(new, st->st_origin, ot->ot_name->oid_nelem+4); put_address(new, 0xFFFFFFFF, ot->ot_name->oid_nelem+8); if (v -> name) free_SNMP_ObjectName (v -> name); v -> name = new; /* Else we start from a previous row */ } else { int i = ot -> ot_name -> oid_nelem; /* Get the lowest entry in the table > the given grp/src/mask */ get_address(oid, &grp, ot->ot_name->oid_nelem); get_address(oid, &src, ot->ot_name->oid_nelem+4); get_address(oid, &mask, ot->ot_name->oid_nelem+8); if (!next_grp_src_mask(>, &st, grp,src,mask)) return NOTOK; put_address(oid, gt->gt_mcastgrp, ot->ot_name->oid_nelem); put_address(oid, st->st_origin, ot->ot_name->oid_nelem+4); put_address(oid, 0xFFFFFFFF, ot->ot_name->oid_nelem+8); } break; default: return int_SNMP_error__status_genErr; } switch (ifvar) { case ipMRouteUpstreamNeighbor: { struct sockaddr_in tmp; tmp.sin_addr.s_addr = gt->gt_route->rt_gateway; return o_ipaddr (oi, v, &tmp); } case ipMRouteInIfIndex: return o_integer (oi, v, gt->gt_route->rt_parent); case ipMRouteUpTime: { time_t currtime; time(&currtime); return o_integer (oi, v, (currtime - gt->gt_ctime)*100); } case ipMRouteExpiryTime: return o_integer (oi, v, gt->gt_timer*100); case ipMRoutePkts: refresh_sg(&sg_req, gt, st); return o_integer (oi, v, sg_req.pktcnt); case ipMRouteOctets: refresh_sg(&sg_req, gt, st); return o_integer (oi, v, sg_req.bytecnt); case ipMRouteDifferentInIfIndexes: refresh_sg(&sg_req, gt, st); return o_integer (oi, v, sg_req.wrong_if); case ipMRouteProtocol: return o_integer (oi, v, 4); default: return int_SNMP_error__status_noSuchName; } } /* * Implements the IP Multicast Routing Next Hop Table portion of the Multicast * MIB */ int o_ipMRouteNextHopTable (oi, v, offset) OI oi; register struct type_SNMP_VarBind *v; int offset; { u_long src, grp, mask, addr; vifi_t vifi; int ifvar; register OID oid = oi -> oi_name; register OT ot = oi -> oi_type; struct gtable *gt; struct stable *st; ifvar = (int) ot -> ot_info; switch (offset) { case type_SNMP_SMUX__PDUs_get__request: if (oid->oid_nelem != ot->ot_name->oid_nelem+17) return int_SNMP_error__status_noSuchName; if (!get_address(oid, &grp, ot->ot_name->oid_nelem) || !get_address(oid, &src, ot->ot_name->oid_nelem+4) || !get_address(oid, &mask, ot->ot_name->oid_nelem+8) || !get_address(oid, &addr, ot->ot_name->oid_nelem+13) || grp!=addr || mask!=0xFFFFFFFF || (!(gt=find_grp(grp))) || (!(st=find_grp_src(gt,src)))) return int_SNMP_error__status_noSuchName; vifi = oid->oid_elements[ot->ot_name->oid_nelem+12]; if (!(VIFM_ISSET(vifi, gt->gt_route->rt_children))) return int_SNMP_error__status_noSuchName; break; case type_SNMP_SMUX__PDUs_get__next__request: /* Check if we're requesting the first row */ if (oid->oid_nelem < ot->ot_name->oid_nelem+17) { OID new; get_address(oid, &grp, ot->ot_name->oid_nelem); get_address(oid, &src, ot->ot_name->oid_nelem+4); get_address(oid, &mask, ot->ot_name->oid_nelem+8); /* Find first child vif */ vifi=0; if (!next_child(>, &st, grp, src, mask, &vifi)) return NOTOK; /* Extend by 17 more ints to hold index columns */ new = oid_extend (oid, ot->ot_name->oid_nelem+17-oid->oid_nelem); if (new == NULLOID) return NOTOK; put_address(new, gt->gt_mcastgrp, ot->ot_name->oid_nelem); put_address(new, st->st_origin, ot->ot_name->oid_nelem+4); put_address(new, 0xFFFFFFFF, ot->ot_name->oid_nelem+8); new->oid_elements[ot->ot_name->oid_nelem+12] = vifi; put_address(new, gt->gt_mcastgrp, ot->ot_name->oid_nelem+13); if (v -> name) free_SNMP_ObjectName (v -> name); v -> name = new; /* Else we start from a previous row */ } else { int i = ot -> ot_name -> oid_nelem; /* Get the lowest entry in the table > the given grp/src/mask */ vifi = oid->oid_elements[oid->oid_nelem-1] + 1; if (!get_address(oid, &grp, ot->ot_name->oid_nelem) || !get_address(oid, &src, ot->ot_name->oid_nelem+4) || !get_address(oid, &mask, ot->ot_name->oid_nelem+8) || !next_child(>, &st, grp, src, mask, &vifi)) return NOTOK; put_address(oid, gt->gt_mcastgrp, ot->ot_name->oid_nelem); put_address(oid, st->st_origin, ot->ot_name->oid_nelem+4); put_address(oid, 0xFFFFFFFF, ot->ot_name->oid_nelem+8); oid->oid_elements[ot->ot_name->oid_nelem+12] = vifi; put_address(oid, gt->gt_mcastgrp, ot->ot_name->oid_nelem+13); } break; default: return int_SNMP_error__status_genErr; } switch (ifvar) { case ipMRouteNextHopState: return o_integer (oi, v, (VIFM_ISSET(vifi, gt->gt_grpmems))? 2 : 1); /* Currently equal to ipMRouteUpTime */ case ipMRouteNextHopUpTime: { time_t currtime; time(&currtime); return o_integer (oi, v, (currtime - gt->gt_ctime)*100); } case ipMRouteNextHopExpiryTime: return o_integer (oi, v, gt->gt_prsent_timer); case ipMRouteNextHopClosestMemberHops: return o_integer (oi, v, 0); case ipMRouteNextHopProtocol: return o_integer (oi, v, 4); default: return int_SNMP_error__status_noSuchName; } }