trap.c (216294) | trap.c (216594) |
---|---|
1/* 2 * Copyright (c) 2001-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Author: Harti Brandt <harti@freebsd.org> | 1/* 2 * Copyright (c) 2001-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Author: Harti Brandt <harti@freebsd.org> |
7 * | 7 * 8 * Copyright (c) 2010 The FreeBSD Foundation 9 * All rights reserved. 10 * 11 * Portions of this software were developed by Shteryana Sotirova Shopova 12 * under sponsorship from the FreeBSD Foundation. 13 * |
8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. --- 13 unchanged lines hidden (view full) --- 29 * $Begemot: bsnmp/snmpd/trap.c,v 1.9 2005/10/04 11:21:39 brandt_h Exp $ 30 * 31 * TrapSinkTable 32 */ 33#include <sys/types.h> 34#include <sys/queue.h> 35#include <sys/sysctl.h> 36#include <sys/un.h> | 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 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. --- 13 unchanged lines hidden (view full) --- 35 * $Begemot: bsnmp/snmpd/trap.c,v 1.9 2005/10/04 11:21:39 brandt_h Exp $ 36 * 37 * TrapSinkTable 38 */ 39#include <sys/types.h> 40#include <sys/queue.h> 41#include <sys/sysctl.h> 42#include <sys/un.h> |
43#include <stdint.h> |
|
37#include <stdio.h> 38#include <stdlib.h> 39#include <stdarg.h> 40#include <stdarg.h> 41#include <string.h> 42#include <ctype.h> 43#include <syslog.h> 44#include <unistd.h> 45#include <netinet/in.h> 46#include <arpa/inet.h> 47 48#include "snmpmod.h" 49#include "snmpd.h" 50#include "tree.h" 51#include "oid.h" 52 53struct trapsink_list trapsink_list = TAILQ_HEAD_INITIALIZER(trapsink_list); 54 | 44#include <stdio.h> 45#include <stdlib.h> 46#include <stdarg.h> 47#include <stdarg.h> 48#include <string.h> 49#include <ctype.h> 50#include <syslog.h> 51#include <unistd.h> 52#include <netinet/in.h> 53#include <arpa/inet.h> 54 55#include "snmpmod.h" 56#include "snmpd.h" 57#include "tree.h" 58#include "oid.h" 59 60struct trapsink_list trapsink_list = TAILQ_HEAD_INITIALIZER(trapsink_list); 61 |
62/* List of target addresses */ 63struct target_addresslist target_addresslist = 64 SLIST_HEAD_INITIALIZER(target_addresslist); 65 66/* List of target parameters */ 67struct target_paramlist target_paramlist = 68 SLIST_HEAD_INITIALIZER(target_paramlist); 69 70/* List of notification targets */ 71struct target_notifylist target_notifylist = 72 SLIST_HEAD_INITIALIZER(target_notifylist); 73 |
|
55static const struct asn_oid oid_begemotTrapSinkTable = 56 OIDX_begemotTrapSinkTable; 57static const struct asn_oid oid_sysUpTime = OIDX_sysUpTime; 58static const struct asn_oid oid_snmpTrapOID = OIDX_snmpTrapOID; 59 60struct trapsink_dep { 61 struct snmp_dependency dep; 62 u_int set; --- 330 unchanged lines hidden (view full) --- 393 case LEAF_begemotTrapSinkVersion: 394 value->v.integer = t->version; 395 break; 396 397 } 398 return (SNMP_ERR_NOERROR); 399} 400 | 74static const struct asn_oid oid_begemotTrapSinkTable = 75 OIDX_begemotTrapSinkTable; 76static const struct asn_oid oid_sysUpTime = OIDX_sysUpTime; 77static const struct asn_oid oid_snmpTrapOID = OIDX_snmpTrapOID; 78 79struct trapsink_dep { 80 struct snmp_dependency dep; 81 u_int set; --- 330 unchanged lines hidden (view full) --- 412 case LEAF_begemotTrapSinkVersion: 413 value->v.integer = t->version; 414 break; 415 416 } 417 return (SNMP_ERR_NOERROR); 418} 419 |
420static void 421snmp_create_v1_trap(struct snmp_pdu *pdu, char *com, 422 const struct asn_oid *trap_oid) 423{ 424 memset(pdu, 0, sizeof(*pdu)); 425 strcpy(pdu->community, com); 426 427 pdu->version = SNMP_V1; 428 pdu->type = SNMP_PDU_TRAP; 429 pdu->enterprise = systemg.object_id; 430 memcpy(pdu->agent_addr, snmpd.trap1addr, 4); 431 pdu->generic_trap = trap_oid->subs[trap_oid->len - 1] - 1; 432 pdu->specific_trap = 0; 433 pdu->time_stamp = get_ticks() - start_tick; 434 pdu->nbindings = 0; 435} 436 437static void 438snmp_create_v2_trap(struct snmp_pdu *pdu, char *com, 439 const struct asn_oid *trap_oid) 440{ 441 memset(pdu, 0, sizeof(*pdu)); 442 strcpy(pdu->community, com); 443 444 pdu->version = SNMP_V2c; 445 pdu->type = SNMP_PDU_TRAP2; 446 pdu->request_id = reqid_next(trap_reqid); 447 pdu->error_index = 0; 448 pdu->error_status = SNMP_ERR_NOERROR; 449 450 pdu->bindings[0].var = oid_sysUpTime; 451 pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; 452 pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; 453 pdu->bindings[0].v.uint32 = get_ticks() - start_tick; 454 455 pdu->bindings[1].var = oid_snmpTrapOID; 456 pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; 457 pdu->bindings[1].syntax = SNMP_SYNTAX_OID; 458 pdu->bindings[1].v.oid = *trap_oid; 459 460 pdu->nbindings = 2; 461} 462 463static void 464snmp_create_v3_trap(struct snmp_pdu *pdu, struct target_param *target, 465 const struct asn_oid *trap_oid) 466{ 467 uint64_t etime; 468 struct usm_user *usmuser; 469 470 memset(pdu, 0, sizeof(*pdu)); 471 472 pdu->version = SNMP_V3; 473 pdu->type = SNMP_PDU_TRAP2; 474 pdu->request_id = reqid_next(trap_reqid); 475 pdu->error_index = 0; 476 pdu->error_status = SNMP_ERR_NOERROR; 477 478 pdu->bindings[0].var = oid_sysUpTime; 479 pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; 480 pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; 481 pdu->bindings[0].v.uint32 = get_ticks() - start_tick; 482 483 pdu->bindings[1].var = oid_snmpTrapOID; 484 pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; 485 pdu->bindings[1].syntax = SNMP_SYNTAX_OID; 486 pdu->bindings[1].v.oid = *trap_oid; 487 488 pdu->nbindings = 2; 489 490 etime = (get_ticks() - start_tick) / 100ULL; 491 if (etime < INT32_MAX) 492 snmpd_engine.engine_time = etime; 493 else { 494 start_tick = get_ticks(); 495 set_snmpd_engine(); 496 snmpd_engine.engine_time = start_tick; 497 } 498 499 memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, 500 snmpd_engine.engine_len); 501 pdu->engine.engine_len = snmpd_engine.engine_len; 502 pdu->engine.engine_boots = snmpd_engine.engine_boots; 503 pdu->engine.engine_time = snmpd_engine.engine_time; 504 pdu->engine.max_msg_size = snmpd_engine.max_msg_size; 505 strlcpy(pdu->user.sec_name, target->secname, 506 sizeof(pdu->user.sec_name)); 507 pdu->security_model = target->sec_model; 508 509 pdu->context_engine_len = snmpd_engine.engine_len; 510 memcpy(pdu->context_engine, snmpd_engine.engine_id, 511 snmpd_engine.engine_len); 512 513 if (target->sec_model == SNMP_SECMODEL_USM && 514 target->sec_level != SNMP_noAuthNoPriv) { 515 usmuser = usm_find_user(pdu->engine.engine_id, 516 pdu->engine.engine_len, pdu->user.sec_name); 517 if (usmuser != NULL) { 518 pdu->user.auth_proto = usmuser->suser.auth_proto; 519 pdu->user.priv_proto = usmuser->suser.priv_proto; 520 memcpy(pdu->user.auth_key, usmuser->suser.auth_key, 521 sizeof(pdu->user.auth_key)); 522 memcpy(pdu->user.priv_key, usmuser->suser.priv_key, 523 sizeof(pdu->user.priv_key)); 524 } 525 snmp_pdu_init_secparams(pdu); 526 } 527} 528 |
|
401void 402snmp_send_trap(const struct asn_oid *trap_oid, ...) 403{ 404 struct snmp_pdu pdu; 405 struct trapsink *t; 406 const struct snmp_value *v; | 529void 530snmp_send_trap(const struct asn_oid *trap_oid, ...) 531{ 532 struct snmp_pdu pdu; 533 struct trapsink *t; 534 const struct snmp_value *v; |
535 struct target_notify *n; 536 struct target_address *ta; 537 struct target_param *tp; 538 |
|
407 va_list ap; 408 u_char *sndbuf; | 539 va_list ap; 540 u_char *sndbuf; |
541 char *tag; |
|
409 size_t sndlen; 410 ssize_t len; | 542 size_t sndlen; 543 ssize_t len; |
544 int32_t ip; |
|
411 412 TAILQ_FOREACH(t, &trapsink_list, link) { 413 if (t->status != TRAPSINK_ACTIVE) 414 continue; | 545 546 TAILQ_FOREACH(t, &trapsink_list, link) { 547 if (t->status != TRAPSINK_ACTIVE) 548 continue; |
415 memset(&pdu, 0, sizeof(pdu)); 416 strcpy(pdu.community, t->comm); 417 if (t->version == TRAPSINK_V1) { 418 pdu.version = SNMP_V1; 419 pdu.type = SNMP_PDU_TRAP; 420 pdu.enterprise = systemg.object_id; 421 memcpy(pdu.agent_addr, snmpd.trap1addr, 4); 422 pdu.generic_trap = trap_oid->subs[trap_oid->len - 1] - 1; 423 pdu.specific_trap = 0; 424 pdu.time_stamp = get_ticks() - start_tick; | 549 550 if (t->version == TRAPSINK_V1) 551 snmp_create_v1_trap(&pdu, t->comm, trap_oid); 552 else 553 snmp_create_v2_trap(&pdu, t->comm, trap_oid); |
425 | 554 |
426 pdu.nbindings = 0; 427 } else { 428 pdu.version = SNMP_V2c; 429 pdu.type = SNMP_PDU_TRAP2; 430 pdu.request_id = reqid_next(trap_reqid); 431 pdu.error_index = 0; 432 pdu.error_status = SNMP_ERR_NOERROR; | 555 va_start(ap, trap_oid); 556 while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 557 pdu.bindings[pdu.nbindings++] = *v; 558 va_end(ap); |
433 | 559 |
434 pdu.bindings[0].var = oid_sysUpTime; 435 pdu.bindings[0].var.subs[pdu.bindings[0].var.len++] = 0; 436 pdu.bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; 437 pdu.bindings[0].v.uint32 = get_ticks() - start_tick; | 560 if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { 561 syslog(LOG_DEBUG, "send trap to %s failed: no access", 562 t->comm); 563 continue; 564 } |
438 | 565 |
439 pdu.bindings[1].var = oid_snmpTrapOID; 440 pdu.bindings[1].var.subs[pdu.bindings[1].var.len++] = 0; 441 pdu.bindings[1].syntax = SNMP_SYNTAX_OID; 442 pdu.bindings[1].v.oid = *trap_oid; | 566 if ((sndbuf = buf_alloc(1)) == NULL) { 567 syslog(LOG_ERR, "trap send buffer: %m"); 568 return; 569 } |
443 | 570 |
444 pdu.nbindings = 2; | 571 snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 572 573 if ((len = send(t->socket, sndbuf, sndlen, 0)) == -1) 574 syslog(LOG_ERR, "send: %m"); 575 else if ((size_t)len != sndlen) 576 syslog(LOG_ERR, "send: short write %zu/%zu", 577 sndlen, (size_t)len); 578 579 free(sndbuf); 580 } 581 582 SLIST_FOREACH(n, &target_notifylist, tn) { 583 if (n->status != RowStatus_active || n->taglist[0] == '\0') 584 continue; 585 586 SLIST_FOREACH(ta, &target_addresslist, ta) 587 if ((tag = strstr(ta->taglist, n->taglist)) != NULL && 588 (tag[strlen(n->taglist)] == ' ' || 589 tag[strlen(n->taglist)] == '\0' || 590 tag[strlen(n->taglist)] == '\t' || 591 tag[strlen(n->taglist)] == '\r' || 592 tag[strlen(n->taglist)] == '\n') && 593 ta->status == RowStatus_active) 594 break; 595 if (ta == NULL) 596 continue; 597 598 SLIST_FOREACH(tp, &target_paramlist, tp) 599 if (strcmp(tp->name, ta->paramname) == 0 && 600 tp->status == 1) 601 break; 602 if (tp == NULL) 603 continue; 604 605 switch (tp->mpmodel) { 606 case SNMP_MPM_SNMP_V1: 607 snmp_create_v1_trap(&pdu, tp->secname, trap_oid); 608 break; 609 610 case SNMP_MPM_SNMP_V2c: 611 snmp_create_v2_trap(&pdu, tp->secname, trap_oid); 612 break; 613 614 case SNMP_MPM_SNMP_V3: 615 snmp_create_v3_trap(&pdu, tp, trap_oid); 616 break; 617 618 default: 619 continue; |
445 } 446 447 va_start(ap, trap_oid); 448 while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 449 pdu.bindings[pdu.nbindings++] = *v; 450 va_end(ap); 451 | 620 } 621 622 va_start(ap, trap_oid); 623 while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 624 pdu.bindings[pdu.nbindings++] = *v; 625 va_end(ap); 626 |
627 if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { 628 syslog(LOG_DEBUG, "send trap to %s failed: no access", 629 t->comm); 630 continue; 631 } 632 |
|
452 if ((sndbuf = buf_alloc(1)) == NULL) { 453 syslog(LOG_ERR, "trap send buffer: %m"); 454 return; 455 } 456 457 snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 458 | 633 if ((sndbuf = buf_alloc(1)) == NULL) { 634 syslog(LOG_ERR, "trap send buffer: %m"); 635 return; 636 } 637 638 snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 639 |
459 if ((len = send(t->socket, sndbuf, sndlen, 0)) == -1) | 640 if ((len = send(ta->socket, sndbuf, sndlen, 0)) == -1) |
460 syslog(LOG_ERR, "send: %m"); 461 else if ((size_t)len != sndlen) 462 syslog(LOG_ERR, "send: short write %zu/%zu", 463 sndlen, (size_t)len); 464 465 free(sndbuf); 466 } 467} | 641 syslog(LOG_ERR, "send: %m"); 642 else if ((size_t)len != sndlen) 643 syslog(LOG_ERR, "send: short write %zu/%zu", 644 sndlen, (size_t)len); 645 646 free(sndbuf); 647 } 648} |
649 650/* 651 * RFC 3413 SNMP Management Target MIB 652 */ 653struct snmpd_target_stats * 654bsnmpd_get_target_stats(void) 655{ 656 return (&snmpd_target_stats); 657} 658 659struct target_address * 660target_first_address(void) 661{ 662 return (SLIST_FIRST(&target_addresslist)); 663} 664 665struct target_address * 666target_next_address(struct target_address *addrs) 667{ 668 if (addrs == NULL) 669 return (NULL); 670 671 return (SLIST_NEXT(addrs, ta)); 672} 673 674struct target_address * 675target_new_address(char *aname) 676{ 677 int cmp; 678 struct target_address *addrs, *temp, *prev; 679 680 SLIST_FOREACH(addrs, &target_addresslist, ta) 681 if (strcmp(aname, addrs->name) == 0) 682 return (NULL); 683 684 if ((addrs = (struct target_address *)malloc(sizeof(*addrs))) == NULL) 685 return (NULL); 686 687 memset(addrs, 0, sizeof(*addrs)); 688 strlcpy(addrs->name, aname, sizeof(addrs->name)); 689 addrs->timeout = 150; 690 addrs->retry = 3; /* XXX */ 691 692 if ((prev = SLIST_FIRST(&target_addresslist)) == NULL || 693 strcmp(aname, prev->name) < 0) { 694 SLIST_INSERT_HEAD(&target_addresslist, addrs, ta); 695 return (addrs); 696 } 697 698 SLIST_FOREACH(temp, &target_addresslist, ta) { 699 if ((cmp = strcmp(aname, temp->name)) <= 0) 700 break; 701 prev = temp; 702 } 703 704 if (temp == NULL || cmp < 0) 705 SLIST_INSERT_AFTER(prev, addrs, ta); 706 else if (cmp > 0) 707 SLIST_INSERT_AFTER(temp, addrs, ta); 708 else { 709 syslog(LOG_ERR, "Target address %s exists", addrs->name); 710 free(addrs); 711 return (NULL); 712 } 713 714 return (addrs); 715} 716 717int 718target_activate_address(struct target_address *addrs) 719{ 720 struct sockaddr_in sa; 721 722 if ((addrs->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 723 syslog(LOG_ERR, "socket(UDP): %m"); 724 return (SNMP_ERR_RES_UNAVAIL); 725 } 726 727 (void)shutdown(addrs->socket, SHUT_RD); 728 sa.sin_len = sizeof(sa); 729 sa.sin_family = AF_INET; 730 731 sa.sin_addr.s_addr = htonl((addrs->address[0] << 24) | 732 (addrs->address[1] << 16) | (addrs->address[2] << 8) | 733 (addrs->address[3] << 0)); 734 sa.sin_port = htons(addrs->address[4]) << 8 | 735 htons(addrs->address[5]) << 0; 736 737 if (connect(addrs->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { 738 syslog(LOG_ERR, "connect(%s,%u): %m", 739 inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); 740 (void)close(addrs->socket); 741 return (SNMP_ERR_GENERR); 742 } 743 744 addrs->status = RowStatus_active; 745 746 return (SNMP_ERR_NOERROR); 747} 748 749int 750target_delete_address(struct target_address *addrs) 751{ 752 SLIST_REMOVE(&target_addresslist, addrs, target_address, ta); 753 if (addrs->status == RowStatus_active) 754 close(addrs->socket); 755 free(addrs); 756 757 return (0); 758} 759 760struct target_param * 761target_first_param(void) 762{ 763 return (SLIST_FIRST(&target_paramlist)); 764} 765 766struct target_param * 767target_next_param(struct target_param *param) 768{ 769 if (param == NULL) 770 return (NULL); 771 772 return (SLIST_NEXT(param, tp)); 773} 774 775struct target_param * 776target_new_param(char *pname) 777{ 778 int cmp; 779 struct target_param *param, *temp, *prev; 780 781 SLIST_FOREACH(param, &target_paramlist, tp) 782 if (strcmp(pname, param->name) == 0) 783 return (NULL); 784 785 if ((param = (struct target_param *)malloc(sizeof(*param))) == NULL) 786 return (NULL); 787 788 memset(param, 0, sizeof(*param)); 789 strlcpy(param->name, pname, sizeof(param->name)); 790 791 if ((prev = SLIST_FIRST(&target_paramlist)) == NULL || 792 strcmp(pname, prev->name) < 0) { 793 SLIST_INSERT_HEAD(&target_paramlist, param, tp); 794 return (param); 795 } 796 797 SLIST_FOREACH(temp, &target_paramlist, tp) { 798 if ((cmp = strcmp(pname, temp->name)) <= 0) 799 break; 800 prev = temp; 801 } 802 803 if (temp == NULL || cmp < 0) 804 SLIST_INSERT_AFTER(prev, param, tp); 805 else if (cmp > 0) 806 SLIST_INSERT_AFTER(temp, param, tp); 807 else { 808 syslog(LOG_ERR, "Target parameter %s exists", param->name); 809 free(param); 810 return (NULL); 811 } 812 813 return (param); 814} 815 816int 817target_delete_param(struct target_param *param) 818{ 819 SLIST_REMOVE(&target_paramlist, param, target_param, tp); 820 free(param); 821 822 return (0); 823} 824 825struct target_notify * 826target_first_notify(void) 827{ 828 return (SLIST_FIRST(&target_notifylist)); 829} 830 831struct target_notify * 832target_next_notify(struct target_notify *notify) 833{ 834 if (notify == NULL) 835 return (NULL); 836 837 return (SLIST_NEXT(notify, tn)); 838} 839 840struct target_notify * 841target_new_notify(char *nname) 842{ 843 int cmp; 844 struct target_notify *notify, *temp, *prev; 845 846 SLIST_FOREACH(notify, &target_notifylist, tn) 847 if (strcmp(nname, notify->name) == 0) 848 return (NULL); 849 850 if ((notify = (struct target_notify *)malloc(sizeof(*notify))) == NULL) 851 return (NULL); 852 853 memset(notify, 0, sizeof(*notify)); 854 strlcpy(notify->name, nname, sizeof(notify->name)); 855 856 if ((prev = SLIST_FIRST(&target_notifylist)) == NULL || 857 strcmp(nname, prev->name) < 0) { 858 SLIST_INSERT_HEAD(&target_notifylist, notify, tn); 859 return (notify); 860 } 861 862 SLIST_FOREACH(temp, &target_notifylist, tn) { 863 if ((cmp = strcmp(nname, temp->name)) <= 0) 864 break; 865 prev = temp; 866 } 867 868 if (temp == NULL || cmp < 0) 869 SLIST_INSERT_AFTER(prev, notify, tn); 870 else if (cmp > 0) 871 SLIST_INSERT_AFTER(temp, notify, tn); 872 else { 873 syslog(LOG_ERR, "Notification target %s exists", notify->name); 874 free(notify); 875 return (NULL); 876 } 877 878 return (notify); 879} 880 881int 882target_delete_notify(struct target_notify *notify) 883{ 884 SLIST_REMOVE(&target_notifylist, notify, target_notify, tn); 885 free(notify); 886 887 return (0); 888} 889 890void 891target_flush_all(void) 892{ 893 struct target_address *addrs; 894 struct target_param *param; 895 struct target_notify *notify; 896 897 while ((addrs = SLIST_FIRST(&target_addresslist)) != NULL) { 898 SLIST_REMOVE_HEAD(&target_addresslist, ta); 899 if (addrs->status == RowStatus_active) 900 close(addrs->socket); 901 free(addrs); 902 } 903 SLIST_INIT(&target_addresslist); 904 905 while ((param = SLIST_FIRST(&target_paramlist)) != NULL) { 906 SLIST_REMOVE_HEAD(&target_paramlist, tp); 907 free(param); 908 } 909 SLIST_INIT(&target_paramlist); 910 911 while ((notify = SLIST_FIRST(&target_notifylist)) != NULL) { 912 SLIST_REMOVE_HEAD(&target_notifylist, tn); 913 free(notify); 914 } 915 SLIST_INIT(&target_notifylist); 916} |
|