| File: | src/usr.sbin/snmpd/application.c |
| Warning: | line 836, column 18 Access to field 'ar_oid' results in a dereference of a null pointer (loaded from variable 'cregion') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: application.c,v 1.41 2023/12/21 12:43:30 martijn Exp $ */ | |||
| 2 | ||||
| 3 | /* | |||
| 4 | * Copyright (c) 2021 Martijn van Duren <martijn@openbsd.org> | |||
| 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/time.h> | |||
| 21 | #include <sys/tree.h> | |||
| 22 | #include <sys/types.h> | |||
| 23 | ||||
| 24 | #include <assert.h> | |||
| 25 | #include <errno(*__errno()).h> | |||
| 26 | #include <event.h> | |||
| 27 | #include <inttypes.h> | |||
| 28 | #include <stdlib.h> | |||
| 29 | #include <stdio.h> | |||
| 30 | #include <string.h> | |||
| 31 | ||||
| 32 | #include "application.h" | |||
| 33 | #include "log.h" | |||
| 34 | #include "smi.h" | |||
| 35 | #include "snmp.h" | |||
| 36 | #include "snmpe.h" | |||
| 37 | #include "mib.h" | |||
| 38 | ||||
| 39 | #define OID(...)(struct ber_oid){ { ... }, (sizeof((uint32_t []) { ... }) / sizeof (uint32_t)) } (struct ber_oid){ { __VA_ARGS__ }, \ | |||
| 40 | (sizeof((uint32_t []) { __VA_ARGS__ }) / sizeof(uint32_t)) } | |||
| 41 | ||||
| 42 | TAILQ_HEAD(, appl_context)struct { struct appl_context *tqh_first; struct appl_context * *tqh_last; } contexts = TAILQ_HEAD_INITIALIZER(contexts){ ((void *)0), &(contexts).tqh_first }; | |||
| 43 | ||||
| 44 | struct appl_agentcap { | |||
| 45 | struct appl_backend *aa_backend; | |||
| 46 | struct appl_context *aa_context; | |||
| 47 | uint32_t aa_index; | |||
| 48 | struct ber_oid aa_oid; | |||
| 49 | char aa_descr[256]; | |||
| 50 | int aa_uptime; | |||
| 51 | ||||
| 52 | TAILQ_ENTRY(appl_agentcap)struct { struct appl_agentcap *tqe_next; struct appl_agentcap **tqe_prev; } aa_entry; | |||
| 53 | }; | |||
| 54 | ||||
| 55 | struct appl_context { | |||
| 56 | char ac_name[APPL_CONTEXTNAME_MAX32 + 1]; | |||
| 57 | ||||
| 58 | RB_HEAD(appl_regions, appl_region)struct appl_regions { struct appl_region *rbh_root; } ac_regions; | |||
| 59 | TAILQ_HEAD(, appl_agentcap)struct { struct appl_agentcap *tqh_first; struct appl_agentcap **tqh_last; } ac_agentcaps; | |||
| 60 | int ac_agentcap_lastid; | |||
| 61 | int ac_agentcap_lastchange; | |||
| 62 | ||||
| 63 | TAILQ_ENTRY(appl_context)struct { struct appl_context *tqe_next; struct appl_context * *tqe_prev; } ac_entries; | |||
| 64 | }; | |||
| 65 | ||||
| 66 | struct appl_region { | |||
| 67 | struct ber_oid ar_oid; | |||
| 68 | uint8_t ar_priority; | |||
| 69 | int32_t ar_timeout; | |||
| 70 | int ar_instance; | |||
| 71 | int ar_subtree; /* Claim entire subtree */ | |||
| 72 | struct appl_backend *ar_backend; | |||
| 73 | struct appl_region *ar_next; /* Sorted by priority */ | |||
| 74 | ||||
| 75 | RB_ENTRY(appl_region)struct { struct appl_region *rbe_left; struct appl_region *rbe_right ; struct appl_region *rbe_parent; int rbe_color; } ar_entry; | |||
| 76 | }; | |||
| 77 | ||||
| 78 | struct appl_request_upstream { | |||
| 79 | struct appl_context *aru_ctx; | |||
| 80 | struct snmp_message *aru_statereference; | |||
| 81 | enum snmp_pdutype aru_requesttype; | |||
| 82 | enum snmp_pdutype aru_responsetype; | |||
| 83 | int32_t aru_requestid; /* upstream requestid */ | |||
| 84 | int32_t aru_transactionid; /* RFC 2741 section 6.1 */ | |||
| 85 | uint16_t aru_nonrepeaters; | |||
| 86 | uint16_t aru_maxrepetitions; | |||
| 87 | struct appl_varbind_internal *aru_vblist; | |||
| 88 | size_t aru_varbindlen; | |||
| 89 | enum appl_error aru_error; | |||
| 90 | int16_t aru_index; | |||
| 91 | int aru_locked; /* Prevent recursion through appl_request_send */ | |||
| 92 | ||||
| 93 | enum snmp_version aru_pduversion; | |||
| 94 | }; | |||
| 95 | ||||
| 96 | struct appl_request_downstream { | |||
| 97 | struct appl_request_upstream *ard_request; | |||
| 98 | struct appl_backend *ard_backend; | |||
| 99 | enum snmp_pdutype ard_requesttype; | |||
| 100 | uint16_t ard_nonrepeaters; | |||
| 101 | uint16_t ard_maxrepetitions; | |||
| 102 | int32_t ard_requestid; | |||
| 103 | uint8_t ard_retries; | |||
| 104 | ||||
| 105 | struct appl_varbind_internal *ard_vblist; | |||
| 106 | struct event ard_timer; | |||
| 107 | ||||
| 108 | RB_ENTRY(appl_request_downstream)struct { struct appl_request_downstream *rbe_left; struct appl_request_downstream *rbe_right; struct appl_request_downstream *rbe_parent; int rbe_color ; } ard_entry; | |||
| 109 | }; | |||
| 110 | ||||
| 111 | enum appl_varbind_state { | |||
| 112 | APPL_VBSTATE_MUSTFILL, | |||
| 113 | APPL_VBSTATE_NEW, | |||
| 114 | APPL_VBSTATE_PENDING, | |||
| 115 | APPL_VBSTATE_DONE | |||
| 116 | }; | |||
| 117 | ||||
| 118 | struct appl_varbind_internal { | |||
| 119 | enum appl_varbind_state avi_state; | |||
| 120 | struct appl_varbind avi_varbind; | |||
| 121 | struct appl_region *avi_region; | |||
| 122 | struct ber_oid avi_origid; | |||
| 123 | int16_t avi_index; | |||
| 124 | struct appl_request_upstream *avi_request_upstream; | |||
| 125 | struct appl_request_downstream *avi_request_downstream; | |||
| 126 | struct appl_varbind_internal *avi_next; | |||
| 127 | struct appl_varbind_internal *avi_sub; | |||
| 128 | }; | |||
| 129 | ||||
| 130 | /* SNMP-TARGET-MIB (RFC 3413) */ | |||
| 131 | struct snmp_target_mib { | |||
| 132 | uint32_t snmp_unavailablecontexts; | |||
| 133 | uint32_t snmp_unknowncontexts; | |||
| 134 | } snmp_target_mib; | |||
| 135 | ||||
| 136 | void appl_agentcap_free(struct appl_agentcap *); | |||
| 137 | enum appl_error appl_region(struct appl_context *, uint32_t, uint8_t, | |||
| 138 | struct ber_oid *, int, int, struct appl_backend *); | |||
| 139 | void appl_region_free(struct appl_context *, struct appl_region *); | |||
| 140 | enum appl_error appl_region_unregister_match(struct appl_context *, uint8_t, | |||
| 141 | struct ber_oid *, char *, struct appl_backend *, int); | |||
| 142 | struct appl_region *appl_region_find(struct appl_context *, | |||
| 143 | const struct ber_oid *); | |||
| 144 | struct appl_region *appl_region_next(struct appl_context *, | |||
| 145 | struct ber_oid *, struct appl_region *); | |||
| 146 | void appl_request_upstream_free(struct appl_request_upstream *); | |||
| 147 | void appl_request_downstream_free(struct appl_request_downstream *); | |||
| 148 | void appl_request_upstream_resolve(struct appl_request_upstream *); | |||
| 149 | void appl_request_downstream_send(struct appl_request_downstream *); | |||
| 150 | void appl_request_downstream_timeout(int, short, void *); | |||
| 151 | void appl_request_upstream_reply(struct appl_request_upstream *); | |||
| 152 | int appl_varbind_valid(struct appl_varbind *, struct appl_varbind_internal *, | |||
| 153 | int, int, int, const char **); | |||
| 154 | int appl_error_valid(enum appl_error, enum snmp_pdutype); | |||
| 155 | int appl_varbind_backend(struct appl_varbind_internal *); | |||
| 156 | void appl_varbind_error(struct appl_varbind_internal *, enum appl_error); | |||
| 157 | void appl_pdu_log(struct appl_backend *, enum snmp_pdutype, int32_t, uint16_t, | |||
| 158 | uint16_t, struct appl_varbind *); | |||
| 159 | void ober_oid_nextsibling(struct ber_oid *); | |||
| 160 | ||||
| 161 | int appl_region_cmp(struct appl_region *, struct appl_region *); | |||
| 162 | int appl_request_cmp(struct appl_request_downstream *, | |||
| 163 | struct appl_request_downstream *); | |||
| 164 | ||||
| 165 | RB_PROTOTYPE_STATIC(appl_regions, appl_region, ar_entry, appl_region_cmp)__attribute__((__unused__)) static void appl_regions_RB_INSERT_COLOR (struct appl_regions *, struct appl_region *); __attribute__( (__unused__)) static void appl_regions_RB_REMOVE_COLOR(struct appl_regions *, struct appl_region *, struct appl_region *); __attribute__((__unused__)) static struct appl_region *appl_regions_RB_REMOVE (struct appl_regions *, struct appl_region *); __attribute__( (__unused__)) static struct appl_region *appl_regions_RB_INSERT (struct appl_regions *, struct appl_region *); __attribute__( (__unused__)) static struct appl_region *appl_regions_RB_FIND (struct appl_regions *, struct appl_region *); __attribute__( (__unused__)) static struct appl_region *appl_regions_RB_NFIND (struct appl_regions *, struct appl_region *); __attribute__( (__unused__)) static struct appl_region *appl_regions_RB_NEXT (struct appl_region *); __attribute__((__unused__)) static struct appl_region *appl_regions_RB_PREV(struct appl_region *); __attribute__ ((__unused__)) static struct appl_region *appl_regions_RB_MINMAX (struct appl_regions *, int);; | |||
| 166 | RB_PROTOTYPE_STATIC(appl_requests, appl_request_downstream, ard_entry,__attribute__((__unused__)) static void appl_requests_RB_INSERT_COLOR (struct appl_requests *, struct appl_request_downstream *); __attribute__ ((__unused__)) static void appl_requests_RB_REMOVE_COLOR(struct appl_requests *, struct appl_request_downstream *, struct appl_request_downstream *);__attribute__((__unused__)) static struct appl_request_downstream *appl_requests_RB_REMOVE(struct appl_requests *, struct appl_request_downstream *); __attribute__((__unused__)) static struct appl_request_downstream *appl_requests_RB_INSERT(struct appl_requests *, struct appl_request_downstream *); __attribute__((__unused__)) static struct appl_request_downstream *appl_requests_RB_FIND(struct appl_requests *, struct appl_request_downstream *); __attribute__((__unused__)) static struct appl_request_downstream *appl_requests_RB_NFIND(struct appl_requests *, struct appl_request_downstream *); __attribute__((__unused__)) static struct appl_request_downstream *appl_requests_RB_NEXT(struct appl_request_downstream *); __attribute__ ((__unused__)) static struct appl_request_downstream *appl_requests_RB_PREV (struct appl_request_downstream *); __attribute__((__unused__ )) static struct appl_request_downstream *appl_requests_RB_MINMAX (struct appl_requests *, int); | |||
| 167 | appl_request_cmp)__attribute__((__unused__)) static void appl_requests_RB_INSERT_COLOR (struct appl_requests *, struct appl_request_downstream *); __attribute__ ((__unused__)) static void appl_requests_RB_REMOVE_COLOR(struct appl_requests *, struct appl_request_downstream *, struct appl_request_downstream *);__attribute__((__unused__)) static struct appl_request_downstream *appl_requests_RB_REMOVE(struct appl_requests *, struct appl_request_downstream *); __attribute__((__unused__)) static struct appl_request_downstream *appl_requests_RB_INSERT(struct appl_requests *, struct appl_request_downstream *); __attribute__((__unused__)) static struct appl_request_downstream *appl_requests_RB_FIND(struct appl_requests *, struct appl_request_downstream *); __attribute__((__unused__)) static struct appl_request_downstream *appl_requests_RB_NFIND(struct appl_requests *, struct appl_request_downstream *); __attribute__((__unused__)) static struct appl_request_downstream *appl_requests_RB_NEXT(struct appl_request_downstream *); __attribute__ ((__unused__)) static struct appl_request_downstream *appl_requests_RB_PREV (struct appl_request_downstream *); __attribute__((__unused__ )) static struct appl_request_downstream *appl_requests_RB_MINMAX (struct appl_requests *, int);; | |||
| 168 | ||||
| 169 | #define APPL_CONTEXT_NAME(ctx)(ctx->ac_name[0] == '\0' ? ((void *)0) : ctx->ac_name) (ctx->ac_name[0] == '\0' ? NULL((void *)0) : ctx->ac_name) | |||
| 170 | ||||
| 171 | void | |||
| 172 | appl(void) | |||
| 173 | { | |||
| 174 | appl_agentx(); | |||
| 175 | } | |||
| 176 | ||||
| 177 | void | |||
| 178 | appl_init(void) | |||
| 179 | { | |||
| 180 | appl_blocklist_init(); | |||
| 181 | appl_internal_init(); | |||
| 182 | appl_agentx_init(); | |||
| 183 | } | |||
| 184 | ||||
| 185 | void | |||
| 186 | appl_shutdown(void) | |||
| 187 | { | |||
| 188 | struct appl_context *ctx, *tctx; | |||
| 189 | ||||
| 190 | appl_blocklist_shutdown(); | |||
| 191 | appl_internal_shutdown(); | |||
| 192 | appl_agentx_shutdown(); | |||
| 193 | ||||
| 194 | TAILQ_FOREACH_SAFE(ctx, &contexts, ac_entries, tctx)for ((ctx) = ((&contexts)->tqh_first); (ctx) != ((void *)0) && ((tctx) = ((ctx)->ac_entries.tqe_next), 1 ); (ctx) = (tctx)) { | |||
| 195 | assert(RB_EMPTY(&(ctx->ac_regions)))((((&(ctx->ac_regions))->rbh_root == ((void *)0))) ? (void)0 : __assert2("/usr/src/usr.sbin/snmpd/application.c", 195, __func__, "RB_EMPTY(&(ctx->ac_regions))")); | |||
| 196 | assert(TAILQ_EMPTY(&(ctx->ac_agentcaps)))(((((&(ctx->ac_agentcaps))->tqh_first) == ((void *) 0))) ? (void)0 : __assert2("/usr/src/usr.sbin/snmpd/application.c" , 196, __func__, "TAILQ_EMPTY(&(ctx->ac_agentcaps))")); | |||
| 197 | TAILQ_REMOVE(&contexts, ctx, ac_entries)do { if (((ctx)->ac_entries.tqe_next) != ((void *)0)) (ctx )->ac_entries.tqe_next->ac_entries.tqe_prev = (ctx)-> ac_entries.tqe_prev; else (&contexts)->tqh_last = (ctx )->ac_entries.tqe_prev; *(ctx)->ac_entries.tqe_prev = ( ctx)->ac_entries.tqe_next; ; ; } while (0); | |||
| 198 | free(ctx); | |||
| 199 | } | |||
| 200 | } | |||
| 201 | ||||
| 202 | struct appl_context * | |||
| 203 | appl_context(const char *name, int create) | |||
| 204 | { | |||
| 205 | struct appl_context *ctx; | |||
| 206 | ||||
| 207 | if (name == NULL((void *)0)) | |||
| 208 | name = ""; | |||
| 209 | ||||
| 210 | if (strlen(name) > APPL_CONTEXTNAME_MAX32) { | |||
| 211 | errno(*__errno()) = EINVAL22; | |||
| 212 | return NULL((void *)0); | |||
| 213 | } | |||
| 214 | ||||
| 215 | TAILQ_FOREACH(ctx, &contexts, ac_entries)for((ctx) = ((&contexts)->tqh_first); (ctx) != ((void * )0); (ctx) = ((ctx)->ac_entries.tqe_next)) { | |||
| 216 | if (strcmp(name, ctx->ac_name) == 0) | |||
| 217 | return ctx; | |||
| 218 | } | |||
| 219 | ||||
| 220 | /* Always allow the default namespace */ | |||
| 221 | if (!create && name[0] != '\0') { | |||
| 222 | errno(*__errno()) = ENOENT2; | |||
| 223 | return NULL((void *)0); | |||
| 224 | } | |||
| 225 | ||||
| 226 | if ((ctx = malloc(sizeof(*ctx))) == NULL((void *)0)) | |||
| 227 | return NULL((void *)0); | |||
| 228 | ||||
| 229 | strlcpy(ctx->ac_name, name, sizeof(ctx->ac_name)); | |||
| 230 | RB_INIT(&(ctx->ac_regions))do { (&(ctx->ac_regions))->rbh_root = ((void *)0); } while (0); | |||
| 231 | TAILQ_INIT(&(ctx->ac_agentcaps))do { (&(ctx->ac_agentcaps))->tqh_first = ((void *)0 ); (&(ctx->ac_agentcaps))->tqh_last = &(&(ctx ->ac_agentcaps))->tqh_first; } while (0); | |||
| 232 | ctx->ac_agentcap_lastid = 0; | |||
| 233 | ctx->ac_agentcap_lastchange = 0; | |||
| 234 | ||||
| 235 | TAILQ_INSERT_TAIL(&contexts, ctx, ac_entries)do { (ctx)->ac_entries.tqe_next = ((void *)0); (ctx)->ac_entries .tqe_prev = (&contexts)->tqh_last; *(&contexts)-> tqh_last = (ctx); (&contexts)->tqh_last = &(ctx)-> ac_entries.tqe_next; } while (0); | |||
| 236 | return ctx; | |||
| 237 | } | |||
| 238 | ||||
| 239 | /* Name from RFC 2741 section 6.2.14 */ | |||
| 240 | enum appl_error | |||
| 241 | appl_addagentcaps(const char *ctxname, struct ber_oid *oid, const char *descr, | |||
| 242 | struct appl_backend *backend) | |||
| 243 | { | |||
| 244 | struct appl_context *ctx; | |||
| 245 | struct appl_agentcap *cap; | |||
| 246 | char oidbuf[1024]; | |||
| 247 | ||||
| 248 | if (ctxname == NULL((void *)0)) | |||
| 249 | ctxname = ""; | |||
| 250 | ||||
| 251 | (void)smi_oid2string(oid, oidbuf, sizeof(oidbuf), 0); | |||
| 252 | log_info("%s: Adding agent capabilities %s context(%s)", | |||
| 253 | backend->ab_name, oidbuf, ctxname); | |||
| 254 | ||||
| 255 | if ((ctx = appl_context(ctxname, 0)) == NULL((void *)0)) { | |||
| 256 | log_info("%s: Can't add agent capabilities %s: " | |||
| 257 | "Unsupported context \"%s\"", backend->ab_name, oidbuf, | |||
| 258 | ctxname); | |||
| 259 | return APPL_ERROR_UNSUPPORTEDCONTEXT; | |||
| 260 | } | |||
| 261 | ||||
| 262 | if ((cap = malloc(sizeof(*cap))) == NULL((void *)0)) { | |||
| 263 | log_warn("%s: Can't add agent capabilities %s", | |||
| 264 | backend->ab_name, oidbuf); | |||
| 265 | return APPL_ERROR_PROCESSINGERROR; | |||
| 266 | } | |||
| 267 | ||||
| 268 | cap->aa_backend = backend; | |||
| 269 | cap->aa_context = ctx; | |||
| 270 | cap->aa_index = ++ctx->ac_agentcap_lastid; | |||
| 271 | cap->aa_oid = *oid; | |||
| 272 | cap->aa_uptime = smi_getticks(); | |||
| 273 | if (strlcpy(cap->aa_descr, descr, | |||
| 274 | sizeof(cap->aa_descr)) >= sizeof(cap->aa_descr)) { | |||
| 275 | log_info("%s: Can't add agent capabilities %s: " | |||
| 276 | "Invalid description", backend->ab_name, oidbuf); | |||
| 277 | free(cap); | |||
| 278 | return APPL_ERROR_PARSEERROR; | |||
| 279 | } | |||
| 280 | ||||
| 281 | TAILQ_INSERT_TAIL(&(ctx->ac_agentcaps), cap, aa_entry)do { (cap)->aa_entry.tqe_next = ((void *)0); (cap)->aa_entry .tqe_prev = (&(ctx->ac_agentcaps))->tqh_last; *(& (ctx->ac_agentcaps))->tqh_last = (cap); (&(ctx-> ac_agentcaps))->tqh_last = &(cap)->aa_entry.tqe_next ; } while (0); | |||
| 282 | ctx->ac_agentcap_lastchange = cap->aa_uptime; | |||
| 283 | ||||
| 284 | return APPL_ERROR_NOERROR; | |||
| 285 | } | |||
| 286 | ||||
| 287 | /* Name from RFC2741 section 6.2.15 */ | |||
| 288 | enum appl_error | |||
| 289 | appl_removeagentcaps(const char *ctxname, struct ber_oid *oid, | |||
| 290 | struct appl_backend *backend) | |||
| 291 | { | |||
| 292 | struct appl_context *ctx; | |||
| 293 | struct appl_agentcap *cap, *tmp; | |||
| 294 | char oidbuf[1024]; | |||
| 295 | int found = 0; | |||
| 296 | ||||
| 297 | if (ctxname == NULL((void *)0)) | |||
| 298 | ctxname = ""; | |||
| 299 | ||||
| 300 | (void)smi_oid2string(oid, oidbuf, sizeof(oidbuf), 0); | |||
| 301 | log_info("%s: Removing agent capabilities %s context(%s)", | |||
| 302 | backend->ab_name, oidbuf, ctxname); | |||
| 303 | ||||
| 304 | if ((ctx = appl_context(ctxname, 0)) == NULL((void *)0)) { | |||
| 305 | log_info("%s: Can't remove agent capabilities %s: " | |||
| 306 | "Unsupported context \"%s\"", backend->ab_name, oidbuf, | |||
| 307 | ctxname); | |||
| 308 | return APPL_ERROR_UNSUPPORTEDCONTEXT; | |||
| 309 | } | |||
| 310 | ||||
| 311 | TAILQ_FOREACH_SAFE(cap, &(ctx->ac_agentcaps), aa_entry, tmp)for ((cap) = ((&(ctx->ac_agentcaps))->tqh_first); ( cap) != ((void *)0) && ((tmp) = ((cap)->aa_entry.tqe_next ), 1); (cap) = (tmp)) { | |||
| 312 | /* No duplicate oid check, just continue */ | |||
| 313 | if (cap->aa_backend != backend || | |||
| 314 | ober_oid_cmp(oid, &(cap->aa_oid)) != 0) | |||
| 315 | continue; | |||
| 316 | found = 1; | |||
| 317 | appl_agentcap_free(cap); | |||
| 318 | } | |||
| 319 | ||||
| 320 | if (found) | |||
| 321 | return APPL_ERROR_NOERROR; | |||
| 322 | ||||
| 323 | log_info("%s: Can't remove agent capabilities %s: not found", | |||
| 324 | backend->ab_name, oidbuf); | |||
| 325 | return APPL_ERROR_UNKNOWNAGENTCAPS; | |||
| 326 | } | |||
| 327 | ||||
| 328 | void | |||
| 329 | appl_agentcap_free(struct appl_agentcap *cap) | |||
| 330 | { | |||
| 331 | TAILQ_REMOVE(&(cap->aa_context->ac_agentcaps), cap, aa_entry)do { if (((cap)->aa_entry.tqe_next) != ((void *)0)) (cap)-> aa_entry.tqe_next->aa_entry.tqe_prev = (cap)->aa_entry. tqe_prev; else (&(cap->aa_context->ac_agentcaps))-> tqh_last = (cap)->aa_entry.tqe_prev; *(cap)->aa_entry.tqe_prev = (cap)->aa_entry.tqe_next; ; ; } while (0); | |||
| 332 | cap->aa_context->ac_agentcap_lastchange = smi_getticks(); | |||
| 333 | free(cap); | |||
| 334 | } | |||
| 335 | ||||
| 336 | struct ber_element * | |||
| 337 | appl_sysorlastchange(struct ber_oid *oid) | |||
| 338 | { | |||
| 339 | struct appl_context *ctx; | |||
| 340 | struct ber_element *value; | |||
| 341 | ||||
| 342 | ctx = appl_context(NULL((void *)0), 0); | |||
| 343 | value = ober_add_integer(NULL((void *)0), ctx->ac_agentcap_lastchange); | |||
| 344 | if (value != NULL((void *)0)) | |||
| 345 | ober_set_header(value, BER_CLASS_APPLICATION0x1, SNMP_T_TIMETICKS); | |||
| 346 | else | |||
| 347 | log_warn("ober_add_integer"); | |||
| 348 | ||||
| 349 | return value; | |||
| 350 | } | |||
| 351 | ||||
| 352 | #define SYSORIDX_POS10 10 | |||
| 353 | struct ber_element * | |||
| 354 | appl_sysortable(struct ber_oid *oid) | |||
| 355 | { | |||
| 356 | struct appl_context *ctx; | |||
| 357 | struct appl_agentcap *cap; | |||
| 358 | struct ber_element *value = NULL((void *)0); | |||
| 359 | ||||
| 360 | if (oid->bo_n != SYSORIDX_POS10 + 1) | |||
| 361 | goto notfound; | |||
| 362 | ||||
| 363 | ctx = appl_context(NULL((void *)0), 0); | |||
| 364 | TAILQ_FOREACH(cap, &(ctx->ac_agentcaps), aa_entry)for((cap) = ((&(ctx->ac_agentcaps))->tqh_first); (cap ) != ((void *)0); (cap) = ((cap)->aa_entry.tqe_next)) { | |||
| 365 | if (cap->aa_index == oid->bo_id[SYSORIDX_POS10]) | |||
| 366 | break; | |||
| 367 | } | |||
| 368 | if (cap == NULL((void *)0)) | |||
| 369 | goto notfound; | |||
| 370 | ||||
| 371 | if (ober_oid_cmp(&OID(MIB_sysORID)(struct ber_oid){ { 1, 3, 6, 1, 2, 1, 1, 9, 1, 2 }, (sizeof(( uint32_t []) { 1, 3, 6, 1, 2, 1, 1, 9, 1, 2 }) / sizeof(uint32_t )) }, oid) == -2) | |||
| 372 | value = ober_add_oid(NULL((void *)0), &(cap->aa_oid)); | |||
| 373 | else if (ober_oid_cmp(&OID(MIB_sysORDescr)(struct ber_oid){ { 1, 3, 6, 1, 2, 1, 1, 9, 1, 3 }, (sizeof(( uint32_t []) { 1, 3, 6, 1, 2, 1, 1, 9, 1, 3 }) / sizeof(uint32_t )) }, oid) == -2) | |||
| 374 | value = ober_add_string(NULL((void *)0), cap->aa_descr); | |||
| 375 | else if (ober_oid_cmp(&OID(MIB_sysORUpTime)(struct ber_oid){ { 1, 3, 6, 1, 2, 1, 1, 9, 1, 4 }, (sizeof(( uint32_t []) { 1, 3, 6, 1, 2, 1, 1, 9, 1, 4 }) / sizeof(uint32_t )) }, oid) == -2) { | |||
| 376 | if ((value = ober_add_integer(NULL((void *)0), cap->aa_uptime)) != NULL((void *)0)) | |||
| 377 | ober_set_header(value, | |||
| 378 | BER_CLASS_APPLICATION0x1, SNMP_T_TIMETICKS); | |||
| 379 | } | |||
| 380 | if (value == NULL((void *)0)) | |||
| 381 | log_warn("ober_add_*"); | |||
| 382 | return value; | |||
| 383 | ||||
| 384 | notfound: | |||
| 385 | if ((value = appl_exception(APPL_EXC_NOSUCHINSTANCE)) == NULL((void *)0)) | |||
| 386 | log_warn("appl_exception"); | |||
| 387 | return value; | |||
| 388 | } | |||
| 389 | ||||
| 390 | struct ber_element * | |||
| 391 | appl_sysortable_getnext(int8_t include, struct ber_oid *oid) | |||
| 392 | { | |||
| 393 | struct appl_context *ctx; | |||
| 394 | struct appl_agentcap *cap; | |||
| 395 | struct ber_element *value = NULL((void *)0); | |||
| 396 | ||||
| 397 | if (oid->bo_n < SYSORIDX_POS10 + 1) { | |||
| 398 | include = 1; | |||
| 399 | oid->bo_id[SYSORIDX_POS10] = 0; | |||
| 400 | } else if (oid->bo_n < SYSORIDX_POS10 + 1) | |||
| 401 | include = 0; | |||
| 402 | ||||
| 403 | ctx = appl_context(NULL((void *)0), 0); | |||
| 404 | TAILQ_FOREACH(cap, &(ctx->ac_agentcaps), aa_entry)for((cap) = ((&(ctx->ac_agentcaps))->tqh_first); (cap ) != ((void *)0); (cap) = ((cap)->aa_entry.tqe_next)) { | |||
| 405 | if (cap->aa_index > oid->bo_id[SYSORIDX_POS10]) | |||
| 406 | break; | |||
| 407 | if (cap->aa_index == oid->bo_id[SYSORIDX_POS10] && include) | |||
| 408 | break; | |||
| 409 | } | |||
| 410 | if (cap == NULL((void *)0)) { | |||
| 411 | value = appl_exception(APPL_EXC_NOSUCHINSTANCE); | |||
| 412 | goto done; | |||
| 413 | } | |||
| 414 | ||||
| 415 | oid->bo_id[SYSORIDX_POS10] = cap->aa_index; | |||
| 416 | oid->bo_n = SYSORIDX_POS10 + 1; | |||
| 417 | ||||
| 418 | if (ober_oid_cmp(&OID(MIB_sysORID)(struct ber_oid){ { 1, 3, 6, 1, 2, 1, 1, 9, 1, 2 }, (sizeof(( uint32_t []) { 1, 3, 6, 1, 2, 1, 1, 9, 1, 2 }) / sizeof(uint32_t )) }, oid) == -2) | |||
| 419 | value = ober_add_oid(NULL((void *)0), &(cap->aa_oid)); | |||
| 420 | else if (ober_oid_cmp(&OID(MIB_sysORDescr)(struct ber_oid){ { 1, 3, 6, 1, 2, 1, 1, 9, 1, 3 }, (sizeof(( uint32_t []) { 1, 3, 6, 1, 2, 1, 1, 9, 1, 3 }) / sizeof(uint32_t )) }, oid) == -2) | |||
| 421 | value = ober_add_string(NULL((void *)0), cap->aa_descr); | |||
| 422 | else if (ober_oid_cmp(&OID(MIB_sysORUpTime)(struct ber_oid){ { 1, 3, 6, 1, 2, 1, 1, 9, 1, 4 }, (sizeof(( uint32_t []) { 1, 3, 6, 1, 2, 1, 1, 9, 1, 4 }) / sizeof(uint32_t )) }, oid) == -2) { | |||
| 423 | if ((value = ober_add_integer(NULL((void *)0), cap->aa_uptime)) != NULL((void *)0)) | |||
| 424 | ober_set_header(value, | |||
| 425 | BER_CLASS_APPLICATION0x1, SNMP_T_TIMETICKS); | |||
| 426 | } | |||
| 427 | done: | |||
| 428 | if (value == NULL((void *)0)) | |||
| 429 | log_warn("ober_add_*"); | |||
| 430 | return value; | |||
| 431 | } | |||
| 432 | ||||
| 433 | struct ber_element * | |||
| 434 | appl_targetmib(struct ber_oid *oid) | |||
| 435 | { | |||
| 436 | struct ber_element *value = NULL((void *)0); | |||
| 437 | ||||
| 438 | if (ober_oid_cmp(oid, &OID(MIB_snmpUnavailableContexts, 0)(struct ber_oid){ { 1, 3, 6, 1, 6, 3, 12, 1, 4, 0 }, (sizeof( (uint32_t []) { 1, 3, 6, 1, 6, 3, 12, 1, 4, 0 }) / sizeof(uint32_t )) }) == 0) | |||
| 439 | value = ober_add_integer(NULL((void *)0), | |||
| 440 | snmp_target_mib.snmp_unavailablecontexts); | |||
| 441 | else if (ober_oid_cmp(oid, &OID(MIB_snmpUnknownContexts, 0)(struct ber_oid){ { 1, 3, 6, 1, 6, 3, 12, 1, 5, 0 }, (sizeof( (uint32_t []) { 1, 3, 6, 1, 6, 3, 12, 1, 5, 0 }) / sizeof(uint32_t )) }) == 0) | |||
| 442 | value = ober_add_integer(NULL((void *)0), | |||
| 443 | snmp_target_mib.snmp_unknowncontexts); | |||
| 444 | ||||
| 445 | if (value != NULL((void *)0)) | |||
| 446 | ober_set_header(value, BER_CLASS_APPLICATION0x1, SNMP_T_COUNTER32); | |||
| 447 | return value; | |||
| 448 | } | |||
| 449 | ||||
| 450 | enum appl_error | |||
| 451 | appl_region(struct appl_context *ctx, uint32_t timeout, uint8_t priority, | |||
| 452 | struct ber_oid *oid, int instance, int subtree, | |||
| 453 | struct appl_backend *backend) | |||
| 454 | { | |||
| 455 | struct appl_region *region = NULL((void *)0), *nregion; | |||
| 456 | char oidbuf[1024], regionbuf[1024], subidbuf[11]; | |||
| 457 | size_t i; | |||
| 458 | ||||
| 459 | /* Don't use smi_oid2string, because appl_register can't use it */ | |||
| 460 | oidbuf[0] = '\0'; | |||
| 461 | for (i = 0; i < oid->bo_n; i++) { | |||
| 462 | if (i != 0) | |||
| 463 | strlcat(oidbuf, ".", sizeof(oidbuf)); | |||
| 464 | snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32"u", | |||
| 465 | oid->bo_id[i]); | |||
| 466 | strlcat(oidbuf, subidbuf, sizeof(oidbuf)); | |||
| 467 | } | |||
| 468 | ||||
| 469 | /* | |||
| 470 | * Don't allow overlap when subtree flag is set. | |||
| 471 | * This allows us to keep control of certain regions like system. | |||
| 472 | */ | |||
| 473 | region = appl_region_find(ctx, oid); | |||
| 474 | if (region != NULL((void *)0) && region->ar_subtree && | |||
| 475 | region->ar_backend != backend) | |||
| 476 | goto overlap; | |||
| 477 | ||||
| 478 | if ((nregion = malloc(sizeof(*nregion))) == NULL((void *)0)) { | |||
| 479 | log_warn("%s: Can't register %s: Processing error", | |||
| 480 | backend->ab_name, oidbuf); | |||
| 481 | return APPL_ERROR_PROCESSINGERROR; | |||
| 482 | } | |||
| 483 | nregion->ar_oid = *oid; | |||
| 484 | nregion->ar_priority = priority; | |||
| 485 | nregion->ar_timeout = timeout; | |||
| 486 | nregion->ar_instance = instance; | |||
| 487 | nregion->ar_subtree = subtree; | |||
| 488 | nregion->ar_backend = backend; | |||
| 489 | nregion->ar_next = NULL((void *)0); | |||
| 490 | ||||
| 491 | region = RB_INSERT(appl_regions, &(ctx->ac_regions), nregion)appl_regions_RB_INSERT(&(ctx->ac_regions), nregion); | |||
| 492 | if (region == NULL((void *)0)) | |||
| 493 | return APPL_ERROR_NOERROR; | |||
| 494 | ||||
| 495 | if (region->ar_priority == priority) | |||
| 496 | goto duplicate; | |||
| 497 | if (region->ar_priority > priority) { | |||
| 498 | RB_REMOVE(appl_regions, &(ctx->ac_regions), region)appl_regions_RB_REMOVE(&(ctx->ac_regions), region); | |||
| 499 | RB_INSERT(appl_regions, &(ctx->ac_regions), nregion)appl_regions_RB_INSERT(&(ctx->ac_regions), nregion); | |||
| 500 | nregion->ar_next = region; | |||
| 501 | return APPL_ERROR_NOERROR; | |||
| 502 | } | |||
| 503 | ||||
| 504 | while (region->ar_next != NULL((void *)0) && | |||
| 505 | region->ar_next->ar_priority < priority) | |||
| 506 | region = region->ar_next; | |||
| 507 | if (region->ar_next != NULL((void *)0) && region->ar_next->ar_priority == priority) | |||
| 508 | goto duplicate; | |||
| 509 | nregion->ar_next = region->ar_next; | |||
| 510 | region->ar_next = nregion; | |||
| 511 | ||||
| 512 | return APPL_ERROR_NOERROR; | |||
| 513 | duplicate: | |||
| 514 | free(nregion); | |||
| 515 | log_info("%s: %s priority %"PRId8"d"": Duplicate registration", | |||
| 516 | backend->ab_name, oidbuf, priority); | |||
| 517 | return APPL_ERROR_DUPLICATEREGISTRATION; | |||
| 518 | overlap: | |||
| 519 | regionbuf[0] = '\0'; | |||
| 520 | for (i = 0; i < region->ar_oid.bo_n; i++) { | |||
| 521 | if (i != 0) | |||
| 522 | strlcat(regionbuf, ".", sizeof(regionbuf)); | |||
| 523 | snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32"u", | |||
| 524 | region->ar_oid.bo_id[i]); | |||
| 525 | strlcat(regionbuf, subidbuf, sizeof(regionbuf)); | |||
| 526 | } | |||
| 527 | log_info("%s: %s overlaps with %s: Request denied", | |||
| 528 | backend->ab_name, oidbuf, regionbuf); | |||
| 529 | return APPL_ERROR_REQUESTDENIED; | |||
| 530 | } | |||
| 531 | ||||
| 532 | /* Name from RFC 2741 section 6.2.3 */ | |||
| 533 | enum appl_error | |||
| 534 | appl_register(const char *ctxname, uint32_t timeout, uint8_t priority, | |||
| 535 | struct ber_oid *oid, int instance, int subtree, uint8_t range_subid, | |||
| 536 | uint32_t upper_bound, struct appl_backend *backend) | |||
| 537 | { | |||
| 538 | struct appl_context *ctx; | |||
| 539 | struct appl_region *region, search; | |||
| 540 | char oidbuf[1024], subidbuf[11]; | |||
| 541 | enum appl_error error; | |||
| 542 | size_t i; | |||
| 543 | uint32_t lower_bound; | |||
| 544 | ||||
| 545 | oidbuf[0] = '\0'; | |||
| 546 | /* smi_oid2string can't do ranges */ | |||
| 547 | for (i = 0; i < oid->bo_n; i++) { | |||
| 548 | snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32"u", oid->bo_id[i]); | |||
| 549 | if (i != 0) | |||
| 550 | strlcat(oidbuf, ".", sizeof(oidbuf)); | |||
| 551 | if (range_subid == i + 1) { | |||
| 552 | strlcat(oidbuf, "[", sizeof(oidbuf)); | |||
| 553 | strlcat(oidbuf, subidbuf, sizeof(oidbuf)); | |||
| 554 | strlcat(oidbuf, "-", sizeof(oidbuf)); | |||
| 555 | snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32"u", | |||
| 556 | upper_bound); | |||
| 557 | strlcat(oidbuf, subidbuf, sizeof(oidbuf)); | |||
| 558 | strlcat(oidbuf, "]", sizeof(oidbuf)); | |||
| 559 | } else | |||
| 560 | strlcat(oidbuf, subidbuf, sizeof(oidbuf)); | |||
| 561 | } | |||
| 562 | ||||
| 563 | if (ctxname == NULL((void *)0)) | |||
| 564 | ctxname = ""; | |||
| 565 | log_info("%s: Registering %s%s context(%s) priority(%"PRIu8"u"") " | |||
| 566 | "timeout(%"PRIu32"u"".%02us)", backend->ab_name, oidbuf, | |||
| 567 | instance ? "(instance)" : "", ctxname, priority, | |||
| 568 | timeout/100, timeout % 100); | |||
| 569 | ||||
| 570 | if ((ctx = appl_context(ctxname, 0)) == NULL((void *)0)) { | |||
| 571 | if (errno(*__errno()) == ENOMEM12) { | |||
| 572 | log_warn("%s: Can't register %s: Processing error", | |||
| 573 | backend->ab_name, oidbuf); | |||
| 574 | return APPL_ERROR_PROCESSINGERROR; | |||
| 575 | } | |||
| 576 | log_info("%s: Can't register %s: Unsupported context \"%s\"", | |||
| 577 | backend->ab_name, oidbuf, ctxname); | |||
| 578 | return APPL_ERROR_UNSUPPORTEDCONTEXT; | |||
| 579 | } | |||
| 580 | /* Default timeouts should be handled by backend */ | |||
| 581 | if (timeout == 0) | |||
| 582 | fatalx("%s: Timeout can't be 0", __func__); | |||
| 583 | if (priority == 0) { | |||
| 584 | log_warnx("%s: Can't register %s: priority can't be 0", | |||
| 585 | backend->ab_name, oidbuf); | |||
| 586 | return APPL_ERROR_PARSEERROR; | |||
| 587 | } | |||
| 588 | ||||
| 589 | if (range_subid == 0) | |||
| 590 | return appl_region(ctx, timeout, priority, oid, instance, | |||
| 591 | subtree, backend); | |||
| 592 | ||||
| 593 | range_subid--; | |||
| 594 | if (range_subid >= oid->bo_n) { | |||
| 595 | log_warnx("%s: Can't register %s: range_subid too large", | |||
| 596 | backend->ab_name, oidbuf); | |||
| 597 | return APPL_ERROR_PARSEERROR; | |||
| 598 | } | |||
| 599 | if (oid->bo_id[range_subid] > upper_bound) { | |||
| 600 | log_warnx("%s: Can't register %s: upper bound smaller than " | |||
| 601 | "range_subid", backend->ab_name, oidbuf); | |||
| 602 | return APPL_ERROR_PARSEERROR; | |||
| 603 | } | |||
| 604 | ||||
| 605 | lower_bound = oid->bo_id[range_subid]; | |||
| 606 | do { | |||
| 607 | if ((error = appl_region(ctx, timeout, priority, oid, instance, | |||
| 608 | subtree, backend)) != APPL_ERROR_NOERROR) | |||
| 609 | goto fail; | |||
| 610 | } while (oid->bo_id[range_subid]++ != upper_bound); | |||
| 611 | if ((error = appl_region(ctx, timeout, priority, oid, instance, subtree, | |||
| 612 | backend)) != APPL_ERROR_NOERROR) | |||
| 613 | goto fail; | |||
| 614 | ||||
| 615 | return APPL_ERROR_NOERROR; | |||
| 616 | fail: | |||
| 617 | search.ar_oid = *oid; | |||
| 618 | if (search.ar_oid.bo_id[range_subid] == lower_bound) | |||
| 619 | return error; | |||
| 620 | ||||
| 621 | for (search.ar_oid.bo_id[range_subid]--; | |||
| 622 | search.ar_oid.bo_id[range_subid] != lower_bound; | |||
| 623 | search.ar_oid.bo_id[range_subid]--) { | |||
| 624 | region = RB_FIND(appl_regions, &(ctx->ac_regions), &search)appl_regions_RB_FIND(&(ctx->ac_regions), &search); | |||
| 625 | while (region->ar_priority != priority) | |||
| 626 | region = region->ar_next; | |||
| 627 | appl_region_free(ctx, region); | |||
| 628 | } | |||
| 629 | region = RB_FIND(appl_regions, &(ctx->ac_regions), &search)appl_regions_RB_FIND(&(ctx->ac_regions), &search); | |||
| 630 | while (region->ar_priority != priority) | |||
| 631 | region = region->ar_next; | |||
| 632 | appl_region_free(ctx, region); | |||
| 633 | return error; | |||
| 634 | } | |||
| 635 | ||||
| 636 | /* Name from RFC 2741 section 6.2.4 */ | |||
| 637 | enum appl_error | |||
| 638 | appl_unregister(const char *ctxname, uint8_t priority, struct ber_oid *oid, | |||
| 639 | uint8_t range_subid, uint32_t upper_bound, struct appl_backend *backend) | |||
| 640 | { | |||
| 641 | struct appl_context *ctx; | |||
| 642 | char oidbuf[1024], subidbuf[11]; | |||
| 643 | enum appl_error error; | |||
| 644 | uint32_t lower_bound; | |||
| 645 | size_t i; | |||
| 646 | ||||
| 647 | oidbuf[0] = '\0'; | |||
| 648 | for (i = 0; i < oid->bo_n; i++) { | |||
| 649 | snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32"u", oid->bo_id[i]); | |||
| 650 | if (i != 0) | |||
| 651 | strlcat(oidbuf, ".", sizeof(oidbuf)); | |||
| 652 | if (range_subid == i + 1) { | |||
| 653 | strlcat(oidbuf, "[", sizeof(oidbuf)); | |||
| 654 | strlcat(oidbuf, subidbuf, sizeof(oidbuf)); | |||
| 655 | strlcat(oidbuf, "-", sizeof(oidbuf)); | |||
| 656 | snprintf(subidbuf, sizeof(subidbuf), "%"PRIu32"u", | |||
| 657 | upper_bound); | |||
| 658 | strlcat(oidbuf, subidbuf, sizeof(oidbuf)); | |||
| 659 | strlcat(oidbuf, "]", sizeof(oidbuf)); | |||
| 660 | } else | |||
| 661 | strlcat(oidbuf, subidbuf, sizeof(oidbuf)); | |||
| 662 | } | |||
| 663 | ||||
| 664 | if (ctxname == NULL((void *)0)) | |||
| 665 | ctxname = ""; | |||
| 666 | log_info("%s: Unregistering %s context(%s) priority(%"PRIu8"u"")", | |||
| 667 | backend->ab_name, oidbuf,ctxname, priority); | |||
| 668 | ||||
| 669 | if ((ctx = appl_context(ctxname, 0)) == NULL((void *)0)) { | |||
| 670 | if (errno(*__errno()) == ENOMEM12) { | |||
| 671 | log_warn("%s: Can't unregister %s: Processing error", | |||
| 672 | backend->ab_name, oidbuf); | |||
| 673 | return APPL_ERROR_PROCESSINGERROR; | |||
| 674 | } | |||
| 675 | log_info("%s: Can't unregister %s: Unsupported context \"%s\"", | |||
| 676 | backend->ab_name, oidbuf, ctxname); | |||
| 677 | return APPL_ERROR_UNSUPPORTEDCONTEXT; | |||
| 678 | } | |||
| 679 | ||||
| 680 | if (priority == 0) { | |||
| 681 | log_warnx("%s: Can't unregister %s: priority can't be 0", | |||
| 682 | backend->ab_name, oidbuf); | |||
| 683 | return APPL_ERROR_PARSEERROR; | |||
| 684 | } | |||
| 685 | ||||
| 686 | if (range_subid == 0) | |||
| 687 | return appl_region_unregister_match(ctx, priority, oid, oidbuf, | |||
| 688 | backend, 1); | |||
| 689 | ||||
| 690 | range_subid--; | |||
| 691 | if (range_subid >= oid->bo_n) { | |||
| 692 | log_warnx("%s: Can't unregiser %s: range_subid too large", | |||
| 693 | backend->ab_name, oidbuf); | |||
| 694 | return APPL_ERROR_PARSEERROR; | |||
| 695 | } | |||
| 696 | if (oid->bo_id[range_subid] > upper_bound) { | |||
| 697 | log_warnx("%s: Can't unregister %s: upper bound smaller than " | |||
| 698 | "range_subid", backend->ab_name, oidbuf); | |||
| 699 | return APPL_ERROR_PARSEERROR; | |||
| 700 | } | |||
| 701 | ||||
| 702 | lower_bound = oid->bo_id[range_subid]; | |||
| 703 | do { | |||
| 704 | if ((error = appl_region_unregister_match(ctx, priority, oid, | |||
| 705 | oidbuf, backend, 0)) != APPL_ERROR_NOERROR) | |||
| 706 | return error; | |||
| 707 | } while (oid->bo_id[range_subid]++ != upper_bound); | |||
| 708 | ||||
| 709 | oid->bo_id[range_subid] = lower_bound; | |||
| 710 | do { | |||
| 711 | (void)appl_region_unregister_match(ctx, priority, oid, oidbuf, | |||
| 712 | backend, 1); | |||
| 713 | } while (oid->bo_id[range_subid]++ != upper_bound); | |||
| 714 | ||||
| 715 | return APPL_ERROR_NOERROR; | |||
| 716 | } | |||
| 717 | ||||
| 718 | enum appl_error | |||
| 719 | appl_region_unregister_match(struct appl_context *ctx, uint8_t priority, | |||
| 720 | struct ber_oid *oid, char *oidbuf, struct appl_backend *backend, int dofree) | |||
| 721 | { | |||
| 722 | struct appl_region *region, search; | |||
| 723 | ||||
| 724 | search.ar_oid = *oid; | |||
| 725 | region = RB_FIND(appl_regions, &(ctx->ac_regions), &search)appl_regions_RB_FIND(&(ctx->ac_regions), &search); | |||
| 726 | while (region != NULL((void *)0) && region->ar_priority < priority) | |||
| 727 | region = region->ar_next; | |||
| 728 | if (region == NULL((void *)0) || region->ar_priority != priority) { | |||
| 729 | log_warnx("%s: Can't unregister %s: region not found", | |||
| 730 | backend->ab_name, oidbuf); | |||
| 731 | return APPL_ERROR_UNKNOWNREGISTRATION; | |||
| 732 | } | |||
| 733 | if (region->ar_backend != backend) { | |||
| 734 | log_warnx("%s: Can't unregister %s: region not owned " | |||
| 735 | "by backend", backend->ab_name, oidbuf); | |||
| 736 | return APPL_ERROR_UNKNOWNREGISTRATION; | |||
| 737 | } | |||
| 738 | if (dofree) | |||
| 739 | appl_region_free(ctx, region); | |||
| 740 | return APPL_ERROR_NOERROR; | |||
| 741 | } | |||
| 742 | ||||
| 743 | void | |||
| 744 | appl_region_free(struct appl_context *ctx, struct appl_region *region) | |||
| 745 | { | |||
| 746 | struct appl_region *pregion; | |||
| 747 | ||||
| 748 | pregion = RB_FIND(appl_regions, &(ctx->ac_regions), region)appl_regions_RB_FIND(&(ctx->ac_regions), region); | |||
| 749 | ||||
| 750 | if (pregion == region) { | |||
| 751 | RB_REMOVE(appl_regions, &(ctx->ac_regions), region)appl_regions_RB_REMOVE(&(ctx->ac_regions), region); | |||
| 752 | if (region->ar_next != NULL((void *)0)) | |||
| 753 | RB_INSERT(appl_regions, &(ctx->ac_regions),appl_regions_RB_INSERT(&(ctx->ac_regions), region-> ar_next) | |||
| 754 | region->ar_next)appl_regions_RB_INSERT(&(ctx->ac_regions), region-> ar_next); | |||
| 755 | } else { | |||
| 756 | while (pregion->ar_next != region) | |||
| 757 | pregion = pregion->ar_next; | |||
| 758 | pregion->ar_next = region->ar_next; | |||
| 759 | } | |||
| 760 | ||||
| 761 | free(region); | |||
| 762 | } | |||
| 763 | ||||
| 764 | /* backend is owned by the sub-application, just release application.c stuff */ | |||
| 765 | void | |||
| 766 | appl_close(struct appl_backend *backend) | |||
| 767 | { | |||
| 768 | struct appl_context *ctx; | |||
| 769 | struct appl_agentcap *cap, *tcap; | |||
| 770 | struct appl_region *region, *tregion, *nregion; | |||
| 771 | struct appl_request_downstream *request, *trequest; | |||
| 772 | ||||
| 773 | TAILQ_FOREACH(ctx, &contexts, ac_entries)for((ctx) = ((&contexts)->tqh_first); (ctx) != ((void * )0); (ctx) = ((ctx)->ac_entries.tqe_next)) { | |||
| 774 | TAILQ_FOREACH_SAFE(cap, &(ctx->ac_agentcaps), aa_entry, tcap)for ((cap) = ((&(ctx->ac_agentcaps))->tqh_first); ( cap) != ((void *)0) && ((tcap) = ((cap)->aa_entry. tqe_next), 1); (cap) = (tcap)) { | |||
| 775 | if (cap->aa_backend == backend) | |||
| 776 | appl_agentcap_free(cap); | |||
| 777 | } | |||
| 778 | RB_FOREACH_SAFE(region, appl_regions,for ((region) = appl_regions_RB_MINMAX(&(ctx->ac_regions ), -1); ((region) != ((void *)0)) && ((tregion) = appl_regions_RB_NEXT (region), 1); (region) = (tregion)) | |||
| 779 | &(ctx->ac_regions), tregion)for ((region) = appl_regions_RB_MINMAX(&(ctx->ac_regions ), -1); ((region) != ((void *)0)) && ((tregion) = appl_regions_RB_NEXT (region), 1); (region) = (tregion)) { | |||
| 780 | while (region != NULL((void *)0)) { | |||
| 781 | nregion = region->ar_next; | |||
| 782 | if (region->ar_backend == backend) | |||
| 783 | appl_region_free(ctx, region); | |||
| 784 | region = nregion; | |||
| 785 | } | |||
| 786 | } | |||
| 787 | } | |||
| 788 | ||||
| 789 | RB_FOREACH_SAFE(request, appl_requests,for ((request) = appl_requests_RB_MINMAX(&(backend->ab_requests ), -1); ((request) != ((void *)0)) && ((trequest) = appl_requests_RB_NEXT (request), 1); (request) = (trequest)) | |||
| 790 | &(backend->ab_requests), trequest)for ((request) = appl_requests_RB_MINMAX(&(backend->ab_requests ), -1); ((request) != ((void *)0)) && ((trequest) = appl_requests_RB_NEXT (request), 1); (request) = (trequest)) | |||
| 791 | appl_request_downstream_free(request); | |||
| 792 | } | |||
| 793 | ||||
| 794 | struct appl_region * | |||
| 795 | appl_region_find(struct appl_context *ctx, | |||
| 796 | const struct ber_oid *oid) | |||
| 797 | { | |||
| 798 | struct appl_region *region, search; | |||
| 799 | ||||
| 800 | search.ar_oid = *oid; | |||
| 801 | while (search.ar_oid.bo_n > 0) { | |||
| 802 | region = RB_FIND(appl_regions, &(ctx->ac_regions), &search)appl_regions_RB_FIND(&(ctx->ac_regions), &search); | |||
| 803 | if (region != NULL((void *)0)) | |||
| 804 | return region; | |||
| 805 | search.ar_oid.bo_n--; | |||
| 806 | } | |||
| 807 | return NULL((void *)0); | |||
| 808 | } | |||
| 809 | ||||
| 810 | struct appl_region * | |||
| 811 | appl_region_next(struct appl_context *ctx, struct ber_oid *oid, | |||
| 812 | struct appl_region *cregion) | |||
| 813 | { | |||
| 814 | struct appl_region search, *nregion, *pregion; | |||
| 815 | int cmp; | |||
| 816 | ||||
| 817 | search.ar_oid = *oid; | |||
| 818 | nregion = RB_NFIND(appl_regions, &(ctx->ac_regions), &search)appl_regions_RB_NFIND(&(ctx->ac_regions), &search); | |||
| 819 | ||||
| 820 | if (cregion == nregion) | |||
| ||||
| 821 | nregion = RB_NEXT(appl_regions, &(ctx->ac_regions), nregion)appl_regions_RB_NEXT(nregion); | |||
| 822 | /* Past last element in tree, we might still have a parent */ | |||
| 823 | if (nregion == NULL((void *)0)) { | |||
| 824 | search.ar_oid = cregion->ar_oid; | |||
| 825 | search.ar_oid.bo_n--; | |||
| 826 | return appl_region_find(ctx, &(search.ar_oid)); | |||
| 827 | } | |||
| 828 | cmp = appl_region_cmp(cregion, nregion); | |||
| 829 | if (cmp >= 0) | |||
| 830 | fatalx("%s: wrong OID order", __func__); | |||
| 831 | /* Direct descendant */ | |||
| 832 | if (cmp == -2) | |||
| 833 | return nregion; | |||
| 834 | ||||
| 835 | /* cmp == -1 */ | |||
| 836 | search.ar_oid = cregion->ar_oid; | |||
| ||||
| 837 | /* Find direct next sibling */ | |||
| 838 | ober_oid_nextsibling(&(search.ar_oid)); | |||
| 839 | if (ober_oid_cmp(&(nregion->ar_oid), &(search.ar_oid)) == 0) | |||
| 840 | return nregion; | |||
| 841 | /* Sibling gaps go to parent, or end end at border */ | |||
| 842 | search.ar_oid = cregion->ar_oid; | |||
| 843 | search.ar_oid.bo_n--; | |||
| 844 | pregion = appl_region_find(ctx, &(search.ar_oid)); | |||
| 845 | ||||
| 846 | return pregion != NULL((void *)0) ? pregion : nregion; | |||
| 847 | } | |||
| 848 | ||||
| 849 | /* Name from RFC 3413 section 3.2 */ | |||
| 850 | void | |||
| 851 | appl_processpdu(struct snmp_message *statereference, const char *ctxname, | |||
| 852 | enum snmp_version pduversion, struct ber_element *pdu) | |||
| 853 | { | |||
| 854 | struct appl_context *ctx; | |||
| 855 | struct appl_request_upstream *ureq; | |||
| 856 | struct ber_element *varbind, *varbindlist; | |||
| 857 | long long nonrepeaters, maxrepetitions; | |||
| 858 | static uint32_t transactionid; | |||
| 859 | int32_t requestid; | |||
| 860 | size_t i, varbindlen = 0, repeaterlen; | |||
| 861 | ||||
| 862 | /* pdu must be ASN.1 validated in snmpe.c */ | |||
| 863 | (void) ober_scanf_elements(pdu, "{diie", &requestid, &nonrepeaters, | |||
| 864 | &maxrepetitions, &varbindlist); | |||
| 865 | ||||
| 866 | /* RFC 3413, section 3.2, processPDU, item 5, final bullet */ | |||
| 867 | if ((ctx = appl_context(ctxname, 0)) == NULL((void *)0)) { | |||
| 868 | snmp_target_mib.snmp_unknowncontexts++; | |||
| 869 | appl_report(statereference, requestid, | |||
| 870 | &OID(MIB_snmpUnknownContexts, 0)(struct ber_oid){ { 1, 3, 6, 1, 6, 3, 12, 1, 5, 0 }, (sizeof( (uint32_t []) { 1, 3, 6, 1, 6, 3, 12, 1, 5, 0 }) / sizeof(uint32_t )) }); | |||
| 871 | return; | |||
| 872 | } | |||
| 873 | ||||
| 874 | if ((ureq = malloc(sizeof(*ureq))) == NULL((void *)0)) | |||
| 875 | fatal("malloc"); | |||
| 876 | ||||
| 877 | ureq->aru_ctx = ctx; | |||
| 878 | ureq->aru_statereference = statereference; | |||
| 879 | ureq->aru_transactionid = transactionid++; | |||
| 880 | ureq->aru_requesttype = pdu->be_type; | |||
| 881 | ureq->aru_responsetype = SNMP_C_RESPONSE; | |||
| 882 | ureq->aru_requestid = requestid; | |||
| 883 | ureq->aru_error = APPL_ERROR_NOERROR; | |||
| 884 | ureq->aru_index = 0; | |||
| 885 | ureq->aru_nonrepeaters = nonrepeaters; | |||
| 886 | ureq->aru_maxrepetitions = maxrepetitions; | |||
| 887 | ureq->aru_varbindlen = 0; | |||
| 888 | ureq->aru_locked = 0; | |||
| 889 | ureq->aru_pduversion = pduversion; | |||
| 890 | ||||
| 891 | varbind = varbindlist->be_subbe_union.bv_sub; | |||
| 892 | for (; varbind != NULL((void *)0); varbind = varbind->be_next) | |||
| 893 | varbindlen++; | |||
| 894 | ||||
| 895 | repeaterlen = varbindlen - nonrepeaters; | |||
| 896 | if (pdu->be_type == SNMP_C_GETBULKREQ) | |||
| 897 | ureq->aru_varbindlen = nonrepeaters + | |||
| 898 | (repeaterlen * maxrepetitions); | |||
| 899 | else | |||
| 900 | ureq->aru_varbindlen = varbindlen; | |||
| 901 | if ((ureq->aru_vblist = calloc(ureq->aru_varbindlen, | |||
| 902 | sizeof(*ureq->aru_vblist))) == NULL((void *)0)) | |||
| 903 | fatal("malloc"); | |||
| 904 | ||||
| 905 | varbind = varbindlist->be_subbe_union.bv_sub; | |||
| 906 | /* Use aru_varbindlen in case maxrepetitions == 0 */ | |||
| 907 | for (i = 0; i < ureq->aru_varbindlen; i++) { | |||
| 908 | ureq->aru_vblist[i].avi_request_upstream = ureq; | |||
| 909 | ureq->aru_vblist[i].avi_index = i + 1; | |||
| 910 | ureq->aru_vblist[i].avi_state = APPL_VBSTATE_NEW; | |||
| 911 | /* This can only happen with bulkreq */ | |||
| 912 | if (varbind == NULL((void *)0)) { | |||
| 913 | ureq->aru_vblist[i - repeaterlen].avi_sub = | |||
| 914 | &(ureq->aru_vblist[i]); | |||
| 915 | ureq->aru_vblist[i].avi_state = APPL_VBSTATE_MUSTFILL; | |||
| 916 | ureq->aru_vblist[i].avi_index = | |||
| 917 | ureq->aru_vblist[i - repeaterlen].avi_index; | |||
| 918 | continue; | |||
| 919 | } | |||
| 920 | ober_get_oid(varbind->be_subbe_union.bv_sub, | |||
| 921 | &(ureq->aru_vblist[i].avi_varbind.av_oid)); | |||
| 922 | ureq->aru_vblist[i].avi_origid = | |||
| 923 | ureq->aru_vblist[i].avi_varbind.av_oid; | |||
| 924 | if (i + 1 < varbindlen) | |||
| 925 | ureq->aru_vblist[i].avi_varbind.av_next = | |||
| 926 | &(ureq->aru_vblist[i + 1].avi_varbind); | |||
| 927 | else | |||
| 928 | ureq->aru_vblist[i].avi_varbind.av_next = NULL((void *)0); | |||
| 929 | varbind = varbind->be_next; | |||
| 930 | } | |||
| 931 | ||||
| 932 | appl_pdu_log(NULL((void *)0), pdu->be_type, requestid, nonrepeaters, | |||
| 933 | maxrepetitions, &(ureq->aru_vblist[0].avi_varbind)); | |||
| 934 | ||||
| 935 | appl_request_upstream_resolve(ureq); | |||
| 936 | } | |||
| 937 | ||||
| 938 | void | |||
| 939 | appl_request_upstream_free(struct appl_request_upstream *ureq) | |||
| 940 | { | |||
| 941 | size_t i; | |||
| 942 | struct appl_varbind_internal *vb; | |||
| 943 | ||||
| 944 | if (ureq == NULL((void *)0)) | |||
| 945 | return; | |||
| 946 | ||||
| 947 | ureq->aru_locked = 1; | |||
| 948 | for (i = 0; i < ureq->aru_varbindlen && ureq->aru_vblist != NULL((void *)0); i++) { | |||
| 949 | vb = &(ureq->aru_vblist[i]); | |||
| 950 | ober_free_elements(vb->avi_varbind.av_value); | |||
| 951 | appl_request_downstream_free(vb->avi_request_downstream); | |||
| 952 | } | |||
| 953 | free(ureq->aru_vblist); | |||
| 954 | ||||
| 955 | assert(ureq->aru_statereference == NULL)((ureq->aru_statereference == ((void *)0)) ? (void)0 : __assert2 ("/usr/src/usr.sbin/snmpd/application.c", 955, __func__, "ureq->aru_statereference == NULL" )); | |||
| 956 | ||||
| 957 | free(ureq); | |||
| 958 | } | |||
| 959 | ||||
| 960 | void | |||
| 961 | appl_request_downstream_free(struct appl_request_downstream *dreq) | |||
| 962 | { | |||
| 963 | struct appl_varbind_internal *vb; | |||
| 964 | ||||
| 965 | if (dreq == NULL((void *)0)) | |||
| 966 | return; | |||
| 967 | ||||
| 968 | RB_REMOVE(appl_requests, &(dreq->ard_backend->ab_requests), dreq)appl_requests_RB_REMOVE(&(dreq->ard_backend->ab_requests ), dreq); | |||
| 969 | evtimer_del(&(dreq->ard_timer))event_del(&(dreq->ard_timer)); | |||
| 970 | ||||
| 971 | for (vb = dreq->ard_vblist; vb != NULL((void *)0); vb = vb->avi_next) { | |||
| 972 | vb->avi_request_downstream = NULL((void *)0); | |||
| 973 | if (vb->avi_state == APPL_VBSTATE_PENDING) | |||
| 974 | vb->avi_state = APPL_VBSTATE_NEW; | |||
| 975 | } | |||
| 976 | ||||
| 977 | appl_request_upstream_resolve(dreq->ard_request); | |||
| 978 | free(dreq); | |||
| 979 | } | |||
| 980 | ||||
| 981 | void | |||
| 982 | appl_request_upstream_resolve(struct appl_request_upstream *ureq) | |||
| 983 | { | |||
| 984 | struct appl_varbind_internal *vb, *lvb, *tvb; | |||
| 985 | struct appl_request_downstream *dreq; | |||
| 986 | struct appl_region *region, *lregion; | |||
| 987 | struct timeval tv; | |||
| 988 | int done; | |||
| 989 | size_t i; | |||
| 990 | int32_t maxrepetitions; | |||
| 991 | int32_t timeout; | |||
| 992 | ||||
| 993 | if (ureq->aru_locked) | |||
| 994 | return; | |||
| 995 | ureq->aru_locked = 1; | |||
| 996 | ||||
| 997 | if (ureq->aru_requesttype == SNMP_C_SETREQ) { | |||
| 998 | ureq->aru_error = APPL_ERROR_NOTWRITABLE; | |||
| 999 | ureq->aru_index = 1; | |||
| 1000 | appl_request_upstream_reply(ureq); | |||
| 1001 | return; | |||
| 1002 | } | |||
| 1003 | ||||
| 1004 | next: | |||
| 1005 | dreq = NULL((void *)0); | |||
| 1006 | lvb = NULL((void *)0); | |||
| 1007 | done = 1; | |||
| 1008 | timeout = 0; | |||
| 1009 | ||||
| 1010 | if (ureq->aru_error != APPL_ERROR_NOERROR) { | |||
| 1011 | appl_request_upstream_reply(ureq); | |||
| 1012 | return; | |||
| 1013 | } | |||
| 1014 | for (i = 0; i < ureq->aru_varbindlen; i++) { | |||
| 1015 | vb = &(ureq->aru_vblist[i]); | |||
| 1016 | ||||
| 1017 | switch (vb->avi_state) { | |||
| 1018 | case APPL_VBSTATE_MUSTFILL: | |||
| 1019 | case APPL_VBSTATE_PENDING: | |||
| 1020 | done = 0; | |||
| 1021 | continue; | |||
| 1022 | case APPL_VBSTATE_DONE: | |||
| 1023 | continue; | |||
| 1024 | case APPL_VBSTATE_NEW: | |||
| 1025 | break; | |||
| 1026 | } | |||
| 1027 | if (appl_varbind_backend(vb) == -1) | |||
| 1028 | fatal("appl_varbind_backend"); | |||
| 1029 | if (vb->avi_state != APPL_VBSTATE_DONE) | |||
| 1030 | done = 0; | |||
| 1031 | } | |||
| 1032 | ||||
| 1033 | for (i = 0; i < ureq->aru_varbindlen; i++) { | |||
| 1034 | vb = &(ureq->aru_vblist[i]); | |||
| 1035 | ||||
| 1036 | if (vb->avi_state != APPL_VBSTATE_NEW) | |||
| 1037 | continue; | |||
| 1038 | ||||
| 1039 | vb = &(ureq->aru_vblist[i]); | |||
| 1040 | region = vb->avi_region; | |||
| 1041 | lregion = lvb != NULL((void *)0) ? lvb->avi_region : NULL((void *)0); | |||
| 1042 | if (lvb != NULL((void *)0) && region->ar_backend != lregion->ar_backend) | |||
| 1043 | continue; | |||
| 1044 | ||||
| 1045 | vb->avi_varbind.av_next = NULL((void *)0); | |||
| 1046 | vb->avi_next = NULL((void *)0); | |||
| 1047 | tvb = vb; | |||
| 1048 | for (maxrepetitions = 0; tvb != NULL((void *)0); tvb = tvb->avi_sub) | |||
| 1049 | maxrepetitions++; | |||
| 1050 | if (dreq == NULL((void *)0)) { | |||
| 1051 | if ((dreq = malloc(sizeof(*dreq))) == NULL((void *)0)) | |||
| 1052 | fatal("malloc"); | |||
| 1053 | ||||
| 1054 | dreq->ard_request = ureq; | |||
| 1055 | dreq->ard_vblist = vb; | |||
| 1056 | dreq->ard_backend = vb->avi_region->ar_backend; | |||
| 1057 | dreq->ard_retries = dreq->ard_backend->ab_retries; | |||
| 1058 | dreq->ard_requesttype = ureq->aru_requesttype; | |||
| 1059 | /* | |||
| 1060 | * We don't yet fully handle bulkrequest responses. | |||
| 1061 | * It's completely valid to map onto getrequest. | |||
| 1062 | * maxrepetitions calculated in preparation of support. | |||
| 1063 | */ | |||
| 1064 | if (dreq->ard_requesttype == SNMP_C_GETBULKREQ && | |||
| 1065 | dreq->ard_backend->ab_fn->ab_getbulk == NULL((void *)0)) | |||
| 1066 | dreq->ard_requesttype = SNMP_C_GETNEXTREQ; | |||
| 1067 | /* | |||
| 1068 | * If first varbind is nonrepeater, set maxrepetitions | |||
| 1069 | * to 0, so that the next varbind with | |||
| 1070 | * maxrepetitions > 1 determines length. | |||
| 1071 | */ | |||
| 1072 | if (maxrepetitions == 1) { | |||
| 1073 | dreq->ard_maxrepetitions = 0; | |||
| 1074 | dreq->ard_nonrepeaters = 1; | |||
| 1075 | } else { | |||
| 1076 | dreq->ard_maxrepetitions = maxrepetitions; | |||
| 1077 | dreq->ard_nonrepeaters = 0; | |||
| 1078 | } | |||
| 1079 | do { | |||
| 1080 | dreq->ard_requestid = arc4random(); | |||
| 1081 | } while (RB_INSERT(appl_requests,appl_requests_RB_INSERT(&(dreq->ard_backend->ab_requests ), dreq) | |||
| 1082 | &(dreq->ard_backend->ab_requests), dreq)appl_requests_RB_INSERT(&(dreq->ard_backend->ab_requests ), dreq) != NULL((void *)0)); | |||
| 1083 | lvb = vb; | |||
| 1084 | /* avi_sub isn't set on !bulkrequest, so we always enter here */ | |||
| 1085 | } else if (maxrepetitions == 1) { | |||
| 1086 | dreq->ard_nonrepeaters++; | |||
| 1087 | vb->avi_varbind.av_next = | |||
| 1088 | &(dreq->ard_vblist->avi_varbind); | |||
| 1089 | vb->avi_next = dreq->ard_vblist; | |||
| 1090 | dreq->ard_vblist = vb; | |||
| 1091 | } else { | |||
| 1092 | lvb->avi_varbind.av_next = &(vb->avi_varbind); | |||
| 1093 | lvb->avi_next = vb; | |||
| 1094 | /* RFC 2741 section 7.2.1.3: | |||
| 1095 | * The value of g.max_repetitions in the GetBulk-PDU may | |||
| 1096 | * be less than (but not greater than) the value in the | |||
| 1097 | * original request PDU. | |||
| 1098 | */ | |||
| 1099 | if (dreq->ard_maxrepetitions > maxrepetitions || | |||
| 1100 | dreq->ard_maxrepetitions == 0) | |||
| 1101 | dreq->ard_maxrepetitions = maxrepetitions; | |||
| 1102 | lvb = vb; | |||
| 1103 | } | |||
| 1104 | vb->avi_request_downstream = dreq; | |||
| 1105 | vb->avi_state = APPL_VBSTATE_PENDING; | |||
| 1106 | if (region->ar_timeout > timeout) | |||
| 1107 | timeout = region->ar_timeout; | |||
| 1108 | } | |||
| 1109 | ||||
| 1110 | if (dreq == NULL((void *)0)) { | |||
| 1111 | ureq->aru_locked = 0; | |||
| 1112 | if (done) | |||
| 1113 | appl_request_upstream_reply(ureq); | |||
| 1114 | return; | |||
| 1115 | } | |||
| 1116 | ||||
| 1117 | tv.tv_sec = timeout / 100; | |||
| 1118 | tv.tv_usec = (timeout % 100) * 10000; | |||
| 1119 | evtimer_set(&(dreq->ard_timer), appl_request_downstream_timeout, dreq)event_set(&(dreq->ard_timer), -1, 0, appl_request_downstream_timeout , dreq); | |||
| 1120 | evtimer_add(&(dreq->ard_timer), &tv)event_add(&(dreq->ard_timer), &tv); | |||
| 1121 | ||||
| 1122 | appl_request_downstream_send(dreq); | |||
| 1123 | goto next; | |||
| 1124 | } | |||
| 1125 | ||||
| 1126 | void | |||
| 1127 | appl_request_downstream_send(struct appl_request_downstream *dreq) | |||
| 1128 | { | |||
| 1129 | ||||
| 1130 | appl_pdu_log(dreq->ard_backend, dreq->ard_requesttype, | |||
| 1131 | dreq->ard_requestid, 0, 0, &(dreq->ard_vblist->avi_varbind)); | |||
| 1132 | ||||
| 1133 | if (dreq->ard_requesttype == SNMP_C_GETREQ) { | |||
| 1134 | dreq->ard_backend->ab_fn->ab_get(dreq->ard_backend, | |||
| 1135 | dreq->ard_request->aru_transactionid, | |||
| 1136 | dreq->ard_requestid, | |||
| 1137 | APPL_CONTEXT_NAME(dreq->ard_request->aru_ctx)(dreq->ard_request->aru_ctx->ac_name[0] == '\0' ? (( void *)0) : dreq->ard_request->aru_ctx->ac_name), | |||
| 1138 | &(dreq->ard_vblist->avi_varbind)); | |||
| 1139 | } else if (dreq->ard_requesttype == SNMP_C_GETNEXTREQ) { | |||
| 1140 | dreq->ard_backend->ab_fn->ab_getnext(dreq->ard_backend, | |||
| 1141 | dreq->ard_request->aru_transactionid, | |||
| 1142 | dreq->ard_requestid, | |||
| 1143 | APPL_CONTEXT_NAME(dreq->ard_request->aru_ctx)(dreq->ard_request->aru_ctx->ac_name[0] == '\0' ? (( void *)0) : dreq->ard_request->aru_ctx->ac_name), | |||
| 1144 | &(dreq->ard_vblist->avi_varbind)); | |||
| 1145 | } | |||
| 1146 | } | |||
| 1147 | ||||
| 1148 | void | |||
| 1149 | appl_request_downstream_timeout(__unused__attribute__((__unused__)) int fd, __unused__attribute__((__unused__)) short event, | |||
| 1150 | void *cookie) | |||
| 1151 | { | |||
| 1152 | struct appl_request_downstream *dreq = cookie; | |||
| 1153 | ||||
| 1154 | log_info("%s: %"PRIu32"u"" timed out%s", | |||
| 1155 | dreq->ard_backend->ab_name, dreq->ard_requestid, | |||
| 1156 | dreq->ard_retries > 0 ? ": retrying" : ""); | |||
| 1157 | if (dreq->ard_retries > 0) { | |||
| 1158 | dreq->ard_retries--; | |||
| 1159 | appl_request_downstream_send(dreq); | |||
| 1160 | } else | |||
| 1161 | appl_response(dreq->ard_backend, dreq->ard_requestid, | |||
| 1162 | APPL_ERROR_GENERR, 1, &(dreq->ard_vblist->avi_varbind)); | |||
| 1163 | } | |||
| 1164 | ||||
| 1165 | void | |||
| 1166 | appl_request_upstream_reply(struct appl_request_upstream *ureq) | |||
| 1167 | { | |||
| 1168 | struct ber_element *varbindlist = NULL((void *)0), *varbind = NULL((void *)0), *value; | |||
| 1169 | struct appl_varbind_internal *vb; | |||
| 1170 | size_t i, repvarbinds, varbindlen; | |||
| 1171 | ssize_t match = -1; | |||
| 1172 | ||||
| 1173 | varbindlen = ureq->aru_varbindlen; | |||
| 1174 | ||||
| 1175 | if (ureq->aru_pduversion == SNMP_V1) { | |||
| 1176 | /* RFC 3584 section 4.2.2.2 Map exceptions */ | |||
| 1177 | for (i = 0; i < varbindlen; i++) { | |||
| 1178 | vb = &(ureq->aru_vblist[i]); | |||
| 1179 | value = vb->avi_varbind.av_value; | |||
| 1180 | if (value != NULL((void *)0) && | |||
| 1181 | value->be_class == BER_CLASS_CONTEXT0x2) | |||
| 1182 | appl_varbind_error(vb, APPL_ERROR_NOSUCHNAME); | |||
| 1183 | } | |||
| 1184 | /* RFC 3584 section 4.4 Map errors */ | |||
| 1185 | switch (ureq->aru_error) { | |||
| 1186 | case APPL_ERROR_WRONGVALUE: | |||
| 1187 | case APPL_ERROR_WRONGENCODING: | |||
| 1188 | case APPL_ERROR_WRONGTYPE: | |||
| 1189 | case APPL_ERROR_WRONGLENGTH: | |||
| 1190 | case APPL_ERROR_INCONSISTENTVALUE: | |||
| 1191 | ureq->aru_error = APPL_ERROR_BADVALUE; | |||
| 1192 | break; | |||
| 1193 | case APPL_ERROR_NOACCESS: | |||
| 1194 | case APPL_ERROR_NOTWRITABLE: | |||
| 1195 | case APPL_ERROR_NOCREATION: | |||
| 1196 | case APPL_ERROR_INCONSISTENTNAME: | |||
| 1197 | case APPL_ERROR_AUTHORIZATIONERROR: | |||
| 1198 | ureq->aru_error = APPL_ERROR_NOSUCHNAME; | |||
| 1199 | break; | |||
| 1200 | case APPL_ERROR_RESOURCEUNAVAILABLE: | |||
| 1201 | case APPL_ERROR_COMMITFAILED: | |||
| 1202 | case APPL_ERROR_UNDOFAILED: | |||
| 1203 | ureq->aru_error = APPL_ERROR_GENERR; | |||
| 1204 | break; | |||
| 1205 | default: | |||
| 1206 | break; | |||
| 1207 | } | |||
| 1208 | } | |||
| 1209 | /* RFC 3416 section 4.2.{1,2,3} reset original varbinds */ | |||
| 1210 | if (ureq->aru_error != APPL_ERROR_NOERROR) { | |||
| 1211 | if (ureq->aru_requesttype == SNMP_C_GETBULKREQ) | |||
| 1212 | varbindlen = | |||
| 1213 | (ureq->aru_varbindlen - ureq->aru_nonrepeaters) / | |||
| 1214 | ureq->aru_maxrepetitions; | |||
| 1215 | for (i = 0; i < varbindlen; i++) { | |||
| 1216 | vb = &(ureq->aru_vblist[i]); | |||
| 1217 | vb->avi_varbind.av_oid = vb->avi_origid; | |||
| 1218 | ober_free_elements(vb->avi_varbind.av_value); | |||
| 1219 | vb->avi_varbind.av_value = ober_add_null(NULL((void *)0)); | |||
| 1220 | } | |||
| 1221 | /* RFC 3416 section 4.2.3: Strip excessive EOMV */ | |||
| 1222 | } else if (ureq->aru_requesttype == SNMP_C_GETBULKREQ) { | |||
| 1223 | repvarbinds = (ureq->aru_varbindlen - ureq->aru_nonrepeaters) / | |||
| 1224 | ureq->aru_maxrepetitions; | |||
| 1225 | for (i = ureq->aru_nonrepeaters; | |||
| 1226 | i < ureq->aru_varbindlen - repvarbinds; i++) { | |||
| 1227 | value = ureq->aru_vblist[i].avi_varbind.av_value; | |||
| 1228 | if ((i - ureq->aru_nonrepeaters) % repvarbinds == 0 && | |||
| 1229 | value->be_class == BER_CLASS_CONTEXT0x2 && | |||
| 1230 | value->be_type == APPL_EXC_ENDOFMIBVIEW) { | |||
| 1231 | if (match != -1) | |||
| 1232 | break; | |||
| 1233 | match = i; | |||
| 1234 | } | |||
| 1235 | if (value->be_class != BER_CLASS_CONTEXT0x2 || | |||
| 1236 | value->be_type != APPL_EXC_ENDOFMIBVIEW) | |||
| 1237 | match = -1; | |||
| 1238 | } | |||
| 1239 | if (match != -1) | |||
| 1240 | varbindlen = match + repvarbinds; | |||
| 1241 | } | |||
| 1242 | ||||
| 1243 | for (i = 0; i < varbindlen; i++) { | |||
| 1244 | vb = &(ureq->aru_vblist[i]); | |||
| 1245 | vb->avi_varbind.av_next = | |||
| 1246 | &(ureq->aru_vblist[i + 1].avi_varbind); | |||
| 1247 | value = vb->avi_varbind.av_value; | |||
| 1248 | if (value->be_class == BER_CLASS_CONTEXT0x2 && | |||
| 1249 | value->be_type == APPL_EXC_ENDOFMIBVIEW) | |||
| 1250 | vb->avi_varbind.av_oid = vb->avi_origid; | |||
| 1251 | } | |||
| 1252 | ||||
| 1253 | ureq->aru_vblist[i - 1].avi_varbind.av_next = NULL((void *)0); | |||
| 1254 | appl_pdu_log(NULL((void *)0), ureq->aru_responsetype, ureq->aru_requestid, | |||
| 1255 | ureq->aru_error, ureq->aru_index, | |||
| 1256 | &(ureq->aru_vblist[0].avi_varbind)); | |||
| 1257 | ||||
| 1258 | for (i = 0; i < varbindlen; i++) { | |||
| 1259 | varbind = ober_printf_elements(varbind, "{Oe}", | |||
| 1260 | &(ureq->aru_vblist[i].avi_varbind.av_oid), | |||
| 1261 | ureq->aru_vblist[i].avi_varbind.av_value); | |||
| 1262 | ureq->aru_vblist[i].avi_varbind.av_value = NULL((void *)0); | |||
| 1263 | if (varbind == NULL((void *)0)) | |||
| 1264 | fatal("ober_printf_elements"); | |||
| 1265 | if (varbindlist == NULL((void *)0)) | |||
| 1266 | varbindlist = varbind; | |||
| 1267 | } | |||
| 1268 | ||||
| 1269 | snmpe_send(ureq->aru_statereference, ureq->aru_responsetype, | |||
| 1270 | ureq->aru_requestid, ureq->aru_error, ureq->aru_index, varbindlist); | |||
| 1271 | ureq->aru_statereference = NULL((void *)0); | |||
| 1272 | appl_request_upstream_free(ureq); | |||
| 1273 | } | |||
| 1274 | ||||
| 1275 | /* Name from RFC 2741 section 6.2.16 */ | |||
| 1276 | void | |||
| 1277 | appl_response(struct appl_backend *backend, int32_t requestid, | |||
| 1278 | enum appl_error error, int16_t index, struct appl_varbind *vblist) | |||
| 1279 | { | |||
| 1280 | struct appl_request_downstream *dreq, search; | |||
| 1281 | struct appl_request_upstream *ureq = NULL((void *)0); | |||
| 1282 | const char *errstr; | |||
| 1283 | char oidbuf[1024]; | |||
| 1284 | struct appl_varbind *vb; | |||
| 1285 | struct appl_varbind_internal *origvb = NULL((void *)0); | |||
| 1286 | int invalid = 0; | |||
| 1287 | int next = 0, eomv; | |||
| 1288 | int32_t i; | |||
| 1289 | ||||
| 1290 | appl_pdu_log(backend, SNMP_C_RESPONSE, requestid, error, index, vblist); | |||
| 1291 | ||||
| 1292 | search.ard_requestid = requestid; | |||
| 1293 | dreq = RB_FIND(appl_requests, &(backend->ab_requests), &search)appl_requests_RB_FIND(&(backend->ab_requests), &search ); | |||
| 1294 | if (dreq == NULL((void *)0)) { | |||
| 1295 | log_debug("%s: %"PRIu32"u"" not outstanding", | |||
| 1296 | backend->ab_name, requestid); | |||
| 1297 | /* Continue to verify validity */ | |||
| 1298 | } else { | |||
| 1299 | ureq = dreq->ard_request; | |||
| 1300 | next = ureq->aru_requesttype == SNMP_C_GETNEXTREQ || | |||
| 1301 | ureq->aru_requesttype == SNMP_C_GETBULKREQ; | |||
| 1302 | origvb = dreq->ard_vblist; | |||
| 1303 | if (!appl_error_valid(error, dreq->ard_requesttype)) { | |||
| 1304 | log_warnx("%s: %"PRIu32"u"" Invalid error", | |||
| 1305 | backend->ab_name, requestid); | |||
| 1306 | invalid = 1; | |||
| 1307 | } | |||
| 1308 | } | |||
| 1309 | ||||
| 1310 | vb = vblist; | |||
| 1311 | for (i = 1; vb != NULL((void *)0); vb = vb->av_next, i++) { | |||
| 1312 | if (!appl_varbind_valid(vb, origvb, next, | |||
| 1313 | error != APPL_ERROR_NOERROR, backend->ab_range, &errstr)) { | |||
| 1314 | smi_oid2string(&(vb->av_oid), oidbuf, | |||
| 1315 | sizeof(oidbuf), 0); | |||
| 1316 | log_warnx("%s: %"PRIu32"u"" %s: %s", | |||
| 1317 | backend->ab_name, requestid, oidbuf, errstr); | |||
| 1318 | invalid = 1; | |||
| 1319 | } | |||
| 1320 | /* Transfer av_value */ | |||
| 1321 | if (origvb != NULL((void *)0)) { | |||
| 1322 | if (error != APPL_ERROR_NOERROR && i == index) | |||
| 1323 | appl_varbind_error(origvb, error); | |||
| 1324 | origvb->avi_state = APPL_VBSTATE_DONE; | |||
| 1325 | origvb->avi_varbind.av_oid = vb->av_oid; | |||
| 1326 | ||||
| 1327 | eomv = vb->av_value != NULL((void *)0) && | |||
| 1328 | vb->av_value->be_class == BER_CLASS_CONTEXT0x2 && | |||
| 1329 | vb->av_value->be_type == APPL_EXC_ENDOFMIBVIEW; | |||
| 1330 | /* | |||
| 1331 | * Treat results past av_oid_end for backends that | |||
| 1332 | * don't support searchranges as EOMV | |||
| 1333 | */ | |||
| 1334 | eomv |= !backend->ab_range && next && | |||
| 1335 | ober_oid_cmp(&(vb->av_oid), | |||
| 1336 | &(origvb->avi_varbind.av_oid_end)) >= 0; | |||
| 1337 | /* RFC 3584 section 4.2.2.1 */ | |||
| 1338 | if (ureq->aru_pduversion == SNMP_V1 && | |||
| 1339 | vb->av_value != NULL((void *)0) && | |||
| 1340 | vb->av_value->be_class == BER_CLASS_APPLICATION0x1 && | |||
| 1341 | vb->av_value->be_type == SNMP_COUNTER64) { | |||
| 1342 | if (next) | |||
| 1343 | eomv = 1; | |||
| 1344 | else | |||
| 1345 | appl_varbind_error(origvb, | |||
| 1346 | APPL_ERROR_NOSUCHNAME); | |||
| 1347 | } | |||
| 1348 | ||||
| 1349 | if (eomv) { | |||
| 1350 | ober_free_elements(vb->av_value); | |||
| 1351 | origvb->avi_varbind.av_oid = | |||
| 1352 | origvb->avi_varbind.av_oid_end; | |||
| 1353 | origvb->avi_varbind.av_include = 1; | |||
| 1354 | vb->av_value = NULL((void *)0); | |||
| 1355 | origvb->avi_state = APPL_VBSTATE_NEW; | |||
| 1356 | } | |||
| 1357 | origvb->avi_varbind.av_value = vb->av_value; | |||
| 1358 | if (origvb->avi_varbind.av_next == NULL((void *)0) && | |||
| 1359 | vb->av_next != NULL((void *)0)) { | |||
| 1360 | log_warnx("%s: Request %"PRIu32"u"" returned more " | |||
| 1361 | "varbinds then requested", | |||
| 1362 | backend->ab_name, requestid); | |||
| 1363 | invalid = 1; | |||
| 1364 | } | |||
| 1365 | if (origvb->avi_sub != NULL((void *)0) && | |||
| 1366 | origvb->avi_state == APPL_VBSTATE_DONE) { | |||
| 1367 | origvb->avi_sub->avi_varbind.av_oid = | |||
| 1368 | origvb->avi_varbind.av_oid; | |||
| 1369 | origvb->avi_sub->avi_origid = | |||
| 1370 | origvb->avi_varbind.av_oid; | |||
| 1371 | origvb->avi_sub->avi_state = APPL_VBSTATE_NEW; | |||
| 1372 | } | |||
| 1373 | origvb = origvb->avi_next; | |||
| 1374 | } else { | |||
| 1375 | ober_free_elements(vb->av_value); | |||
| 1376 | vb->av_value = NULL((void *)0); | |||
| 1377 | } | |||
| 1378 | } | |||
| 1379 | if (error != APPL_ERROR_NOERROR && (index <= 0 || index >= i)) { | |||
| 1380 | log_warnx("Invalid error index"); | |||
| 1381 | invalid = 1; | |||
| 1382 | } | |||
| 1383 | /* amavisd-snmp-subagent sets index to 1, no reason to crash over it. */ | |||
| 1384 | #if PEDANTIC | |||
| 1385 | if (error == APPL_ERROR_NOERROR && index != 0) { | |||
| 1386 | log_warnx("error index with no error"); | |||
| 1387 | invalid = 1; | |||
| 1388 | } | |||
| 1389 | #endif | |||
| 1390 | if (vb == NULL((void *)0) && origvb != NULL((void *)0)) { | |||
| 1391 | log_warnx("%s: Request %"PRIu32"u"" returned less varbinds then " | |||
| 1392 | "requested", backend->ab_name, requestid); | |||
| 1393 | invalid = 1; | |||
| 1394 | } | |||
| 1395 | ||||
| 1396 | if (dreq != NULL((void *)0)) { | |||
| 1397 | if (invalid) | |||
| 1398 | appl_varbind_error(dreq->ard_vblist, APPL_ERROR_GENERR); | |||
| 1399 | appl_request_downstream_free(dreq); | |||
| 1400 | } | |||
| 1401 | ||||
| 1402 | if (invalid && backend->ab_fn->ab_close != NULL((void *)0)) { | |||
| 1403 | log_warnx("%s: Closing: Too many parse errors", | |||
| 1404 | backend->ab_name); | |||
| 1405 | backend->ab_fn->ab_close(backend, APPL_CLOSE_REASONPARSEERROR); | |||
| 1406 | } | |||
| 1407 | } | |||
| 1408 | ||||
| 1409 | int | |||
| 1410 | appl_varbind_valid(struct appl_varbind *varbind, | |||
| 1411 | struct appl_varbind_internal *request, int next, int null, int range, | |||
| 1412 | const char **errstr) | |||
| 1413 | { | |||
| 1414 | int cmp; | |||
| 1415 | int eomv = 0; | |||
| 1416 | ||||
| 1417 | if (null) | |||
| 1418 | next = 0; | |||
| 1419 | ||||
| 1420 | if (varbind->av_value == NULL((void *)0)) { | |||
| 1421 | if (!null) { | |||
| 1422 | *errstr = "missing value"; | |||
| 1423 | return 0; | |||
| 1424 | } | |||
| 1425 | return 1; | |||
| 1426 | } | |||
| 1427 | if (varbind->av_value->be_class == BER_CLASS_UNIVERSAL0x0) { | |||
| 1428 | switch (varbind->av_value->be_type) { | |||
| 1429 | case BER_TYPE_NULL5: | |||
| 1430 | if (null) | |||
| 1431 | break; | |||
| 1432 | *errstr = "not expecting null value"; | |||
| 1433 | return 0; | |||
| 1434 | case BER_TYPE_INTEGER2: | |||
| 1435 | case BER_TYPE_OCTETSTRING4: | |||
| 1436 | case BER_TYPE_OBJECT6: | |||
| 1437 | if (!null) | |||
| 1438 | break; | |||
| 1439 | /* FALLTHROUGH */ | |||
| 1440 | default: | |||
| 1441 | *errstr = "invalid value"; | |||
| 1442 | return 0; | |||
| 1443 | } | |||
| 1444 | } else if (varbind->av_value->be_class == BER_CLASS_APPLICATION0x1) { | |||
| 1445 | switch (varbind->av_value->be_type) { | |||
| 1446 | case SNMP_T_IPADDR: | |||
| 1447 | case SNMP_T_COUNTER32: | |||
| 1448 | case SNMP_T_GAUGE32: | |||
| 1449 | case SNMP_T_TIMETICKS: | |||
| 1450 | case SNMP_T_OPAQUE: | |||
| 1451 | case SNMP_T_COUNTER64: | |||
| 1452 | if (!null) | |||
| 1453 | break; | |||
| 1454 | /* FALLTHROUGH */ | |||
| 1455 | default: | |||
| 1456 | *errstr = "expecting null value"; | |||
| 1457 | return 0; | |||
| 1458 | } | |||
| 1459 | } else if (varbind->av_value->be_class == BER_CLASS_CONTEXT0x2) { | |||
| 1460 | switch (varbind->av_value->be_type) { | |||
| 1461 | case APPL_EXC_NOSUCHOBJECT: | |||
| 1462 | if (next && request != NULL((void *)0)) { | |||
| 1463 | *errstr = "Unexpected noSuchObject"; | |||
| 1464 | return 0; | |||
| 1465 | } | |||
| 1466 | /* FALLTHROUGH */ | |||
| 1467 | case APPL_EXC_NOSUCHINSTANCE: | |||
| 1468 | if (null) { | |||
| 1469 | *errstr = "expecting null value"; | |||
| 1470 | return 0; | |||
| 1471 | } | |||
| 1472 | if (next && request != NULL((void *)0)) { | |||
| 1473 | *errstr = "Unexpected noSuchInstance"; | |||
| 1474 | return 0; | |||
| 1475 | } | |||
| 1476 | break; | |||
| 1477 | case APPL_EXC_ENDOFMIBVIEW: | |||
| 1478 | if (null) { | |||
| 1479 | *errstr = "expecting null value"; | |||
| 1480 | return 0; | |||
| 1481 | } | |||
| 1482 | if (!next && request != NULL((void *)0)) { | |||
| 1483 | *errstr = "Unexpected endOfMibView"; | |||
| 1484 | return 0; | |||
| 1485 | } | |||
| 1486 | eomv = 1; | |||
| 1487 | break; | |||
| 1488 | default: | |||
| 1489 | *errstr = "invalid exception"; | |||
| 1490 | return 0; | |||
| 1491 | } | |||
| 1492 | } else { | |||
| 1493 | *errstr = "invalid value"; | |||
| 1494 | return 0; | |||
| 1495 | } | |||
| 1496 | ||||
| 1497 | if (request == NULL((void *)0)) | |||
| 1498 | return 1; | |||
| 1499 | ||||
| 1500 | cmp = ober_oid_cmp(&(request->avi_varbind.av_oid), &(varbind->av_oid)); | |||
| 1501 | if (next) { | |||
| 1502 | if (request->avi_region->ar_instance && | |||
| 1503 | ober_oid_cmp(&(request->avi_region->ar_oid), | |||
| 1504 | &(varbind->av_oid)) != 0) { | |||
| 1505 | *errstr = "oid below instance"; | |||
| 1506 | return 0; | |||
| 1507 | } | |||
| 1508 | if (!eomv) { | |||
| 1509 | if (request->avi_varbind.av_include) { | |||
| 1510 | if (cmp > 0) { | |||
| 1511 | *errstr = "oid not incrementing"; | |||
| 1512 | return 0; | |||
| 1513 | } | |||
| 1514 | } else { | |||
| 1515 | if (cmp >= 0) { | |||
| 1516 | *errstr = "oid not incrementing"; | |||
| 1517 | return 0; | |||
| 1518 | } | |||
| 1519 | } | |||
| 1520 | if (range && ober_oid_cmp(&(varbind->av_oid), | |||
| 1521 | &(request->avi_varbind.av_oid_end)) >= 0) { | |||
| 1522 | *errstr = "end oid not honoured"; | |||
| 1523 | return 0; | |||
| 1524 | } | |||
| 1525 | } | |||
| 1526 | } else { | |||
| 1527 | if (cmp != 0) { | |||
| 1528 | *errstr = "oids not equal"; | |||
| 1529 | return 0; | |||
| 1530 | } | |||
| 1531 | } | |||
| 1532 | return 1; | |||
| 1533 | } | |||
| 1534 | ||||
| 1535 | int | |||
| 1536 | appl_error_valid(enum appl_error error, enum snmp_pdutype type) | |||
| 1537 | { | |||
| 1538 | switch (error) { | |||
| 1539 | case APPL_ERROR_NOERROR: | |||
| 1540 | case APPL_ERROR_TOOBIG: | |||
| 1541 | case APPL_ERROR_NOSUCHNAME: | |||
| 1542 | case APPL_ERROR_GENERR: | |||
| 1543 | return 1; | |||
| 1544 | case APPL_ERROR_BADVALUE: | |||
| 1545 | case APPL_ERROR_READONLY: | |||
| 1546 | case APPL_ERROR_NOACCESS: | |||
| 1547 | case APPL_ERROR_WRONGTYPE: | |||
| 1548 | case APPL_ERROR_WRONGLENGTH: | |||
| 1549 | case APPL_ERROR_WRONGENCODING: | |||
| 1550 | case APPL_ERROR_WRONGVALUE: | |||
| 1551 | case APPL_ERROR_NOCREATION: | |||
| 1552 | case APPL_ERROR_INCONSISTENTVALUE: | |||
| 1553 | case APPL_ERROR_RESOURCEUNAVAILABLE: | |||
| 1554 | case APPL_ERROR_COMMITFAILED: | |||
| 1555 | case APPL_ERROR_UNDOFAILED: | |||
| 1556 | case APPL_ERROR_NOTWRITABLE: | |||
| 1557 | case APPL_ERROR_INCONSISTENTNAME: | |||
| 1558 | return type == SNMP_C_SETREQ; | |||
| 1559 | case APPL_ERROR_AUTHORIZATIONERROR: | |||
| 1560 | return type == SNMP_C_GETREQ || type == SNMP_C_SETREQ; | |||
| 1561 | default: | |||
| 1562 | return 0; | |||
| 1563 | } | |||
| 1564 | } | |||
| 1565 | ||||
| 1566 | int | |||
| 1567 | appl_varbind_backend(struct appl_varbind_internal *ivb) | |||
| 1568 | { | |||
| 1569 | struct appl_request_upstream *ureq = ivb->avi_request_upstream; | |||
| 1570 | struct appl_region search, *region, *pregion; | |||
| 1571 | struct appl_varbind *vb = &(ivb->avi_varbind); | |||
| 1572 | struct ber_oid oid, nextsibling; | |||
| 1573 | int next, cmp; | |||
| 1574 | ||||
| 1575 | next = ureq->aru_requesttype == SNMP_C_GETNEXTREQ || | |||
| 1576 | ureq->aru_requesttype == SNMP_C_GETBULKREQ; | |||
| 1577 | ||||
| 1578 | region = appl_region_find(ureq->aru_ctx, &(vb->av_oid)); | |||
| 1579 | if (region == NULL((void *)0)) { | |||
| 1580 | if (!next) { | |||
| 1581 | vb->av_value = appl_exception(APPL_EXC_NOSUCHOBJECT); | |||
| 1582 | ivb->avi_state = APPL_VBSTATE_DONE; | |||
| 1583 | if (vb->av_value == NULL((void *)0)) | |||
| 1584 | return -1; | |||
| 1585 | return 0; | |||
| 1586 | } | |||
| 1587 | search.ar_oid = vb->av_oid; | |||
| 1588 | region = RB_NFIND(appl_regions,appl_regions_RB_NFIND(&(ureq->aru_ctx->ac_regions), &search) | |||
| 1589 | &(ureq->aru_ctx->ac_regions), &search)appl_regions_RB_NFIND(&(ureq->aru_ctx->ac_regions), &search); | |||
| 1590 | if (region == NULL((void *)0)) | |||
| 1591 | goto eomv; | |||
| 1592 | vb->av_oid = region->ar_oid; | |||
| 1593 | vb->av_include = 1; | |||
| 1594 | } | |||
| 1595 | cmp = ober_oid_cmp(&(region->ar_oid), &(vb->av_oid)); | |||
| 1596 | if (cmp == -2) { | |||
| 1597 | if (region->ar_instance) { | |||
| 1598 | if (!next) { | |||
| 1599 | vb->av_value = | |||
| 1600 | appl_exception(APPL_EXC_NOSUCHINSTANCE); | |||
| 1601 | ivb->avi_state = APPL_VBSTATE_DONE; | |||
| 1602 | if (vb->av_value == NULL((void *)0)) | |||
| 1603 | return -1; | |||
| 1604 | return 0; | |||
| 1605 | } | |||
| 1606 | vb->av_oid = region->ar_oid; | |||
| 1607 | ober_oid_nextsibling(&(vb->av_oid)); | |||
| 1608 | vb->av_include = 1; | |||
| 1609 | return appl_varbind_backend(ivb); | |||
| 1610 | } | |||
| 1611 | } else if (cmp == 0) { | |||
| 1612 | if (region->ar_instance && next && !vb->av_include) { | |||
| 1613 | vb->av_oid = region->ar_oid; | |||
| 1614 | ober_oid_nextsibling(&(vb->av_oid)); | |||
| 1615 | vb->av_include = 1; | |||
| 1616 | return appl_varbind_backend(ivb); | |||
| 1617 | } | |||
| 1618 | } | |||
| 1619 | ivb->avi_region = region; | |||
| 1620 | if (next) { | |||
| 1621 | oid = vb->av_oid; | |||
| 1622 | /* | |||
| 1623 | * For the searchrange end we only want contiguous regions. | |||
| 1624 | * This means directly connecting, or overlapping with the same | |||
| 1625 | * backend. | |||
| 1626 | */ | |||
| 1627 | do { | |||
| 1628 | pregion = region; | |||
| 1629 | region = appl_region_next(ureq->aru_ctx, &oid, pregion); | |||
| 1630 | if (region == NULL((void *)0)) { | |||
| 1631 | oid = pregion->ar_oid; | |||
| 1632 | ober_oid_nextsibling(&oid); | |||
| 1633 | break; | |||
| 1634 | } | |||
| 1635 | cmp = ober_oid_cmp(&(region->ar_oid), &oid); | |||
| 1636 | if (cmp == 2) | |||
| 1637 | oid = region->ar_oid; | |||
| 1638 | else if (cmp == 1) { | |||
| 1639 | /* Break out if we find a gap */ | |||
| 1640 | nextsibling = pregion->ar_oid; | |||
| 1641 | ober_oid_nextsibling(&nextsibling); | |||
| 1642 | if (ober_oid_cmp(&(region->ar_oid), | |||
| 1643 | &nextsibling) != 0) { | |||
| 1644 | oid = pregion->ar_oid; | |||
| 1645 | ober_oid_nextsibling(&oid); | |||
| 1646 | break; | |||
| 1647 | } | |||
| 1648 | oid = region->ar_oid; | |||
| 1649 | } else if (cmp == -2) { | |||
| 1650 | oid = pregion->ar_oid; | |||
| 1651 | ober_oid_nextsibling(&oid); | |||
| 1652 | } else | |||
| 1653 | fatalx("We can't stop/move back on getnext"); | |||
| 1654 | } while (region->ar_backend == pregion->ar_backend); | |||
| 1655 | vb->av_oid_end = oid; | |||
| 1656 | } | |||
| 1657 | return 0; | |||
| 1658 | ||||
| 1659 | eomv: | |||
| 1660 | do { | |||
| 1661 | ivb->avi_varbind.av_value = | |||
| 1662 | appl_exception(APPL_EXC_ENDOFMIBVIEW); | |||
| 1663 | ivb->avi_state = APPL_VBSTATE_DONE; | |||
| 1664 | if (ivb->avi_varbind.av_value == NULL((void *)0)) | |||
| 1665 | return -1; | |||
| 1666 | if (ivb->avi_sub != NULL((void *)0)) { | |||
| 1667 | ivb->avi_sub->avi_varbind.av_oid = | |||
| 1668 | ivb->avi_varbind.av_oid; | |||
| 1669 | ivb->avi_sub->avi_origid = ivb->avi_origid; | |||
| 1670 | } | |||
| 1671 | ivb = ivb->avi_sub; | |||
| 1672 | } while (ivb != NULL((void *)0)); | |||
| 1673 | ||||
| 1674 | return 0; | |||
| 1675 | } | |||
| 1676 | ||||
| 1677 | void | |||
| 1678 | appl_varbind_error(struct appl_varbind_internal *avi, enum appl_error error) | |||
| 1679 | { | |||
| 1680 | struct appl_request_upstream *ureq = avi->avi_request_upstream; | |||
| 1681 | ||||
| 1682 | if (ureq->aru_error == APPL_ERROR_GENERR) | |||
| 1683 | return; | |||
| 1684 | if (ureq->aru_error != APPL_ERROR_NOERROR && error != APPL_ERROR_GENERR) | |||
| 1685 | return; | |||
| 1686 | ureq->aru_error = error; | |||
| 1687 | ureq->aru_index = avi->avi_index; | |||
| 1688 | } | |||
| 1689 | ||||
| 1690 | void | |||
| 1691 | appl_report(struct snmp_message *statereference, int32_t requestid, | |||
| 1692 | struct ber_oid *oid) | |||
| 1693 | { | |||
| 1694 | struct appl_request_upstream *ureq; | |||
| 1695 | ||||
| 1696 | if ((ureq = calloc(1, sizeof(*ureq))) == NULL((void *)0)) | |||
| 1697 | fatal("malloc"); | |||
| 1698 | ureq->aru_ctx = appl_context(NULL((void *)0), 0); | |||
| 1699 | ureq->aru_statereference = statereference; | |||
| 1700 | ureq->aru_requesttype = SNMP_C_GETREQ; | |||
| 1701 | ureq->aru_responsetype = SNMP_C_REPORT; | |||
| 1702 | ureq->aru_requestid = requestid; | |||
| 1703 | ureq->aru_transactionid = 0; | |||
| 1704 | ureq->aru_nonrepeaters = 0; | |||
| 1705 | ureq->aru_maxrepetitions = 0; | |||
| 1706 | if ((ureq->aru_vblist = calloc(1, sizeof(*ureq->aru_vblist))) == NULL((void *)0)) | |||
| 1707 | fatal("malloc"); | |||
| 1708 | ureq->aru_varbindlen = 1; | |||
| 1709 | ureq->aru_error = APPL_ERROR_NOERROR; | |||
| 1710 | ureq->aru_index = 0; | |||
| 1711 | ureq->aru_locked = 0; | |||
| 1712 | ureq->aru_pduversion = SNMP_V3; | |||
| 1713 | ||||
| 1714 | ureq->aru_vblist[0].avi_state = APPL_VBSTATE_NEW; | |||
| 1715 | ureq->aru_vblist[0].avi_varbind.av_oid = *oid; | |||
| 1716 | ureq->aru_vblist[0].avi_varbind.av_value = NULL((void *)0); | |||
| 1717 | ureq->aru_vblist[0].avi_varbind.av_next = NULL((void *)0); | |||
| 1718 | ureq->aru_vblist[0].avi_origid = *oid; | |||
| 1719 | ureq->aru_vblist[0].avi_index = 1; | |||
| 1720 | ureq->aru_vblist[0].avi_request_upstream = ureq; | |||
| 1721 | ureq->aru_vblist[0].avi_request_downstream = NULL((void *)0); | |||
| 1722 | ureq->aru_vblist[0].avi_next = NULL((void *)0); | |||
| 1723 | ureq->aru_vblist[0].avi_sub = NULL((void *)0); | |||
| 1724 | ||||
| 1725 | appl_request_upstream_resolve(ureq); | |||
| 1726 | } | |||
| 1727 | ||||
| 1728 | struct ber_element * | |||
| 1729 | appl_exception(enum appl_exception type) | |||
| 1730 | { | |||
| 1731 | struct ber_element *value; | |||
| 1732 | ||||
| 1733 | if ((value = ober_add_null(NULL((void *)0))) == NULL((void *)0)) { | |||
| 1734 | log_warn("malloc"); | |||
| 1735 | return NULL((void *)0); | |||
| 1736 | } | |||
| 1737 | ober_set_header(value, BER_CLASS_CONTEXT0x2, type); | |||
| 1738 | ||||
| 1739 | return value; | |||
| 1740 | } | |||
| 1741 | ||||
| 1742 | void | |||
| 1743 | appl_pdu_log(struct appl_backend *backend, enum snmp_pdutype pdutype, | |||
| 1744 | int32_t requestid, uint16_t error, uint16_t index, | |||
| 1745 | struct appl_varbind *vblist) | |||
| 1746 | { | |||
| 1747 | struct appl_varbind *vb; | |||
| 1748 | char buf[1024], oidbuf[1024], *str; | |||
| 1749 | int next; | |||
| 1750 | ||||
| 1751 | if (log_getverbose() < 2) | |||
| 1752 | return; | |||
| 1753 | ||||
| 1754 | next = (pdutype == SNMP_C_GETNEXTREQ || pdutype == SNMP_C_GETBULKREQ); | |||
| 1755 | ||||
| 1756 | buf[0] = '\0'; | |||
| 1757 | for (vb = vblist; vb != NULL((void *)0); vb = vb->av_next) { | |||
| 1758 | strlcat(buf, "{", sizeof(buf)); | |||
| 1759 | strlcat(buf, smi_oid2string(&(vb->av_oid), oidbuf, | |||
| 1760 | sizeof(oidbuf), 0), sizeof(buf)); | |||
| 1761 | if (next) { | |||
| 1762 | if (vb->av_include) | |||
| 1763 | strlcat(buf, "(incl)", sizeof(buf)); | |||
| 1764 | if (vb->av_oid_end.bo_n > 0) { | |||
| 1765 | strlcat(buf, "-", sizeof(buf)); | |||
| 1766 | strlcat(buf, smi_oid2string(&(vb->av_oid_end), | |||
| 1767 | oidbuf, sizeof(oidbuf), 0), sizeof(buf)); | |||
| 1768 | } | |||
| 1769 | } | |||
| 1770 | strlcat(buf, ":", sizeof(buf)); | |||
| 1771 | if (vb->av_value != NULL((void *)0)) { | |||
| 1772 | str = smi_print_element(vb->av_value); | |||
| 1773 | strlcat(buf, str == NULL((void *)0) ? "???" : str, sizeof(buf)); | |||
| 1774 | free(str); | |||
| 1775 | } else | |||
| 1776 | strlcat(buf, "null", sizeof(buf)); | |||
| 1777 | strlcat(buf, "}", sizeof(buf)); | |||
| 1778 | } | |||
| 1779 | log_debug("%s%s%s{%"PRId32"d"", %"PRIu16"u"", %"PRIu16"u"", {%s}}", | |||
| 1780 | backend != NULL((void *)0) ? backend->ab_name : "", | |||
| 1781 | backend != NULL((void *)0) ? ": " : "", | |||
| 1782 | snmpe_pdutype2string(pdutype), requestid, error, index, buf); | |||
| 1783 | } | |||
| 1784 | ||||
| 1785 | void | |||
| 1786 | ober_oid_nextsibling(struct ber_oid *oid) | |||
| 1787 | { | |||
| 1788 | while (oid->bo_n > 0) { | |||
| 1789 | oid->bo_id[oid->bo_n - 1]++; | |||
| 1790 | /* Overflow check */ | |||
| 1791 | if (oid->bo_id[oid->bo_n - 1] != 0) | |||
| 1792 | return; | |||
| 1793 | oid->bo_n--; | |||
| 1794 | } | |||
| 1795 | } | |||
| 1796 | ||||
| 1797 | int | |||
| 1798 | appl_region_cmp(struct appl_region *r1, struct appl_region *r2) | |||
| 1799 | { | |||
| 1800 | return ober_oid_cmp(&(r1->ar_oid), &(r2->ar_oid)); | |||
| 1801 | } | |||
| 1802 | ||||
| 1803 | int | |||
| 1804 | appl_request_cmp(struct appl_request_downstream *r1, | |||
| 1805 | struct appl_request_downstream *r2) | |||
| 1806 | { | |||
| 1807 | return r1->ard_requestid < r2->ard_requestid ? -1 : | |||
| 1808 | r1->ard_requestid > r2->ard_requestid; | |||
| 1809 | } | |||
| 1810 | ||||
| 1811 | RB_GENERATE_STATIC(appl_regions, appl_region, ar_entry, appl_region_cmp)__attribute__((__unused__)) static void appl_regions_RB_INSERT_COLOR (struct appl_regions *head, struct appl_region *elm) { struct appl_region *parent, *gparent, *tmp; while ((parent = (elm)-> ar_entry.rbe_parent) && (parent)->ar_entry.rbe_color == 1) { gparent = (parent)->ar_entry.rbe_parent; if (parent == (gparent)->ar_entry.rbe_left) { tmp = (gparent)->ar_entry .rbe_right; if (tmp && (tmp)->ar_entry.rbe_color == 1) { (tmp)->ar_entry.rbe_color = 0; do { (parent)->ar_entry .rbe_color = 0; (gparent)->ar_entry.rbe_color = 1; } while (0); elm = gparent; continue; } if ((parent)->ar_entry.rbe_right == elm) { do { (tmp) = (parent)->ar_entry.rbe_right; if ( ((parent)->ar_entry.rbe_right = (tmp)->ar_entry.rbe_left )) { ((tmp)->ar_entry.rbe_left)->ar_entry.rbe_parent = ( parent); } do {} while (0); if (((tmp)->ar_entry.rbe_parent = (parent)->ar_entry.rbe_parent)) { if ((parent) == ((parent )->ar_entry.rbe_parent)->ar_entry.rbe_left) ((parent)-> ar_entry.rbe_parent)->ar_entry.rbe_left = (tmp); else ((parent )->ar_entry.rbe_parent)->ar_entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->ar_entry.rbe_left = ( parent); (parent)->ar_entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->ar_entry.rbe_parent)) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent )->ar_entry.rbe_color = 0; (gparent)->ar_entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)->ar_entry.rbe_left ; if (((gparent)->ar_entry.rbe_left = (tmp)->ar_entry.rbe_right )) { ((tmp)->ar_entry.rbe_right)->ar_entry.rbe_parent = (gparent); } do {} while (0); if (((tmp)->ar_entry.rbe_parent = (gparent)->ar_entry.rbe_parent)) { if ((gparent) == ((gparent )->ar_entry.rbe_parent)->ar_entry.rbe_left) ((gparent)-> ar_entry.rbe_parent)->ar_entry.rbe_left = (tmp); else ((gparent )->ar_entry.rbe_parent)->ar_entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->ar_entry.rbe_right = ( gparent); (gparent)->ar_entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->ar_entry.rbe_parent)) do {} while (0); } while (0); } else { tmp = (gparent)->ar_entry.rbe_left; if (tmp && (tmp)->ar_entry.rbe_color == 1) { (tmp)-> ar_entry.rbe_color = 0; do { (parent)->ar_entry.rbe_color = 0; (gparent)->ar_entry.rbe_color = 1; } while (0); elm = gparent ; continue; } if ((parent)->ar_entry.rbe_left == elm) { do { (tmp) = (parent)->ar_entry.rbe_left; if (((parent)-> ar_entry.rbe_left = (tmp)->ar_entry.rbe_right)) { ((tmp)-> ar_entry.rbe_right)->ar_entry.rbe_parent = (parent); } do { } while (0); if (((tmp)->ar_entry.rbe_parent = (parent)-> ar_entry.rbe_parent)) { if ((parent) == ((parent)->ar_entry .rbe_parent)->ar_entry.rbe_left) ((parent)->ar_entry.rbe_parent )->ar_entry.rbe_left = (tmp); else ((parent)->ar_entry. rbe_parent)->ar_entry.rbe_right = (tmp); } else (head)-> rbh_root = (tmp); (tmp)->ar_entry.rbe_right = (parent); (parent )->ar_entry.rbe_parent = (tmp); do {} while (0); if (((tmp )->ar_entry.rbe_parent)) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->ar_entry .rbe_color = 0; (gparent)->ar_entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)->ar_entry.rbe_right; if (((gparent )->ar_entry.rbe_right = (tmp)->ar_entry.rbe_left)) { (( tmp)->ar_entry.rbe_left)->ar_entry.rbe_parent = (gparent ); } do {} while (0); if (((tmp)->ar_entry.rbe_parent = (gparent )->ar_entry.rbe_parent)) { if ((gparent) == ((gparent)-> ar_entry.rbe_parent)->ar_entry.rbe_left) ((gparent)->ar_entry .rbe_parent)->ar_entry.rbe_left = (tmp); else ((gparent)-> ar_entry.rbe_parent)->ar_entry.rbe_right = (tmp); } else ( head)->rbh_root = (tmp); (tmp)->ar_entry.rbe_left = (gparent ); (gparent)->ar_entry.rbe_parent = (tmp); do {} while (0) ; if (((tmp)->ar_entry.rbe_parent)) do {} while (0); } while (0); } } (head->rbh_root)->ar_entry.rbe_color = 0; } __attribute__ ((__unused__)) static void appl_regions_RB_REMOVE_COLOR(struct appl_regions *head, struct appl_region *parent, struct appl_region *elm) { struct appl_region *tmp; while ((elm == ((void *)0) || (elm)->ar_entry.rbe_color == 0) && elm != (head)-> rbh_root) { if ((parent)->ar_entry.rbe_left == elm) { tmp = (parent)->ar_entry.rbe_right; if ((tmp)->ar_entry.rbe_color == 1) { do { (tmp)->ar_entry.rbe_color = 0; (parent)-> ar_entry.rbe_color = 1; } while (0); do { (tmp) = (parent)-> ar_entry.rbe_right; if (((parent)->ar_entry.rbe_right = (tmp )->ar_entry.rbe_left)) { ((tmp)->ar_entry.rbe_left)-> ar_entry.rbe_parent = (parent); } do {} while (0); if (((tmp) ->ar_entry.rbe_parent = (parent)->ar_entry.rbe_parent)) { if ((parent) == ((parent)->ar_entry.rbe_parent)->ar_entry .rbe_left) ((parent)->ar_entry.rbe_parent)->ar_entry.rbe_left = (tmp); else ((parent)->ar_entry.rbe_parent)->ar_entry .rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp) ->ar_entry.rbe_left = (parent); (parent)->ar_entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->ar_entry.rbe_parent )) do {} while (0); } while (0); tmp = (parent)->ar_entry. rbe_right; } if (((tmp)->ar_entry.rbe_left == ((void *)0) || ((tmp)->ar_entry.rbe_left)->ar_entry.rbe_color == 0) && ((tmp)->ar_entry.rbe_right == ((void *)0) || ((tmp)->ar_entry .rbe_right)->ar_entry.rbe_color == 0)) { (tmp)->ar_entry .rbe_color = 1; elm = parent; parent = (elm)->ar_entry.rbe_parent ; } else { if ((tmp)->ar_entry.rbe_right == ((void *)0) || ((tmp)->ar_entry.rbe_right)->ar_entry.rbe_color == 0) { struct appl_region *oleft; if ((oleft = (tmp)->ar_entry.rbe_left )) (oleft)->ar_entry.rbe_color = 0; (tmp)->ar_entry.rbe_color = 1; do { (oleft) = (tmp)->ar_entry.rbe_left; if (((tmp)-> ar_entry.rbe_left = (oleft)->ar_entry.rbe_right)) { ((oleft )->ar_entry.rbe_right)->ar_entry.rbe_parent = (tmp); } do {} while (0); if (((oleft)->ar_entry.rbe_parent = (tmp)-> ar_entry.rbe_parent)) { if ((tmp) == ((tmp)->ar_entry.rbe_parent )->ar_entry.rbe_left) ((tmp)->ar_entry.rbe_parent)-> ar_entry.rbe_left = (oleft); else ((tmp)->ar_entry.rbe_parent )->ar_entry.rbe_right = (oleft); } else (head)->rbh_root = (oleft); (oleft)->ar_entry.rbe_right = (tmp); (tmp)-> ar_entry.rbe_parent = (oleft); do {} while (0); if (((oleft)-> ar_entry.rbe_parent)) do {} while (0); } while (0); tmp = (parent )->ar_entry.rbe_right; } (tmp)->ar_entry.rbe_color = (parent )->ar_entry.rbe_color; (parent)->ar_entry.rbe_color = 0 ; if ((tmp)->ar_entry.rbe_right) ((tmp)->ar_entry.rbe_right )->ar_entry.rbe_color = 0; do { (tmp) = (parent)->ar_entry .rbe_right; if (((parent)->ar_entry.rbe_right = (tmp)-> ar_entry.rbe_left)) { ((tmp)->ar_entry.rbe_left)->ar_entry .rbe_parent = (parent); } do {} while (0); if (((tmp)->ar_entry .rbe_parent = (parent)->ar_entry.rbe_parent)) { if ((parent ) == ((parent)->ar_entry.rbe_parent)->ar_entry.rbe_left ) ((parent)->ar_entry.rbe_parent)->ar_entry.rbe_left = ( tmp); else ((parent)->ar_entry.rbe_parent)->ar_entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->ar_entry .rbe_left = (parent); (parent)->ar_entry.rbe_parent = (tmp ); do {} while (0); if (((tmp)->ar_entry.rbe_parent)) do { } while (0); } while (0); elm = (head)->rbh_root; break; } } else { tmp = (parent)->ar_entry.rbe_left; if ((tmp)-> ar_entry.rbe_color == 1) { do { (tmp)->ar_entry.rbe_color = 0; (parent)->ar_entry.rbe_color = 1; } while (0); do { (tmp ) = (parent)->ar_entry.rbe_left; if (((parent)->ar_entry .rbe_left = (tmp)->ar_entry.rbe_right)) { ((tmp)->ar_entry .rbe_right)->ar_entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->ar_entry.rbe_parent = (parent)->ar_entry .rbe_parent)) { if ((parent) == ((parent)->ar_entry.rbe_parent )->ar_entry.rbe_left) ((parent)->ar_entry.rbe_parent)-> ar_entry.rbe_left = (tmp); else ((parent)->ar_entry.rbe_parent )->ar_entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->ar_entry.rbe_right = (parent); (parent)-> ar_entry.rbe_parent = (tmp); do {} while (0); if (((tmp)-> ar_entry.rbe_parent)) do {} while (0); } while (0); tmp = (parent )->ar_entry.rbe_left; } if (((tmp)->ar_entry.rbe_left == ((void *)0) || ((tmp)->ar_entry.rbe_left)->ar_entry.rbe_color == 0) && ((tmp)->ar_entry.rbe_right == ((void *)0 ) || ((tmp)->ar_entry.rbe_right)->ar_entry.rbe_color == 0)) { (tmp)->ar_entry.rbe_color = 1; elm = parent; parent = (elm)->ar_entry.rbe_parent; } else { if ((tmp)->ar_entry .rbe_left == ((void *)0) || ((tmp)->ar_entry.rbe_left)-> ar_entry.rbe_color == 0) { struct appl_region *oright; if ((oright = (tmp)->ar_entry.rbe_right)) (oright)->ar_entry.rbe_color = 0; (tmp)->ar_entry.rbe_color = 1; do { (oright) = (tmp) ->ar_entry.rbe_right; if (((tmp)->ar_entry.rbe_right = ( oright)->ar_entry.rbe_left)) { ((oright)->ar_entry.rbe_left )->ar_entry.rbe_parent = (tmp); } do {} while (0); if (((oright )->ar_entry.rbe_parent = (tmp)->ar_entry.rbe_parent)) { if ((tmp) == ((tmp)->ar_entry.rbe_parent)->ar_entry.rbe_left ) ((tmp)->ar_entry.rbe_parent)->ar_entry.rbe_left = (oright ); else ((tmp)->ar_entry.rbe_parent)->ar_entry.rbe_right = (oright); } else (head)->rbh_root = (oright); (oright)-> ar_entry.rbe_left = (tmp); (tmp)->ar_entry.rbe_parent = (oright ); do {} while (0); if (((oright)->ar_entry.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->ar_entry.rbe_left ; } (tmp)->ar_entry.rbe_color = (parent)->ar_entry.rbe_color ; (parent)->ar_entry.rbe_color = 0; if ((tmp)->ar_entry .rbe_left) ((tmp)->ar_entry.rbe_left)->ar_entry.rbe_color = 0; do { (tmp) = (parent)->ar_entry.rbe_left; if (((parent )->ar_entry.rbe_left = (tmp)->ar_entry.rbe_right)) { (( tmp)->ar_entry.rbe_right)->ar_entry.rbe_parent = (parent ); } do {} while (0); if (((tmp)->ar_entry.rbe_parent = (parent )->ar_entry.rbe_parent)) { if ((parent) == ((parent)->ar_entry .rbe_parent)->ar_entry.rbe_left) ((parent)->ar_entry.rbe_parent )->ar_entry.rbe_left = (tmp); else ((parent)->ar_entry. rbe_parent)->ar_entry.rbe_right = (tmp); } else (head)-> rbh_root = (tmp); (tmp)->ar_entry.rbe_right = (parent); (parent )->ar_entry.rbe_parent = (tmp); do {} while (0); if (((tmp )->ar_entry.rbe_parent)) do {} while (0); } while (0); elm = (head)->rbh_root; break; } } } if (elm) (elm)->ar_entry .rbe_color = 0; } __attribute__((__unused__)) static struct appl_region * appl_regions_RB_REMOVE(struct appl_regions *head, struct appl_region *elm) { struct appl_region *child, *parent, *old = elm; int color ; if ((elm)->ar_entry.rbe_left == ((void *)0)) child = (elm )->ar_entry.rbe_right; else if ((elm)->ar_entry.rbe_right == ((void *)0)) child = (elm)->ar_entry.rbe_left; else { struct appl_region *left; elm = (elm)->ar_entry.rbe_right; while ((left = (elm)->ar_entry.rbe_left)) elm = left; child = ( elm)->ar_entry.rbe_right; parent = (elm)->ar_entry.rbe_parent ; color = (elm)->ar_entry.rbe_color; if (child) (child)-> ar_entry.rbe_parent = parent; if (parent) { if ((parent)-> ar_entry.rbe_left == elm) (parent)->ar_entry.rbe_left = child ; else (parent)->ar_entry.rbe_right = child; do {} while ( 0); } else (head)->rbh_root = child; if ((elm)->ar_entry .rbe_parent == old) parent = elm; (elm)->ar_entry = (old)-> ar_entry; if ((old)->ar_entry.rbe_parent) { if (((old)-> ar_entry.rbe_parent)->ar_entry.rbe_left == old) ((old)-> ar_entry.rbe_parent)->ar_entry.rbe_left = elm; else ((old) ->ar_entry.rbe_parent)->ar_entry.rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; ((old)->ar_entry .rbe_left)->ar_entry.rbe_parent = elm; if ((old)->ar_entry .rbe_right) ((old)->ar_entry.rbe_right)->ar_entry.rbe_parent = elm; if (parent) { left = parent; do { do {} while (0); } while ((left = (left)->ar_entry.rbe_parent)); } goto color; } parent = (elm)->ar_entry.rbe_parent; color = (elm)->ar_entry. rbe_color; if (child) (child)->ar_entry.rbe_parent = parent ; if (parent) { if ((parent)->ar_entry.rbe_left == elm) (parent )->ar_entry.rbe_left = child; else (parent)->ar_entry.rbe_right = child; do {} while (0); } else (head)->rbh_root = child ; color: if (color == 0) appl_regions_RB_REMOVE_COLOR(head, parent , child); return (old); } __attribute__((__unused__)) static struct appl_region * appl_regions_RB_INSERT(struct appl_regions *head , struct appl_region *elm) { struct appl_region *tmp; struct appl_region *parent = ((void *)0); int comp = 0; tmp = (head)->rbh_root ; while (tmp) { parent = tmp; comp = (appl_region_cmp)(elm, parent ); if (comp < 0) tmp = (tmp)->ar_entry.rbe_left; else if (comp > 0) tmp = (tmp)->ar_entry.rbe_right; else return (tmp); } do { (elm)->ar_entry.rbe_parent = parent; (elm)-> ar_entry.rbe_left = (elm)->ar_entry.rbe_right = ((void *)0 ); (elm)->ar_entry.rbe_color = 1; } while (0); if (parent != ((void *)0)) { if (comp < 0) (parent)->ar_entry.rbe_left = elm; else (parent)->ar_entry.rbe_right = elm; do {} while (0); } else (head)->rbh_root = elm; appl_regions_RB_INSERT_COLOR (head, elm); return (((void *)0)); } __attribute__((__unused__ )) static struct appl_region * appl_regions_RB_FIND(struct appl_regions *head, struct appl_region *elm) { struct appl_region *tmp = ( head)->rbh_root; int comp; while (tmp) { comp = appl_region_cmp (elm, tmp); if (comp < 0) tmp = (tmp)->ar_entry.rbe_left ; else if (comp > 0) tmp = (tmp)->ar_entry.rbe_right; else return (tmp); } return (((void *)0)); } __attribute__((__unused__ )) static struct appl_region * appl_regions_RB_NFIND(struct appl_regions *head, struct appl_region *elm) { struct appl_region *tmp = ( head)->rbh_root; struct appl_region *res = ((void *)0); int comp; while (tmp) { comp = appl_region_cmp(elm, tmp); if (comp < 0) { res = tmp; tmp = (tmp)->ar_entry.rbe_left; } else if (comp > 0) tmp = (tmp)->ar_entry.rbe_right; else return (tmp); } return (res); } __attribute__((__unused__)) static struct appl_region * appl_regions_RB_NEXT(struct appl_region *elm) { if ((elm)->ar_entry.rbe_right) { elm = (elm)->ar_entry .rbe_right; while ((elm)->ar_entry.rbe_left) elm = (elm)-> ar_entry.rbe_left; } else { if ((elm)->ar_entry.rbe_parent && (elm == ((elm)->ar_entry.rbe_parent)->ar_entry .rbe_left)) elm = (elm)->ar_entry.rbe_parent; else { while ((elm)->ar_entry.rbe_parent && (elm == ((elm)-> ar_entry.rbe_parent)->ar_entry.rbe_right)) elm = (elm)-> ar_entry.rbe_parent; elm = (elm)->ar_entry.rbe_parent; } } return (elm); } __attribute__((__unused__)) static struct appl_region * appl_regions_RB_PREV(struct appl_region *elm) { if ((elm)-> ar_entry.rbe_left) { elm = (elm)->ar_entry.rbe_left; while ((elm)->ar_entry.rbe_right) elm = (elm)->ar_entry.rbe_right ; } else { if ((elm)->ar_entry.rbe_parent && (elm == ((elm)->ar_entry.rbe_parent)->ar_entry.rbe_right)) elm = (elm)->ar_entry.rbe_parent; else { while ((elm)->ar_entry .rbe_parent && (elm == ((elm)->ar_entry.rbe_parent )->ar_entry.rbe_left)) elm = (elm)->ar_entry.rbe_parent ; elm = (elm)->ar_entry.rbe_parent; } } return (elm); } __attribute__ ((__unused__)) static struct appl_region * appl_regions_RB_MINMAX (struct appl_regions *head, int val) { struct appl_region *tmp = (head)->rbh_root; struct appl_region *parent = ((void * )0); while (tmp) { parent = tmp; if (val < 0) tmp = (tmp)-> ar_entry.rbe_left; else tmp = (tmp)->ar_entry.rbe_right; } return (parent); }; | |||
| 1812 | RB_GENERATE_STATIC(appl_requests, appl_request_downstream, ard_entry,__attribute__((__unused__)) static void appl_requests_RB_INSERT_COLOR (struct appl_requests *head, struct appl_request_downstream * elm) { struct appl_request_downstream *parent, *gparent, *tmp ; while ((parent = (elm)->ard_entry.rbe_parent) && (parent)->ard_entry.rbe_color == 1) { gparent = (parent)-> ard_entry.rbe_parent; if (parent == (gparent)->ard_entry.rbe_left ) { tmp = (gparent)->ard_entry.rbe_right; if (tmp && (tmp)->ard_entry.rbe_color == 1) { (tmp)->ard_entry.rbe_color = 0; do { (parent)->ard_entry.rbe_color = 0; (gparent)-> ard_entry.rbe_color = 1; } while (0); elm = gparent; continue ; } if ((parent)->ard_entry.rbe_right == elm) { do { (tmp) = (parent)->ard_entry.rbe_right; if (((parent)->ard_entry .rbe_right = (tmp)->ard_entry.rbe_left)) { ((tmp)->ard_entry .rbe_left)->ard_entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->ard_entry.rbe_parent = (parent)->ard_entry .rbe_parent)) { if ((parent) == ((parent)->ard_entry.rbe_parent )->ard_entry.rbe_left) ((parent)->ard_entry.rbe_parent) ->ard_entry.rbe_left = (tmp); else ((parent)->ard_entry .rbe_parent)->ard_entry.rbe_right = (tmp); } else (head)-> rbh_root = (tmp); (tmp)->ard_entry.rbe_left = (parent); (parent )->ard_entry.rbe_parent = (tmp); do {} while (0); if (((tmp )->ard_entry.rbe_parent)) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->ard_entry .rbe_color = 0; (gparent)->ard_entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)->ard_entry.rbe_left; if (((gparent )->ard_entry.rbe_left = (tmp)->ard_entry.rbe_right)) { ( (tmp)->ard_entry.rbe_right)->ard_entry.rbe_parent = (gparent ); } do {} while (0); if (((tmp)->ard_entry.rbe_parent = ( gparent)->ard_entry.rbe_parent)) { if ((gparent) == ((gparent )->ard_entry.rbe_parent)->ard_entry.rbe_left) ((gparent )->ard_entry.rbe_parent)->ard_entry.rbe_left = (tmp); else ((gparent)->ard_entry.rbe_parent)->ard_entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->ard_entry .rbe_right = (gparent); (gparent)->ard_entry.rbe_parent = ( tmp); do {} while (0); if (((tmp)->ard_entry.rbe_parent)) do {} while (0); } while (0); } else { tmp = (gparent)->ard_entry .rbe_left; if (tmp && (tmp)->ard_entry.rbe_color == 1) { (tmp)->ard_entry.rbe_color = 0; do { (parent)->ard_entry .rbe_color = 0; (gparent)->ard_entry.rbe_color = 1; } while (0); elm = gparent; continue; } if ((parent)->ard_entry.rbe_left == elm) { do { (tmp) = (parent)->ard_entry.rbe_left; if ( ((parent)->ard_entry.rbe_left = (tmp)->ard_entry.rbe_right )) { ((tmp)->ard_entry.rbe_right)->ard_entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->ard_entry.rbe_parent = (parent)->ard_entry.rbe_parent)) { if ((parent) == ((parent )->ard_entry.rbe_parent)->ard_entry.rbe_left) ((parent) ->ard_entry.rbe_parent)->ard_entry.rbe_left = (tmp); else ((parent)->ard_entry.rbe_parent)->ard_entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->ard_entry .rbe_right = (parent); (parent)->ard_entry.rbe_parent = (tmp ); do {} while (0); if (((tmp)->ard_entry.rbe_parent)) do { } while (0); } while (0); tmp = parent; parent = elm; elm = tmp ; } do { (parent)->ard_entry.rbe_color = 0; (gparent)-> ard_entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)-> ard_entry.rbe_right; if (((gparent)->ard_entry.rbe_right = (tmp)->ard_entry.rbe_left)) { ((tmp)->ard_entry.rbe_left )->ard_entry.rbe_parent = (gparent); } do {} while (0); if (((tmp)->ard_entry.rbe_parent = (gparent)->ard_entry.rbe_parent )) { if ((gparent) == ((gparent)->ard_entry.rbe_parent)-> ard_entry.rbe_left) ((gparent)->ard_entry.rbe_parent)-> ard_entry.rbe_left = (tmp); else ((gparent)->ard_entry.rbe_parent )->ard_entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->ard_entry.rbe_left = (gparent); (gparent) ->ard_entry.rbe_parent = (tmp); do {} while (0); if (((tmp )->ard_entry.rbe_parent)) do {} while (0); } while (0); } } (head->rbh_root)->ard_entry.rbe_color = 0; } __attribute__ ((__unused__)) static void appl_requests_RB_REMOVE_COLOR(struct appl_requests *head, struct appl_request_downstream *parent, struct appl_request_downstream *elm) { struct appl_request_downstream *tmp; while ((elm == ((void *)0) || (elm)->ard_entry.rbe_color == 0) && elm != (head)->rbh_root) { if ((parent)-> ard_entry.rbe_left == elm) { tmp = (parent)->ard_entry.rbe_right ; if ((tmp)->ard_entry.rbe_color == 1) { do { (tmp)->ard_entry .rbe_color = 0; (parent)->ard_entry.rbe_color = 1; } while (0); do { (tmp) = (parent)->ard_entry.rbe_right; if (((parent )->ard_entry.rbe_right = (tmp)->ard_entry.rbe_left)) { ( (tmp)->ard_entry.rbe_left)->ard_entry.rbe_parent = (parent ); } do {} while (0); if (((tmp)->ard_entry.rbe_parent = ( parent)->ard_entry.rbe_parent)) { if ((parent) == ((parent )->ard_entry.rbe_parent)->ard_entry.rbe_left) ((parent) ->ard_entry.rbe_parent)->ard_entry.rbe_left = (tmp); else ((parent)->ard_entry.rbe_parent)->ard_entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->ard_entry .rbe_left = (parent); (parent)->ard_entry.rbe_parent = (tmp ); do {} while (0); if (((tmp)->ard_entry.rbe_parent)) do { } while (0); } while (0); tmp = (parent)->ard_entry.rbe_right ; } if (((tmp)->ard_entry.rbe_left == ((void *)0) || ((tmp )->ard_entry.rbe_left)->ard_entry.rbe_color == 0) && ((tmp)->ard_entry.rbe_right == ((void *)0) || ((tmp)-> ard_entry.rbe_right)->ard_entry.rbe_color == 0)) { (tmp)-> ard_entry.rbe_color = 1; elm = parent; parent = (elm)->ard_entry .rbe_parent; } else { if ((tmp)->ard_entry.rbe_right == (( void *)0) || ((tmp)->ard_entry.rbe_right)->ard_entry.rbe_color == 0) { struct appl_request_downstream *oleft; if ((oleft = ( tmp)->ard_entry.rbe_left)) (oleft)->ard_entry.rbe_color = 0; (tmp)->ard_entry.rbe_color = 1; do { (oleft) = (tmp) ->ard_entry.rbe_left; if (((tmp)->ard_entry.rbe_left = ( oleft)->ard_entry.rbe_right)) { ((oleft)->ard_entry.rbe_right )->ard_entry.rbe_parent = (tmp); } do {} while (0); if ((( oleft)->ard_entry.rbe_parent = (tmp)->ard_entry.rbe_parent )) { if ((tmp) == ((tmp)->ard_entry.rbe_parent)->ard_entry .rbe_left) ((tmp)->ard_entry.rbe_parent)->ard_entry.rbe_left = (oleft); else ((tmp)->ard_entry.rbe_parent)->ard_entry .rbe_right = (oleft); } else (head)->rbh_root = (oleft); ( oleft)->ard_entry.rbe_right = (tmp); (tmp)->ard_entry.rbe_parent = (oleft); do {} while (0); if (((oleft)->ard_entry.rbe_parent )) do {} while (0); } while (0); tmp = (parent)->ard_entry .rbe_right; } (tmp)->ard_entry.rbe_color = (parent)->ard_entry .rbe_color; (parent)->ard_entry.rbe_color = 0; if ((tmp)-> ard_entry.rbe_right) ((tmp)->ard_entry.rbe_right)->ard_entry .rbe_color = 0; do { (tmp) = (parent)->ard_entry.rbe_right ; if (((parent)->ard_entry.rbe_right = (tmp)->ard_entry .rbe_left)) { ((tmp)->ard_entry.rbe_left)->ard_entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->ard_entry.rbe_parent = (parent)->ard_entry.rbe_parent)) { if ((parent) == ((parent )->ard_entry.rbe_parent)->ard_entry.rbe_left) ((parent) ->ard_entry.rbe_parent)->ard_entry.rbe_left = (tmp); else ((parent)->ard_entry.rbe_parent)->ard_entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->ard_entry .rbe_left = (parent); (parent)->ard_entry.rbe_parent = (tmp ); do {} while (0); if (((tmp)->ard_entry.rbe_parent)) do { } while (0); } while (0); elm = (head)->rbh_root; break; } } else { tmp = (parent)->ard_entry.rbe_left; if ((tmp)-> ard_entry.rbe_color == 1) { do { (tmp)->ard_entry.rbe_color = 0; (parent)->ard_entry.rbe_color = 1; } while (0); do { (tmp) = (parent)->ard_entry.rbe_left; if (((parent)->ard_entry .rbe_left = (tmp)->ard_entry.rbe_right)) { ((tmp)->ard_entry .rbe_right)->ard_entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->ard_entry.rbe_parent = (parent)->ard_entry .rbe_parent)) { if ((parent) == ((parent)->ard_entry.rbe_parent )->ard_entry.rbe_left) ((parent)->ard_entry.rbe_parent) ->ard_entry.rbe_left = (tmp); else ((parent)->ard_entry .rbe_parent)->ard_entry.rbe_right = (tmp); } else (head)-> rbh_root = (tmp); (tmp)->ard_entry.rbe_right = (parent); ( parent)->ard_entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->ard_entry.rbe_parent)) do {} while (0); } while ( 0); tmp = (parent)->ard_entry.rbe_left; } if (((tmp)->ard_entry .rbe_left == ((void *)0) || ((tmp)->ard_entry.rbe_left)-> ard_entry.rbe_color == 0) && ((tmp)->ard_entry.rbe_right == ((void *)0) || ((tmp)->ard_entry.rbe_right)->ard_entry .rbe_color == 0)) { (tmp)->ard_entry.rbe_color = 1; elm = parent ; parent = (elm)->ard_entry.rbe_parent; } else { if ((tmp) ->ard_entry.rbe_left == ((void *)0) || ((tmp)->ard_entry .rbe_left)->ard_entry.rbe_color == 0) { struct appl_request_downstream *oright; if ((oright = (tmp)->ard_entry.rbe_right)) (oright )->ard_entry.rbe_color = 0; (tmp)->ard_entry.rbe_color = 1; do { (oright) = (tmp)->ard_entry.rbe_right; if (((tmp) ->ard_entry.rbe_right = (oright)->ard_entry.rbe_left)) { ((oright)->ard_entry.rbe_left)->ard_entry.rbe_parent = (tmp); } do {} while (0); if (((oright)->ard_entry.rbe_parent = (tmp)->ard_entry.rbe_parent)) { if ((tmp) == ((tmp)-> ard_entry.rbe_parent)->ard_entry.rbe_left) ((tmp)->ard_entry .rbe_parent)->ard_entry.rbe_left = (oright); else ((tmp)-> ard_entry.rbe_parent)->ard_entry.rbe_right = (oright); } else (head)->rbh_root = (oright); (oright)->ard_entry.rbe_left = (tmp); (tmp)->ard_entry.rbe_parent = (oright); do {} while (0); if (((oright)->ard_entry.rbe_parent)) do {} while (0 ); } while (0); tmp = (parent)->ard_entry.rbe_left; } (tmp )->ard_entry.rbe_color = (parent)->ard_entry.rbe_color; (parent)->ard_entry.rbe_color = 0; if ((tmp)->ard_entry .rbe_left) ((tmp)->ard_entry.rbe_left)->ard_entry.rbe_color = 0; do { (tmp) = (parent)->ard_entry.rbe_left; if (((parent )->ard_entry.rbe_left = (tmp)->ard_entry.rbe_right)) { ( (tmp)->ard_entry.rbe_right)->ard_entry.rbe_parent = (parent ); } do {} while (0); if (((tmp)->ard_entry.rbe_parent = ( parent)->ard_entry.rbe_parent)) { if ((parent) == ((parent )->ard_entry.rbe_parent)->ard_entry.rbe_left) ((parent) ->ard_entry.rbe_parent)->ard_entry.rbe_left = (tmp); else ((parent)->ard_entry.rbe_parent)->ard_entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->ard_entry .rbe_right = (parent); (parent)->ard_entry.rbe_parent = (tmp ); do {} while (0); if (((tmp)->ard_entry.rbe_parent)) do { } while (0); } while (0); elm = (head)->rbh_root; break; } } } if (elm) (elm)->ard_entry.rbe_color = 0; } __attribute__ ((__unused__)) static struct appl_request_downstream * appl_requests_RB_REMOVE (struct appl_requests *head, struct appl_request_downstream * elm) { struct appl_request_downstream *child, *parent, *old = elm; int color; if ((elm)->ard_entry.rbe_left == ((void * )0)) child = (elm)->ard_entry.rbe_right; else if ((elm)-> ard_entry.rbe_right == ((void *)0)) child = (elm)->ard_entry .rbe_left; else { struct appl_request_downstream *left; elm = (elm)->ard_entry.rbe_right; while ((left = (elm)->ard_entry .rbe_left)) elm = left; child = (elm)->ard_entry.rbe_right ; parent = (elm)->ard_entry.rbe_parent; color = (elm)-> ard_entry.rbe_color; if (child) (child)->ard_entry.rbe_parent = parent; if (parent) { if ((parent)->ard_entry.rbe_left == elm) (parent)->ard_entry.rbe_left = child; else (parent)-> ard_entry.rbe_right = child; do {} while (0); } else (head)-> rbh_root = child; if ((elm)->ard_entry.rbe_parent == old) parent = elm; (elm)->ard_entry = (old)->ard_entry; if ((old)-> ard_entry.rbe_parent) { if (((old)->ard_entry.rbe_parent)-> ard_entry.rbe_left == old) ((old)->ard_entry.rbe_parent)-> ard_entry.rbe_left = elm; else ((old)->ard_entry.rbe_parent )->ard_entry.rbe_right = elm; do {} while (0); } else (head )->rbh_root = elm; ((old)->ard_entry.rbe_left)->ard_entry .rbe_parent = elm; if ((old)->ard_entry.rbe_right) ((old)-> ard_entry.rbe_right)->ard_entry.rbe_parent = elm; if (parent ) { left = parent; do { do {} while (0); } while ((left = (left )->ard_entry.rbe_parent)); } goto color; } parent = (elm)-> ard_entry.rbe_parent; color = (elm)->ard_entry.rbe_color; if (child) (child)->ard_entry.rbe_parent = parent; if (parent ) { if ((parent)->ard_entry.rbe_left == elm) (parent)-> ard_entry.rbe_left = child; else (parent)->ard_entry.rbe_right = child; do {} while (0); } else (head)->rbh_root = child ; color: if (color == 0) appl_requests_RB_REMOVE_COLOR(head, parent , child); return (old); } __attribute__((__unused__)) static struct appl_request_downstream * appl_requests_RB_INSERT(struct appl_requests *head, struct appl_request_downstream *elm) { struct appl_request_downstream *tmp; struct appl_request_downstream *parent = ((void *)0); int comp = 0; tmp = (head)->rbh_root; while (tmp) { parent = tmp ; comp = (appl_request_cmp)(elm, parent); if (comp < 0) tmp = (tmp)->ard_entry.rbe_left; else if (comp > 0) tmp = ( tmp)->ard_entry.rbe_right; else return (tmp); } do { (elm) ->ard_entry.rbe_parent = parent; (elm)->ard_entry.rbe_left = (elm)->ard_entry.rbe_right = ((void *)0); (elm)->ard_entry .rbe_color = 1; } while (0); if (parent != ((void *)0)) { if ( comp < 0) (parent)->ard_entry.rbe_left = elm; else (parent )->ard_entry.rbe_right = elm; do {} while (0); } else (head )->rbh_root = elm; appl_requests_RB_INSERT_COLOR(head, elm ); return (((void *)0)); } __attribute__((__unused__)) static struct appl_request_downstream * appl_requests_RB_FIND(struct appl_requests *head, struct appl_request_downstream *elm) { struct appl_request_downstream *tmp = (head)->rbh_root; int comp ; while (tmp) { comp = appl_request_cmp(elm, tmp); if (comp < 0) tmp = (tmp)->ard_entry.rbe_left; else if (comp > 0) tmp = (tmp)->ard_entry.rbe_right; else return (tmp); } return (((void *)0)); } __attribute__((__unused__)) static struct appl_request_downstream * appl_requests_RB_NFIND(struct appl_requests *head, struct appl_request_downstream *elm) { struct appl_request_downstream *tmp = (head)->rbh_root ; struct appl_request_downstream *res = ((void *)0); int comp ; while (tmp) { comp = appl_request_cmp(elm, tmp); if (comp < 0) { res = tmp; tmp = (tmp)->ard_entry.rbe_left; } else if (comp > 0) tmp = (tmp)->ard_entry.rbe_right; else return (tmp); } return (res); } __attribute__((__unused__)) static struct appl_request_downstream * appl_requests_RB_NEXT(struct appl_request_downstream *elm) { if ((elm)->ard_entry.rbe_right) { elm = (elm)-> ard_entry.rbe_right; while ((elm)->ard_entry.rbe_left) elm = (elm)->ard_entry.rbe_left; } else { if ((elm)->ard_entry .rbe_parent && (elm == ((elm)->ard_entry.rbe_parent )->ard_entry.rbe_left)) elm = (elm)->ard_entry.rbe_parent ; else { while ((elm)->ard_entry.rbe_parent && (elm == ((elm)->ard_entry.rbe_parent)->ard_entry.rbe_right) ) elm = (elm)->ard_entry.rbe_parent; elm = (elm)->ard_entry .rbe_parent; } } return (elm); } __attribute__((__unused__)) static struct appl_request_downstream * appl_requests_RB_PREV(struct appl_request_downstream *elm) { if ((elm)->ard_entry.rbe_left ) { elm = (elm)->ard_entry.rbe_left; while ((elm)->ard_entry .rbe_right) elm = (elm)->ard_entry.rbe_right; } else { if ( (elm)->ard_entry.rbe_parent && (elm == ((elm)-> ard_entry.rbe_parent)->ard_entry.rbe_right)) elm = (elm)-> ard_entry.rbe_parent; else { while ((elm)->ard_entry.rbe_parent && (elm == ((elm)->ard_entry.rbe_parent)->ard_entry .rbe_left)) elm = (elm)->ard_entry.rbe_parent; elm = (elm) ->ard_entry.rbe_parent; } } return (elm); } __attribute__( (__unused__)) static struct appl_request_downstream * appl_requests_RB_MINMAX (struct appl_requests *head, int val) { struct appl_request_downstream *tmp = (head)->rbh_root; struct appl_request_downstream * parent = ((void *)0); while (tmp) { parent = tmp; if (val < 0) tmp = (tmp)->ard_entry.rbe_left; else tmp = (tmp)-> ard_entry.rbe_right; } return (parent); } | |||
| 1813 | appl_request_cmp)__attribute__((__unused__)) static void appl_requests_RB_INSERT_COLOR (struct appl_requests *head, struct appl_request_downstream * elm) { struct appl_request_downstream *parent, *gparent, *tmp ; while ((parent = (elm)->ard_entry.rbe_parent) && (parent)->ard_entry.rbe_color == 1) { gparent = (parent)-> ard_entry.rbe_parent; if (parent == (gparent)->ard_entry.rbe_left ) { tmp = (gparent)->ard_entry.rbe_right; if (tmp && (tmp)->ard_entry.rbe_color == 1) { (tmp)->ard_entry.rbe_color = 0; do { (parent)->ard_entry.rbe_color = 0; (gparent)-> ard_entry.rbe_color = 1; } while (0); elm = gparent; continue ; } if ((parent)->ard_entry.rbe_right == elm) { do { (tmp) = (parent)->ard_entry.rbe_right; if (((parent)->ard_entry .rbe_right = (tmp)->ard_entry.rbe_left)) { ((tmp)->ard_entry .rbe_left)->ard_entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->ard_entry.rbe_parent = (parent)->ard_entry .rbe_parent)) { if ((parent) == ((parent)->ard_entry.rbe_parent )->ard_entry.rbe_left) ((parent)->ard_entry.rbe_parent) ->ard_entry.rbe_left = (tmp); else ((parent)->ard_entry .rbe_parent)->ard_entry.rbe_right = (tmp); } else (head)-> rbh_root = (tmp); (tmp)->ard_entry.rbe_left = (parent); (parent )->ard_entry.rbe_parent = (tmp); do {} while (0); if (((tmp )->ard_entry.rbe_parent)) do {} while (0); } while (0); tmp = parent; parent = elm; elm = tmp; } do { (parent)->ard_entry .rbe_color = 0; (gparent)->ard_entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)->ard_entry.rbe_left; if (((gparent )->ard_entry.rbe_left = (tmp)->ard_entry.rbe_right)) { ( (tmp)->ard_entry.rbe_right)->ard_entry.rbe_parent = (gparent ); } do {} while (0); if (((tmp)->ard_entry.rbe_parent = ( gparent)->ard_entry.rbe_parent)) { if ((gparent) == ((gparent )->ard_entry.rbe_parent)->ard_entry.rbe_left) ((gparent )->ard_entry.rbe_parent)->ard_entry.rbe_left = (tmp); else ((gparent)->ard_entry.rbe_parent)->ard_entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->ard_entry .rbe_right = (gparent); (gparent)->ard_entry.rbe_parent = ( tmp); do {} while (0); if (((tmp)->ard_entry.rbe_parent)) do {} while (0); } while (0); } else { tmp = (gparent)->ard_entry .rbe_left; if (tmp && (tmp)->ard_entry.rbe_color == 1) { (tmp)->ard_entry.rbe_color = 0; do { (parent)->ard_entry .rbe_color = 0; (gparent)->ard_entry.rbe_color = 1; } while (0); elm = gparent; continue; } if ((parent)->ard_entry.rbe_left == elm) { do { (tmp) = (parent)->ard_entry.rbe_left; if ( ((parent)->ard_entry.rbe_left = (tmp)->ard_entry.rbe_right )) { ((tmp)->ard_entry.rbe_right)->ard_entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->ard_entry.rbe_parent = (parent)->ard_entry.rbe_parent)) { if ((parent) == ((parent )->ard_entry.rbe_parent)->ard_entry.rbe_left) ((parent) ->ard_entry.rbe_parent)->ard_entry.rbe_left = (tmp); else ((parent)->ard_entry.rbe_parent)->ard_entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->ard_entry .rbe_right = (parent); (parent)->ard_entry.rbe_parent = (tmp ); do {} while (0); if (((tmp)->ard_entry.rbe_parent)) do { } while (0); } while (0); tmp = parent; parent = elm; elm = tmp ; } do { (parent)->ard_entry.rbe_color = 0; (gparent)-> ard_entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)-> ard_entry.rbe_right; if (((gparent)->ard_entry.rbe_right = (tmp)->ard_entry.rbe_left)) { ((tmp)->ard_entry.rbe_left )->ard_entry.rbe_parent = (gparent); } do {} while (0); if (((tmp)->ard_entry.rbe_parent = (gparent)->ard_entry.rbe_parent )) { if ((gparent) == ((gparent)->ard_entry.rbe_parent)-> ard_entry.rbe_left) ((gparent)->ard_entry.rbe_parent)-> ard_entry.rbe_left = (tmp); else ((gparent)->ard_entry.rbe_parent )->ard_entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->ard_entry.rbe_left = (gparent); (gparent) ->ard_entry.rbe_parent = (tmp); do {} while (0); if (((tmp )->ard_entry.rbe_parent)) do {} while (0); } while (0); } } (head->rbh_root)->ard_entry.rbe_color = 0; } __attribute__ ((__unused__)) static void appl_requests_RB_REMOVE_COLOR(struct appl_requests *head, struct appl_request_downstream *parent, struct appl_request_downstream *elm) { struct appl_request_downstream *tmp; while ((elm == ((void *)0) || (elm)->ard_entry.rbe_color == 0) && elm != (head)->rbh_root) { if ((parent)-> ard_entry.rbe_left == elm) { tmp = (parent)->ard_entry.rbe_right ; if ((tmp)->ard_entry.rbe_color == 1) { do { (tmp)->ard_entry .rbe_color = 0; (parent)->ard_entry.rbe_color = 1; } while (0); do { (tmp) = (parent)->ard_entry.rbe_right; if (((parent )->ard_entry.rbe_right = (tmp)->ard_entry.rbe_left)) { ( (tmp)->ard_entry.rbe_left)->ard_entry.rbe_parent = (parent ); } do {} while (0); if (((tmp)->ard_entry.rbe_parent = ( parent)->ard_entry.rbe_parent)) { if ((parent) == ((parent )->ard_entry.rbe_parent)->ard_entry.rbe_left) ((parent) ->ard_entry.rbe_parent)->ard_entry.rbe_left = (tmp); else ((parent)->ard_entry.rbe_parent)->ard_entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->ard_entry .rbe_left = (parent); (parent)->ard_entry.rbe_parent = (tmp ); do {} while (0); if (((tmp)->ard_entry.rbe_parent)) do { } while (0); } while (0); tmp = (parent)->ard_entry.rbe_right ; } if (((tmp)->ard_entry.rbe_left == ((void *)0) || ((tmp )->ard_entry.rbe_left)->ard_entry.rbe_color == 0) && ((tmp)->ard_entry.rbe_right == ((void *)0) || ((tmp)-> ard_entry.rbe_right)->ard_entry.rbe_color == 0)) { (tmp)-> ard_entry.rbe_color = 1; elm = parent; parent = (elm)->ard_entry .rbe_parent; } else { if ((tmp)->ard_entry.rbe_right == (( void *)0) || ((tmp)->ard_entry.rbe_right)->ard_entry.rbe_color == 0) { struct appl_request_downstream *oleft; if ((oleft = ( tmp)->ard_entry.rbe_left)) (oleft)->ard_entry.rbe_color = 0; (tmp)->ard_entry.rbe_color = 1; do { (oleft) = (tmp) ->ard_entry.rbe_left; if (((tmp)->ard_entry.rbe_left = ( oleft)->ard_entry.rbe_right)) { ((oleft)->ard_entry.rbe_right )->ard_entry.rbe_parent = (tmp); } do {} while (0); if ((( oleft)->ard_entry.rbe_parent = (tmp)->ard_entry.rbe_parent )) { if ((tmp) == ((tmp)->ard_entry.rbe_parent)->ard_entry .rbe_left) ((tmp)->ard_entry.rbe_parent)->ard_entry.rbe_left = (oleft); else ((tmp)->ard_entry.rbe_parent)->ard_entry .rbe_right = (oleft); } else (head)->rbh_root = (oleft); ( oleft)->ard_entry.rbe_right = (tmp); (tmp)->ard_entry.rbe_parent = (oleft); do {} while (0); if (((oleft)->ard_entry.rbe_parent )) do {} while (0); } while (0); tmp = (parent)->ard_entry .rbe_right; } (tmp)->ard_entry.rbe_color = (parent)->ard_entry .rbe_color; (parent)->ard_entry.rbe_color = 0; if ((tmp)-> ard_entry.rbe_right) ((tmp)->ard_entry.rbe_right)->ard_entry .rbe_color = 0; do { (tmp) = (parent)->ard_entry.rbe_right ; if (((parent)->ard_entry.rbe_right = (tmp)->ard_entry .rbe_left)) { ((tmp)->ard_entry.rbe_left)->ard_entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->ard_entry.rbe_parent = (parent)->ard_entry.rbe_parent)) { if ((parent) == ((parent )->ard_entry.rbe_parent)->ard_entry.rbe_left) ((parent) ->ard_entry.rbe_parent)->ard_entry.rbe_left = (tmp); else ((parent)->ard_entry.rbe_parent)->ard_entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->ard_entry .rbe_left = (parent); (parent)->ard_entry.rbe_parent = (tmp ); do {} while (0); if (((tmp)->ard_entry.rbe_parent)) do { } while (0); } while (0); elm = (head)->rbh_root; break; } } else { tmp = (parent)->ard_entry.rbe_left; if ((tmp)-> ard_entry.rbe_color == 1) { do { (tmp)->ard_entry.rbe_color = 0; (parent)->ard_entry.rbe_color = 1; } while (0); do { (tmp) = (parent)->ard_entry.rbe_left; if (((parent)->ard_entry .rbe_left = (tmp)->ard_entry.rbe_right)) { ((tmp)->ard_entry .rbe_right)->ard_entry.rbe_parent = (parent); } do {} while (0); if (((tmp)->ard_entry.rbe_parent = (parent)->ard_entry .rbe_parent)) { if ((parent) == ((parent)->ard_entry.rbe_parent )->ard_entry.rbe_left) ((parent)->ard_entry.rbe_parent) ->ard_entry.rbe_left = (tmp); else ((parent)->ard_entry .rbe_parent)->ard_entry.rbe_right = (tmp); } else (head)-> rbh_root = (tmp); (tmp)->ard_entry.rbe_right = (parent); ( parent)->ard_entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->ard_entry.rbe_parent)) do {} while (0); } while ( 0); tmp = (parent)->ard_entry.rbe_left; } if (((tmp)->ard_entry .rbe_left == ((void *)0) || ((tmp)->ard_entry.rbe_left)-> ard_entry.rbe_color == 0) && ((tmp)->ard_entry.rbe_right == ((void *)0) || ((tmp)->ard_entry.rbe_right)->ard_entry .rbe_color == 0)) { (tmp)->ard_entry.rbe_color = 1; elm = parent ; parent = (elm)->ard_entry.rbe_parent; } else { if ((tmp) ->ard_entry.rbe_left == ((void *)0) || ((tmp)->ard_entry .rbe_left)->ard_entry.rbe_color == 0) { struct appl_request_downstream *oright; if ((oright = (tmp)->ard_entry.rbe_right)) (oright )->ard_entry.rbe_color = 0; (tmp)->ard_entry.rbe_color = 1; do { (oright) = (tmp)->ard_entry.rbe_right; if (((tmp) ->ard_entry.rbe_right = (oright)->ard_entry.rbe_left)) { ((oright)->ard_entry.rbe_left)->ard_entry.rbe_parent = (tmp); } do {} while (0); if (((oright)->ard_entry.rbe_parent = (tmp)->ard_entry.rbe_parent)) { if ((tmp) == ((tmp)-> ard_entry.rbe_parent)->ard_entry.rbe_left) ((tmp)->ard_entry .rbe_parent)->ard_entry.rbe_left = (oright); else ((tmp)-> ard_entry.rbe_parent)->ard_entry.rbe_right = (oright); } else (head)->rbh_root = (oright); (oright)->ard_entry.rbe_left = (tmp); (tmp)->ard_entry.rbe_parent = (oright); do {} while (0); if (((oright)->ard_entry.rbe_parent)) do {} while (0 ); } while (0); tmp = (parent)->ard_entry.rbe_left; } (tmp )->ard_entry.rbe_color = (parent)->ard_entry.rbe_color; (parent)->ard_entry.rbe_color = 0; if ((tmp)->ard_entry .rbe_left) ((tmp)->ard_entry.rbe_left)->ard_entry.rbe_color = 0; do { (tmp) = (parent)->ard_entry.rbe_left; if (((parent )->ard_entry.rbe_left = (tmp)->ard_entry.rbe_right)) { ( (tmp)->ard_entry.rbe_right)->ard_entry.rbe_parent = (parent ); } do {} while (0); if (((tmp)->ard_entry.rbe_parent = ( parent)->ard_entry.rbe_parent)) { if ((parent) == ((parent )->ard_entry.rbe_parent)->ard_entry.rbe_left) ((parent) ->ard_entry.rbe_parent)->ard_entry.rbe_left = (tmp); else ((parent)->ard_entry.rbe_parent)->ard_entry.rbe_right = (tmp); } else (head)->rbh_root = (tmp); (tmp)->ard_entry .rbe_right = (parent); (parent)->ard_entry.rbe_parent = (tmp ); do {} while (0); if (((tmp)->ard_entry.rbe_parent)) do { } while (0); } while (0); elm = (head)->rbh_root; break; } } } if (elm) (elm)->ard_entry.rbe_color = 0; } __attribute__ ((__unused__)) static struct appl_request_downstream * appl_requests_RB_REMOVE (struct appl_requests *head, struct appl_request_downstream * elm) { struct appl_request_downstream *child, *parent, *old = elm; int color; if ((elm)->ard_entry.rbe_left == ((void * )0)) child = (elm)->ard_entry.rbe_right; else if ((elm)-> ard_entry.rbe_right == ((void *)0)) child = (elm)->ard_entry .rbe_left; else { struct appl_request_downstream *left; elm = (elm)->ard_entry.rbe_right; while ((left = (elm)->ard_entry .rbe_left)) elm = left; child = (elm)->ard_entry.rbe_right ; parent = (elm)->ard_entry.rbe_parent; color = (elm)-> ard_entry.rbe_color; if (child) (child)->ard_entry.rbe_parent = parent; if (parent) { if ((parent)->ard_entry.rbe_left == elm) (parent)->ard_entry.rbe_left = child; else (parent)-> ard_entry.rbe_right = child; do {} while (0); } else (head)-> rbh_root = child; if ((elm)->ard_entry.rbe_parent == old) parent = elm; (elm)->ard_entry = (old)->ard_entry; if ((old)-> ard_entry.rbe_parent) { if (((old)->ard_entry.rbe_parent)-> ard_entry.rbe_left == old) ((old)->ard_entry.rbe_parent)-> ard_entry.rbe_left = elm; else ((old)->ard_entry.rbe_parent )->ard_entry.rbe_right = elm; do {} while (0); } else (head )->rbh_root = elm; ((old)->ard_entry.rbe_left)->ard_entry .rbe_parent = elm; if ((old)->ard_entry.rbe_right) ((old)-> ard_entry.rbe_right)->ard_entry.rbe_parent = elm; if (parent ) { left = parent; do { do {} while (0); } while ((left = (left )->ard_entry.rbe_parent)); } goto color; } parent = (elm)-> ard_entry.rbe_parent; color = (elm)->ard_entry.rbe_color; if (child) (child)->ard_entry.rbe_parent = parent; if (parent ) { if ((parent)->ard_entry.rbe_left == elm) (parent)-> ard_entry.rbe_left = child; else (parent)->ard_entry.rbe_right = child; do {} while (0); } else (head)->rbh_root = child ; color: if (color == 0) appl_requests_RB_REMOVE_COLOR(head, parent , child); return (old); } __attribute__((__unused__)) static struct appl_request_downstream * appl_requests_RB_INSERT(struct appl_requests *head, struct appl_request_downstream *elm) { struct appl_request_downstream *tmp; struct appl_request_downstream *parent = ((void *)0); int comp = 0; tmp = (head)->rbh_root; while (tmp) { parent = tmp ; comp = (appl_request_cmp)(elm, parent); if (comp < 0) tmp = (tmp)->ard_entry.rbe_left; else if (comp > 0) tmp = ( tmp)->ard_entry.rbe_right; else return (tmp); } do { (elm) ->ard_entry.rbe_parent = parent; (elm)->ard_entry.rbe_left = (elm)->ard_entry.rbe_right = ((void *)0); (elm)->ard_entry .rbe_color = 1; } while (0); if (parent != ((void *)0)) { if ( comp < 0) (parent)->ard_entry.rbe_left = elm; else (parent )->ard_entry.rbe_right = elm; do {} while (0); } else (head )->rbh_root = elm; appl_requests_RB_INSERT_COLOR(head, elm ); return (((void *)0)); } __attribute__((__unused__)) static struct appl_request_downstream * appl_requests_RB_FIND(struct appl_requests *head, struct appl_request_downstream *elm) { struct appl_request_downstream *tmp = (head)->rbh_root; int comp ; while (tmp) { comp = appl_request_cmp(elm, tmp); if (comp < 0) tmp = (tmp)->ard_entry.rbe_left; else if (comp > 0) tmp = (tmp)->ard_entry.rbe_right; else return (tmp); } return (((void *)0)); } __attribute__((__unused__)) static struct appl_request_downstream * appl_requests_RB_NFIND(struct appl_requests *head, struct appl_request_downstream *elm) { struct appl_request_downstream *tmp = (head)->rbh_root ; struct appl_request_downstream *res = ((void *)0); int comp ; while (tmp) { comp = appl_request_cmp(elm, tmp); if (comp < 0) { res = tmp; tmp = (tmp)->ard_entry.rbe_left; } else if (comp > 0) tmp = (tmp)->ard_entry.rbe_right; else return (tmp); } return (res); } __attribute__((__unused__)) static struct appl_request_downstream * appl_requests_RB_NEXT(struct appl_request_downstream *elm) { if ((elm)->ard_entry.rbe_right) { elm = (elm)-> ard_entry.rbe_right; while ((elm)->ard_entry.rbe_left) elm = (elm)->ard_entry.rbe_left; } else { if ((elm)->ard_entry .rbe_parent && (elm == ((elm)->ard_entry.rbe_parent )->ard_entry.rbe_left)) elm = (elm)->ard_entry.rbe_parent ; else { while ((elm)->ard_entry.rbe_parent && (elm == ((elm)->ard_entry.rbe_parent)->ard_entry.rbe_right) ) elm = (elm)->ard_entry.rbe_parent; elm = (elm)->ard_entry .rbe_parent; } } return (elm); } __attribute__((__unused__)) static struct appl_request_downstream * appl_requests_RB_PREV(struct appl_request_downstream *elm) { if ((elm)->ard_entry.rbe_left ) { elm = (elm)->ard_entry.rbe_left; while ((elm)->ard_entry .rbe_right) elm = (elm)->ard_entry.rbe_right; } else { if ( (elm)->ard_entry.rbe_parent && (elm == ((elm)-> ard_entry.rbe_parent)->ard_entry.rbe_right)) elm = (elm)-> ard_entry.rbe_parent; else { while ((elm)->ard_entry.rbe_parent && (elm == ((elm)->ard_entry.rbe_parent)->ard_entry .rbe_left)) elm = (elm)->ard_entry.rbe_parent; elm = (elm) ->ard_entry.rbe_parent; } } return (elm); } __attribute__( (__unused__)) static struct appl_request_downstream * appl_requests_RB_MINMAX (struct appl_requests *head, int val) { struct appl_request_downstream *tmp = (head)->rbh_root; struct appl_request_downstream * parent = ((void *)0); while (tmp) { parent = tmp; if (val < 0) tmp = (tmp)->ard_entry.rbe_left; else tmp = (tmp)-> ard_entry.rbe_right; } return (parent); }; |