1 /* $OpenBSD: smi.c,v 1.7 2012/02/01 18:44:06 camield Exp $ */ 2 3 /* 4 * Copyright (c) 2007, 2008 Reyk Floeter <reyk@vantronix.net> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/queue.h> 20 #include <sys/param.h> 21 #include <sys/types.h> 22 #include <sys/stat.h> 23 #include <sys/socket.h> 24 #include <sys/un.h> 25 #include <sys/tree.h> 26 #include <sys/sysctl.h> 27 28 #include <net/if.h> 29 #include <net/if_dl.h> 30 #include <net/if_arp.h> 31 #include <net/if_media.h> 32 #include <net/route.h> 33 #include <netinet/in.h> 34 #include <netinet/if_ether.h> 35 #include <arpa/inet.h> 36 37 #include <stdlib.h> 38 #include <stdio.h> 39 #include <errno.h> 40 #include <event.h> 41 #include <fcntl.h> 42 #include <string.h> 43 #include <unistd.h> 44 #include <pwd.h> 45 46 #include "snmpd.h" 47 #include "mib.h" 48 49 extern struct snmpd *env; 50 51 RB_HEAD(oidtree, oid); 52 RB_PROTOTYPE(oidtree, oid, o_element, smi_oid_cmp); 53 struct oidtree smi_oidtree; 54 55 u_long 56 smi_getticks(void) 57 { 58 struct timeval now, run; 59 u_long ticks; 60 61 gettimeofday(&now, NULL); 62 if (timercmp(&now, &env->sc_starttime, <=)) 63 return (0); 64 timersub(&now, &env->sc_starttime, &run); 65 ticks = run.tv_sec * 100; 66 if (run.tv_usec) 67 ticks += run.tv_usec / 10000; 68 69 return (ticks); 70 } 71 72 void 73 smi_oidlen(struct ber_oid *o) 74 { 75 size_t i; 76 77 for (i = 0; i < BER_MAX_OID_LEN && o->bo_id[i] != 0; i++) 78 ; 79 o->bo_n = i; 80 } 81 82 void 83 smi_scalar_oidlen(struct ber_oid *o) 84 { 85 smi_oidlen(o); 86 87 /* Append .0. */ 88 if (o->bo_n < BER_MAX_OID_LEN) 89 o->bo_n++; 90 } 91 92 char * 93 smi_oidstring(struct ber_oid *o, char *buf, size_t len) 94 { 95 char str[256]; 96 struct oid *value, key; 97 size_t i, lookup = 1; 98 99 bzero(buf, len); 100 bzero(&key, sizeof(key)); 101 bcopy(o, &key.o_id, sizeof(struct ber_oid)); 102 key.o_flags |= OID_KEY; /* do not match wildcards */ 103 104 if (env->sc_flags & SNMPD_F_NONAMES) 105 lookup = 0; 106 107 for (i = 0; i < o->bo_n; i++) { 108 key.o_oidlen = i + 1; 109 if (lookup && 110 (value = RB_FIND(oidtree, &smi_oidtree, &key)) != NULL) 111 snprintf(str, sizeof(str), "%s", value->o_name); 112 else 113 snprintf(str, sizeof(str), "%d", key.o_oid[i]); 114 strlcat(buf, str, len); 115 if (i < (o->bo_n - 1)) 116 strlcat(buf, ".", len); 117 } 118 119 return (buf); 120 } 121 122 void 123 smi_delete(struct oid *oid) 124 { 125 struct oid key, *value; 126 127 bcopy(&oid->o_id, &key.o_id, sizeof(struct ber_oid)); 128 if ((value = RB_FIND(oidtree, &smi_oidtree, &key)) != NULL && 129 value == oid) 130 RB_REMOVE(oidtree, &smi_oidtree, value); 131 132 if (oid->o_data != NULL) 133 free(oid->o_data); 134 if (oid->o_flags & OID_DYNAMIC) { 135 free(oid->o_name); 136 free(oid); 137 } 138 } 139 140 void 141 smi_insert(struct oid *oid) 142 { 143 struct oid key, *value; 144 145 if ((oid->o_flags & OID_TABLE) && oid->o_get == NULL) 146 fatalx("smi_insert: invalid MIB table"); 147 148 bcopy(&oid->o_id, &key.o_id, sizeof(struct ber_oid)); 149 value = RB_FIND(oidtree, &smi_oidtree, &key); 150 if (value != NULL) 151 smi_delete(value); 152 153 RB_INSERT(oidtree, &smi_oidtree, oid); 154 } 155 156 void 157 smi_mibtree(struct oid *oids) 158 { 159 struct oid *oid, *decl; 160 size_t i; 161 162 for (i = 0; oids[i].o_oid[0] != 0; i++) { 163 oid = &oids[i]; 164 smi_oidlen(&oid->o_id); 165 if (oid->o_name != NULL) { 166 if ((oid->o_flags & OID_TABLE) && oid->o_get == NULL) 167 fatalx("smi_mibtree: invalid MIB table"); 168 RB_INSERT(oidtree, &smi_oidtree, oid); 169 continue; 170 } 171 decl = RB_FIND(oidtree, &smi_oidtree, oid); 172 if (decl == NULL) 173 fatalx("smi_mibtree: undeclared MIB"); 174 decl->o_flags = oid->o_flags; 175 decl->o_get = oid->o_get; 176 decl->o_set = oid->o_set; 177 decl->o_table = oid->o_table; 178 decl->o_val = oid->o_val; 179 decl->o_data = oid->o_data; 180 } 181 } 182 183 int 184 smi_init(void) 185 { 186 RB_INIT(&smi_oidtree); 187 mib_init(); 188 return (0); 189 } 190 191 struct oid * 192 smi_find(struct oid *oid) 193 { 194 return (RB_FIND(oidtree, &smi_oidtree, oid)); 195 } 196 197 struct oid * 198 smi_next(struct oid *oid) 199 { 200 return (RB_NEXT(oidtree, &smi_oidtree, oid)); 201 } 202 203 struct oid * 204 smi_foreach(struct oid *oid, u_int flags) 205 { 206 /* 207 * Traverse the tree of MIBs with the option to check 208 * for specific OID flags. 209 */ 210 if (oid == NULL) { 211 oid = RB_MIN(oidtree, &smi_oidtree); 212 if (oid == NULL) 213 return (NULL); 214 if (flags == 0 || (oid->o_flags & flags)) 215 return (oid); 216 } 217 for (;;) { 218 oid = RB_NEXT(oidtree, &smi_oidtree, oid); 219 if (oid == NULL) 220 break; 221 if (flags == 0 || (oid->o_flags & flags)) 222 return (oid); 223 } 224 225 return (oid); 226 } 227 228 int 229 smi_oid_cmp(struct oid *a, struct oid *b) 230 { 231 size_t i; 232 233 for (i = 0; i < MIN(a->o_oidlen, b->o_oidlen); i++) 234 if (a->o_oid[i] != b->o_oid[i]) 235 return (a->o_oid[i] - b->o_oid[i]); 236 237 /* 238 * Return success if the matched object is a table 239 * (it will match any sub-elements) 240 */ 241 if ((b->o_flags & OID_TABLE) && 242 (a->o_flags & OID_KEY) == 0 && 243 (a->o_oidlen > b->o_oidlen)) 244 return (0); 245 246 return (a->o_oidlen - b->o_oidlen); 247 } 248 249 RB_GENERATE(oidtree, oid, o_element, smi_oid_cmp); 250