2 * Copyright (c) 2001-2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Author: Harti Brandt <harti@freebsd.org>
8 * Copyright (c) 2010 The FreeBSD Foundation
11 * Portions of this software were developed by Shteryana Sotirova Shopova
12 * under sponsorship from the FreeBSD Foundation.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
23 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * $Begemot: bsnmp/snmpd/trap.c,v 1.9 2005/10/04 11:21:39 brandt_h Exp $
39 #include <sys/types.h>
40 #include <sys/queue.h>
41 #include <sys/sysctl.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
58 #define SNMPTREE_TYPES
62 struct trapsink_list trapsink_list = TAILQ_HEAD_INITIALIZER(trapsink_list);
64 /* List of target addresses */
65 static struct target_addresslist target_addresslist =
66 SLIST_HEAD_INITIALIZER(target_addresslist);
68 /* List of target parameters */
69 static struct target_paramlist target_paramlist =
70 SLIST_HEAD_INITIALIZER(target_paramlist);
72 /* List of notification targets */
73 static struct target_notifylist target_notifylist =
74 SLIST_HEAD_INITIALIZER(target_notifylist);
76 static const struct asn_oid oid_begemotTrapSinkTable =
77 OIDX_begemotTrapSinkTable;
78 static const struct asn_oid oid_sysUpTime = OIDX_sysUpTime;
79 static const struct asn_oid oid_snmpTrapOID = OIDX_snmpTrapOID;
82 struct snmp_dependency dep;
85 u_char comm[SNMP_COMMUNITY_MAXLEN + 1];
90 u_char rb_comm[SNMP_COMMUNITY_MAXLEN + 1];
95 TDEP_VERSION = 0x0004,
99 TDEP_DESTROY = 0x0004,
103 trapsink_create(struct trapsink_dep *tdep)
106 struct sockaddr_in sa;
108 if ((t = malloc(sizeof(*t))) == NULL)
109 return (SNMP_ERR_RES_UNAVAIL);
111 t->index = tdep->dep.idx;
112 t->status = TRAPSINK_NOT_READY;
114 t->version = TRAPSINK_V2;
116 if ((t->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
117 syslog(LOG_ERR, "socket(UDP): %m");
119 return (SNMP_ERR_RES_UNAVAIL);
121 (void)shutdown(t->socket, SHUT_RD);
122 memset(&sa, 0, sizeof(sa));
123 sa.sin_len = sizeof(sa);
124 sa.sin_family = AF_INET;
125 sa.sin_addr.s_addr = htonl((t->index.subs[0] << 24) |
126 (t->index.subs[1] << 16) | (t->index.subs[2] << 8) |
127 (t->index.subs[3] << 0));
128 sa.sin_port = htons(t->index.subs[4]);
130 if (connect(t->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) {
131 syslog(LOG_ERR, "connect(%s,%u): %m",
132 inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
133 (void)close(t->socket);
135 return (SNMP_ERR_GENERR);
138 if (tdep->set & TDEP_VERSION)
139 t->version = tdep->version;
140 if (tdep->set & TDEP_COMM)
141 strcpy(t->comm, tdep->comm);
143 if (t->comm[0] != '\0')
144 t->status = TRAPSINK_NOT_IN_SERVICE;
146 /* look whether we should activate */
147 if (tdep->status == 4) {
148 if (t->status == TRAPSINK_NOT_READY) {
150 (void)close(t->socket);
152 return (SNMP_ERR_INCONS_VALUE);
154 t->status = TRAPSINK_ACTIVE;
157 INSERT_OBJECT_OID(t, &trapsink_list);
159 tdep->rb |= TDEP_CREATE;
161 return (SNMP_ERR_NOERROR);
165 trapsink_free(struct trapsink *t)
167 TAILQ_REMOVE(&trapsink_list, t, link);
169 (void)close(t->socket);
174 trapsink_modify(struct trapsink *t, struct trapsink_dep *tdep)
176 tdep->rb_status = t->status;
177 tdep->rb_version = t->version;
178 strcpy(tdep->rb_comm, t->comm);
180 if (tdep->set & TDEP_STATUS) {
181 /* if we are active and should move to not_in_service do
183 if (tdep->status == 2 && tdep->rb_status == TRAPSINK_ACTIVE) {
184 t->status = TRAPSINK_NOT_IN_SERVICE;
185 tdep->rb |= TDEP_MODIFY;
189 if (tdep->set & TDEP_VERSION)
190 t->version = tdep->version;
191 if (tdep->set & TDEP_COMM)
192 strcpy(t->comm, tdep->comm);
194 if (tdep->set & TDEP_STATUS) {
195 /* if we were inactive and should go active - do this now */
196 if (tdep->status == 1 && tdep->rb_status != TRAPSINK_ACTIVE) {
197 if (t->comm[0] == '\0') {
198 t->status = tdep->rb_status;
199 t->version = tdep->rb_version;
200 strcpy(t->comm, tdep->rb_comm);
201 return (SNMP_ERR_INCONS_VALUE);
203 t->status = TRAPSINK_ACTIVE;
204 tdep->rb |= TDEP_MODIFY;
207 return (SNMP_ERR_NOERROR);
211 trapsink_unmodify(struct trapsink *t, struct trapsink_dep *tdep)
213 if (tdep->set & TDEP_STATUS)
214 t->status = tdep->rb_status;
215 if (tdep->set & TDEP_VERSION)
216 t->version = tdep->rb_version;
217 if (tdep->set & TDEP_COMM)
218 strcpy(t->comm, tdep->rb_comm);
220 return (SNMP_ERR_NOERROR);
224 trapsink_destroy(struct snmp_context *ctx __unused, struct trapsink *t,
225 struct trapsink_dep *tdep)
227 t->status = TRAPSINK_DESTROY;
228 tdep->rb_status = t->status;
229 tdep->rb |= TDEP_DESTROY;
230 return (SNMP_ERR_NOERROR);
234 trapsink_undestroy(struct trapsink *t, struct trapsink_dep *tdep)
236 t->status = tdep->rb_status;
237 return (SNMP_ERR_NOERROR);
241 trapsink_dep(struct snmp_context *ctx, struct snmp_dependency *dep,
244 struct trapsink_dep *tdep = (struct trapsink_dep *)dep;
247 t = FIND_OBJECT_OID(&trapsink_list, &dep->idx, 0);
251 case SNMP_DEPOP_COMMIT:
252 if (tdep->set & TDEP_STATUS) {
253 switch (tdep->status) {
258 return (SNMP_ERR_INCONS_VALUE);
259 return (trapsink_modify(t, tdep));
264 return (SNMP_ERR_INCONS_VALUE);
265 return (trapsink_create(tdep));
269 return (SNMP_ERR_NOERROR);
270 return (trapsink_destroy(ctx, t, tdep));
272 } else if (tdep->set != 0)
273 return (trapsink_modify(t, tdep));
275 return (SNMP_ERR_NOERROR);
277 case SNMP_DEPOP_ROLLBACK:
278 if (tdep->rb & TDEP_CREATE) {
280 return (SNMP_ERR_NOERROR);
282 if (tdep->rb & TDEP_MODIFY)
283 return (trapsink_unmodify(t, tdep));
284 if(tdep->rb & TDEP_DESTROY)
285 return (trapsink_undestroy(t, tdep));
286 return (SNMP_ERR_NOERROR);
288 case SNMP_DEPOP_FINISH:
289 if ((tdep->rb & TDEP_DESTROY) && t != NULL &&
290 ctx->code == SNMP_RET_OK)
292 return (SNMP_ERR_NOERROR);
298 op_trapsink(struct snmp_context *ctx, struct snmp_value *value,
299 u_int sub, u_int iidx, enum snmp_op op)
305 struct trapsink_dep *tdep;
312 case SNMP_OP_GETNEXT:
313 if ((t = NEXT_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL)
314 return (SNMP_ERR_NOSUCHNAME);
315 index_append(&value->var, sub, &t->index);
319 if ((t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL)
320 return (SNMP_ERR_NOSUCHNAME);
324 if (index_decode(&value->var, sub, iidx, ipa, &port) ||
325 port == 0 || port > 65535)
326 return (SNMP_ERR_NO_CREATION);
327 t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub);
329 asn_slice_oid(&idx, &value->var, sub, value->var.len);
331 tdep = (struct trapsink_dep *)snmp_dep_lookup(ctx,
332 &oid_begemotTrapSinkTable, &idx,
333 sizeof(*tdep), trapsink_dep);
335 return (SNMP_ERR_RES_UNAVAIL);
337 switch (value->var.subs[sub - 1]) {
339 case LEAF_begemotTrapSinkStatus:
340 if (tdep->set & TDEP_STATUS)
341 return (SNMP_ERR_INCONS_VALUE);
342 switch (value->v.integer) {
347 return (SNMP_ERR_INCONS_VALUE);
353 return (SNMP_ERR_INCONS_VALUE);
360 return (SNMP_ERR_WRONG_VALUE);
362 tdep->status = value->v.integer;
363 tdep->set |= TDEP_STATUS;
364 return (SNMP_ERR_NOERROR);
366 case LEAF_begemotTrapSinkComm:
367 if (tdep->set & TDEP_COMM)
368 return (SNMP_ERR_INCONS_VALUE);
369 if (value->v.octetstring.len == 0 ||
370 value->v.octetstring.len > SNMP_COMMUNITY_MAXLEN)
371 return (SNMP_ERR_WRONG_VALUE);
372 for (p = value->v.octetstring.octets;
373 p < value->v.octetstring.octets + value->v.octetstring.len;
375 if (!isascii(*p) || !isprint(*p))
376 return (SNMP_ERR_WRONG_VALUE);
378 tdep->set |= TDEP_COMM;
379 strncpy(tdep->comm, value->v.octetstring.octets,
380 value->v.octetstring.len);
381 tdep->comm[value->v.octetstring.len] = '\0';
382 return (SNMP_ERR_NOERROR);
384 case LEAF_begemotTrapSinkVersion:
385 if (tdep->set & TDEP_VERSION)
386 return (SNMP_ERR_INCONS_VALUE);
387 if (value->v.integer != TRAPSINK_V1 &&
388 value->v.integer != TRAPSINK_V2)
389 return (SNMP_ERR_WRONG_VALUE);
390 tdep->version = value->v.integer;
391 tdep->set |= TDEP_VERSION;
392 return (SNMP_ERR_NOERROR);
395 return (SNMP_ERR_INCONS_NAME);
397 return (SNMP_ERR_NOT_WRITEABLE);
400 case SNMP_OP_ROLLBACK:
402 return (SNMP_ERR_NOERROR);
405 switch (value->var.subs[sub - 1]) {
407 case LEAF_begemotTrapSinkStatus:
408 value->v.integer = t->status;
411 case LEAF_begemotTrapSinkComm:
412 return (string_get(value, t->comm, -1));
414 case LEAF_begemotTrapSinkVersion:
415 value->v.integer = t->version;
419 return (SNMP_ERR_NOERROR);
423 snmp_create_v1_trap(struct snmp_pdu *pdu, char *com,
424 const struct asn_oid *trap_oid)
426 memset(pdu, 0, sizeof(*pdu));
427 strlcpy(pdu->community, com, sizeof(pdu->community));
429 pdu->version = SNMP_V1;
430 pdu->type = SNMP_PDU_TRAP;
431 pdu->enterprise = systemg.object_id;
432 memcpy(pdu->agent_addr, snmpd.trap1addr, 4);
433 pdu->generic_trap = trap_oid->subs[trap_oid->len - 1] - 1;
434 pdu->specific_trap = 0;
435 pdu->time_stamp = get_ticks() - start_tick;
440 snmp_create_v2_trap(struct snmp_pdu *pdu, char *com,
441 const struct asn_oid *trap_oid)
443 memset(pdu, 0, sizeof(*pdu));
444 strlcpy(pdu->community, com, sizeof(pdu->community));
446 pdu->version = SNMP_V2c;
447 pdu->type = SNMP_PDU_TRAP2;
448 pdu->request_id = reqid_next(trap_reqid);
449 pdu->error_index = 0;
450 pdu->error_status = SNMP_ERR_NOERROR;
452 pdu->bindings[0].var = oid_sysUpTime;
453 pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0;
454 pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS;
455 pdu->bindings[0].v.uint32 = get_ticks() - start_tick;
457 pdu->bindings[1].var = oid_snmpTrapOID;
458 pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0;
459 pdu->bindings[1].syntax = SNMP_SYNTAX_OID;
460 pdu->bindings[1].v.oid = *trap_oid;
466 snmp_create_v3_trap(struct snmp_pdu *pdu, struct target_param *target,
467 const struct asn_oid *trap_oid)
469 struct usm_user *usmuser;
471 memset(pdu, 0, sizeof(*pdu));
473 pdu->version = SNMP_V3;
474 pdu->type = SNMP_PDU_TRAP2;
475 pdu->request_id = reqid_next(trap_reqid);
476 pdu->error_index = 0;
477 pdu->error_status = SNMP_ERR_NOERROR;
479 pdu->bindings[0].var = oid_sysUpTime;
480 pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0;
481 pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS;
482 pdu->bindings[0].v.uint32 = get_ticks() - start_tick;
484 pdu->bindings[1].var = oid_snmpTrapOID;
485 pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0;
486 pdu->bindings[1].syntax = SNMP_SYNTAX_OID;
487 pdu->bindings[1].v.oid = *trap_oid;
491 update_snmpd_engine_time();
493 memcpy(pdu->engine.engine_id, snmpd_engine.engine_id,
494 snmpd_engine.engine_len);
495 pdu->engine.engine_len = snmpd_engine.engine_len;
496 pdu->engine.engine_boots = snmpd_engine.engine_boots;
497 pdu->engine.engine_time = snmpd_engine.engine_time;
498 pdu->engine.max_msg_size = snmpd_engine.max_msg_size;
499 strlcpy(pdu->user.sec_name, target->secname,
500 sizeof(pdu->user.sec_name));
501 pdu->security_model = target->sec_model;
503 pdu->context_engine_len = snmpd_engine.engine_len;
504 memcpy(pdu->context_engine, snmpd_engine.engine_id,
505 snmpd_engine.engine_len);
507 if (target->sec_model == SNMP_SECMODEL_USM &&
508 target->sec_level != SNMP_noAuthNoPriv) {
509 usmuser = usm_find_user(pdu->engine.engine_id,
510 pdu->engine.engine_len, pdu->user.sec_name);
511 if (usmuser != NULL) {
512 pdu->user.auth_proto = usmuser->suser.auth_proto;
513 pdu->user.priv_proto = usmuser->suser.priv_proto;
514 memcpy(pdu->user.auth_key, usmuser->suser.auth_key,
515 sizeof(pdu->user.auth_key));
516 memcpy(pdu->user.priv_key, usmuser->suser.priv_key,
517 sizeof(pdu->user.priv_key));
519 snmp_pdu_init_secparams(pdu);
524 snmp_send_trap(const struct asn_oid *trap_oid, ...)
528 const struct snmp_value *v;
529 struct target_notify *n;
530 struct target_address *ta;
531 struct target_param *tp;
540 TAILQ_FOREACH(t, &trapsink_list, link) {
541 if (t->status != TRAPSINK_ACTIVE)
544 if (t->version == TRAPSINK_V1)
545 snmp_create_v1_trap(&pdu, t->comm, trap_oid);
547 snmp_create_v2_trap(&pdu, t->comm, trap_oid);
549 va_start(ap, trap_oid);
550 while ((v = va_arg(ap, const struct snmp_value *)) != NULL)
551 pdu.bindings[pdu.nbindings++] = *v;
554 if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) {
555 syslog(LOG_DEBUG, "send trap to %s failed: no access",
560 if ((sndbuf = buf_alloc(1)) == NULL) {
561 syslog(LOG_ERR, "trap send buffer: %m");
565 snmp_output(&pdu, sndbuf, &sndlen, "TRAP");
567 if ((len = send(t->socket, sndbuf, sndlen, 0)) == -1)
568 syslog(LOG_ERR, "send: %m");
569 else if ((size_t)len != sndlen)
570 syslog(LOG_ERR, "send: short write %zu/%zu",
571 sndlen, (size_t)len);
576 SLIST_FOREACH(n, &target_notifylist, tn) {
577 if (n->status != RowStatus_active || n->taglist[0] == '\0')
580 SLIST_FOREACH(ta, &target_addresslist, ta)
581 if ((tag = strstr(ta->taglist, n->taglist)) != NULL &&
582 (tag[strlen(n->taglist)] == ' ' ||
583 tag[strlen(n->taglist)] == '\0' ||
584 tag[strlen(n->taglist)] == '\t' ||
585 tag[strlen(n->taglist)] == '\r' ||
586 tag[strlen(n->taglist)] == '\n') &&
587 ta->status == RowStatus_active)
592 SLIST_FOREACH(tp, &target_paramlist, tp)
593 if (strcmp(tp->name, ta->paramname) == 0 &&
599 switch (tp->mpmodel) {
600 case SNMP_MPM_SNMP_V1:
601 snmp_create_v1_trap(&pdu, tp->secname, trap_oid);
604 case SNMP_MPM_SNMP_V2c:
605 snmp_create_v2_trap(&pdu, tp->secname, trap_oid);
608 case SNMP_MPM_SNMP_V3:
609 snmp_create_v3_trap(&pdu, tp, trap_oid);
616 va_start(ap, trap_oid);
617 while ((v = va_arg(ap, const struct snmp_value *)) != NULL)
618 pdu.bindings[pdu.nbindings++] = *v;
621 if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) {
622 syslog(LOG_DEBUG, "send trap to %s failed: no access",
627 if ((sndbuf = buf_alloc(1)) == NULL) {
628 syslog(LOG_ERR, "trap send buffer: %m");
632 snmp_output(&pdu, sndbuf, &sndlen, "TRAP");
634 if ((len = send(ta->socket, sndbuf, sndlen, 0)) == -1)
635 syslog(LOG_ERR, "send: %m");
636 else if ((size_t)len != sndlen)
637 syslog(LOG_ERR, "send: short write %zu/%zu",
638 sndlen, (size_t)len);
645 * RFC 3413 SNMP Management Target MIB
647 struct snmpd_target_stats *
648 bsnmpd_get_target_stats(void)
650 return (&snmpd_target_stats);
653 struct target_address *
654 target_first_address(void)
656 return (SLIST_FIRST(&target_addresslist));
659 struct target_address *
660 target_next_address(struct target_address *addrs)
665 return (SLIST_NEXT(addrs, ta));
668 struct target_address *
669 target_new_address(char *aname)
672 struct target_address *addrs, *temp, *prev;
674 SLIST_FOREACH(addrs, &target_addresslist, ta)
675 if (strcmp(aname, addrs->name) == 0)
678 if ((addrs = (struct target_address *)malloc(sizeof(*addrs))) == NULL)
681 memset(addrs, 0, sizeof(*addrs));
682 strlcpy(addrs->name, aname, sizeof(addrs->name));
683 addrs->timeout = 150;
684 addrs->retry = 3; /* XXX */
686 if ((prev = SLIST_FIRST(&target_addresslist)) == NULL ||
687 strcmp(aname, prev->name) < 0) {
688 SLIST_INSERT_HEAD(&target_addresslist, addrs, ta);
692 SLIST_FOREACH(temp, &target_addresslist, ta) {
693 if ((cmp = strcmp(aname, temp->name)) <= 0)
698 if (temp == NULL || cmp < 0)
699 SLIST_INSERT_AFTER(prev, addrs, ta);
701 SLIST_INSERT_AFTER(temp, addrs, ta);
703 syslog(LOG_ERR, "Target address %s exists", addrs->name);
712 target_activate_address(struct target_address *addrs)
714 struct sockaddr_in sa;
716 if ((addrs->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
717 syslog(LOG_ERR, "socket(UDP): %m");
718 return (SNMP_ERR_RES_UNAVAIL);
721 (void)shutdown(addrs->socket, SHUT_RD);
722 memset(&sa, 0, sizeof(sa));
723 sa.sin_len = sizeof(sa);
724 sa.sin_family = AF_INET;
726 sa.sin_addr.s_addr = htonl((addrs->address[0] << 24) |
727 (addrs->address[1] << 16) | (addrs->address[2] << 8) |
728 (addrs->address[3] << 0));
729 sa.sin_port = htons(addrs->address[4] << 8 | addrs->address[5]);
731 if (connect(addrs->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) {
732 syslog(LOG_ERR, "connect(%s,%u): %m",
733 inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
734 (void)close(addrs->socket);
735 return (SNMP_ERR_GENERR);
738 addrs->status = RowStatus_active;
740 return (SNMP_ERR_NOERROR);
744 target_delete_address(struct target_address *addrs)
746 SLIST_REMOVE(&target_addresslist, addrs, target_address, ta);
747 if (addrs->status == RowStatus_active)
748 close(addrs->socket);
754 struct target_param *
755 target_first_param(void)
757 return (SLIST_FIRST(&target_paramlist));
760 struct target_param *
761 target_next_param(struct target_param *param)
766 return (SLIST_NEXT(param, tp));
769 struct target_param *
770 target_new_param(char *pname)
773 struct target_param *param, *temp, *prev;
775 SLIST_FOREACH(param, &target_paramlist, tp)
776 if (strcmp(pname, param->name) == 0)
779 if ((param = (struct target_param *)malloc(sizeof(*param))) == NULL)
782 memset(param, 0, sizeof(*param));
783 strlcpy(param->name, pname, sizeof(param->name));
785 if ((prev = SLIST_FIRST(&target_paramlist)) == NULL ||
786 strcmp(pname, prev->name) < 0) {
787 SLIST_INSERT_HEAD(&target_paramlist, param, tp);
791 SLIST_FOREACH(temp, &target_paramlist, tp) {
792 if ((cmp = strcmp(pname, temp->name)) <= 0)
797 if (temp == NULL || cmp < 0)
798 SLIST_INSERT_AFTER(prev, param, tp);
800 SLIST_INSERT_AFTER(temp, param, tp);
802 syslog(LOG_ERR, "Target parameter %s exists", param->name);
811 target_delete_param(struct target_param *param)
813 SLIST_REMOVE(&target_paramlist, param, target_param, tp);
819 struct target_notify *
820 target_first_notify(void)
822 return (SLIST_FIRST(&target_notifylist));
825 struct target_notify *
826 target_next_notify(struct target_notify *notify)
831 return (SLIST_NEXT(notify, tn));
834 struct target_notify *
835 target_new_notify(char *nname)
838 struct target_notify *notify, *temp, *prev;
840 SLIST_FOREACH(notify, &target_notifylist, tn)
841 if (strcmp(nname, notify->name) == 0)
844 if ((notify = (struct target_notify *)malloc(sizeof(*notify))) == NULL)
847 memset(notify, 0, sizeof(*notify));
848 strlcpy(notify->name, nname, sizeof(notify->name));
850 if ((prev = SLIST_FIRST(&target_notifylist)) == NULL ||
851 strcmp(nname, prev->name) < 0) {
852 SLIST_INSERT_HEAD(&target_notifylist, notify, tn);
856 SLIST_FOREACH(temp, &target_notifylist, tn) {
857 if ((cmp = strcmp(nname, temp->name)) <= 0)
862 if (temp == NULL || cmp < 0)
863 SLIST_INSERT_AFTER(prev, notify, tn);
865 SLIST_INSERT_AFTER(temp, notify, tn);
867 syslog(LOG_ERR, "Notification target %s exists", notify->name);
876 target_delete_notify(struct target_notify *notify)
878 SLIST_REMOVE(&target_notifylist, notify, target_notify, tn);
885 target_flush_all(void)
887 struct target_address *addrs;
888 struct target_param *param;
889 struct target_notify *notify;
891 while ((addrs = SLIST_FIRST(&target_addresslist)) != NULL) {
892 SLIST_REMOVE_HEAD(&target_addresslist, ta);
893 if (addrs->status == RowStatus_active)
894 close(addrs->socket);
897 SLIST_INIT(&target_addresslist);
899 while ((param = SLIST_FIRST(&target_paramlist)) != NULL) {
900 SLIST_REMOVE_HEAD(&target_paramlist, tp);
903 SLIST_INIT(&target_paramlist);
905 while ((notify = SLIST_FIRST(&target_notifylist)) != NULL) {
906 SLIST_REMOVE_HEAD(&target_notifylist, tn);
909 SLIST_INIT(&target_notifylist);