| /* |
| *Copyright(c)2004,Cisco URP imburses and Network Information Center in Beijing University of Posts and Telecommunications researches. |
| * |
| *All right reserved |
| * |
| *File Name:pingCtlTable.c |
| *File Description:Rows of the pingCtlTable MIB add , delete and read.Rows of lookupResultsTable |
| * MIB add and delete.Rows of pingProbeHistoryTable MIB add and delete. |
| * The main function is also here. |
| * |
| *Current Version:1.0 |
| *Author:ChenJing |
| *Date:2004.8.20 |
| */ |
| |
| /* |
| * This should always be included first before anything else |
| */ |
| |
| #include <net-snmp/net-snmp-config.h> |
| #include <net-snmp/net-snmp-includes.h> |
| #include <net-snmp/agent/net-snmp-agent-includes.h> |
| |
| #if HAVE_STDLIB_H |
| #include <stdlib.h> |
| #endif |
| #if HAVE_STRING_H |
| #include <string.h> |
| #else |
| #include <strings.h> |
| #endif |
| #ifdef HAVE_LIMITS_H |
| #include <limits.h> |
| #endif |
| |
| #include <netdb.h> |
| #include <netinet/in.h> |
| |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| #include <arpa/inet.h> |
| |
| #include "pingCtlTable.h" |
| #include "pingResultsTable.h" |
| #include "pingProbeHistoryTable.h" |
| #include "header_complex.h" |
| |
| static inline void tvsub(struct timeval *, struct timeval *); |
| static inline int schedule_exit(int, int *, long *, long *, long *, long *); |
| static inline int in_flight(__u16 *, long *, long *, long *); |
| static inline void acknowledge(__u16, __u16 *, long *, int *); |
| static inline void advance_ntransmitted(__u16 *, long *); |
| static inline void update_interval(int, int, int *, int *); |
| static long llsqrt(long long); |
| static __inline__ int ipv6_addr_any(struct in6_addr *); |
| static char *pr_addr(struct in6_addr *, int); |
| static char *pr_addr_n(struct in6_addr *); |
| |
| /* |
| *pingCtlTable_variables_oid: |
| * |
| */ |
| |
| |
| oid pingCtlTable_variables_oid[] = |
| { 1, 3, 6, 1, 2, 1, 80, 1, 2 }; |
| |
| /* trap */ |
| oid pingProbeFailed[] = { 1, 3, 6, 1, 2, 1, 80, 0, 1 }; |
| oid pingTestFailed[] = { 1, 3, 6, 1, 2, 1, 80, 0, 2 }; |
| oid pingTestCompleted[] = { 1, 3, 6, 1, 2, 1, 80, 0, 3 }; |
| |
| |
| struct variable2 pingCtlTable_variables[] = { |
| /* |
| * magic number , variable type , ro/rw , callback fn , L, oidsuffix |
| */ |
| {COLUMN_PINGCTLTARGETADDRESSTYPE, ASN_INTEGER, RWRITE, var_pingCtlTable, 2, {1, 3}}, |
| {COLUMN_PINGCTLTARGETADDRESS, ASN_OCTET_STR, RWRITE, var_pingCtlTable, 2, {1, 4}}, |
| {COLUMN_PINGCTLDATASIZE, ASN_UNSIGNED, RONLY, var_pingCtlTable, 2, {1, 5}}, |
| {COLUMN_PINGCTLTIMEOUT, ASN_UNSIGNED, RONLY, var_pingCtlTable, 2, {1, 6}}, |
| {COLUMN_PINGCTLPROBECOUNT, ASN_UNSIGNED, RONLY, var_pingCtlTable, 2, {1, 7}}, |
| {COLUMN_PINGCTLADMINSTATUS, ASN_INTEGER, RWRITE, var_pingCtlTable, 2, {1, 8}}, |
| {COLUMN_PINGCTLDATAFILL, ASN_OCTET_STR, RWRITE, var_pingCtlTable, 2, {1, 9}}, |
| {COLUMN_PINGCTLFREQUENCY, ASN_UNSIGNED, RWRITE, var_pingCtlTable, 2, {1, 10}}, |
| {COLUMN_PINGCTLMAXROWS, ASN_UNSIGNED, RWRITE, var_pingCtlTable, 2, {1, 11}}, |
| {COLUMN_PINGCTLSTORAGETYPE, ASN_INTEGER, RWRITE, var_pingCtlTable, 2, {1, 12}}, |
| {COLUMN_PINGCTLTRAPGENERATION, ASN_OCTET_STR, RWRITE, var_pingCtlTable, 2, {1, 13}}, |
| {COLUMN_PINGCTLTRAPPROBEFAILUREFILTER, ASN_UNSIGNED, RWRITE, var_pingCtlTable, 2, {1, 14}}, |
| {COLUMN_PINGCTLTRAPTESTFAILUREFILTER, ASN_UNSIGNED, RWRITE, var_pingCtlTable, 2, {1, 15}}, |
| {COLUMN_PINGCTLTYPE, ASN_OBJECT_ID, RWRITE, var_pingCtlTable, 2, {1, 16}}, |
| {COLUMN_PINGCTLDESCR, ASN_OCTET_STR, RWRITE, var_pingCtlTable, 2, {1, 17}}, |
| {COLUMN_PINGCTLSOURCEADDRESSTYPE, ASN_INTEGER, RWRITE, var_pingCtlTable, 2, {1, 18}}, |
| {COLUMN_PINGCTLSOURCEADDRESS, ASN_OCTET_STR, RWRITE, var_pingCtlTable, 2, {1, 19}}, |
| {COLUMN_PINGCTLIFINDEX, ASN_INTEGER, RWRITE, var_pingCtlTable, 2, {1, 20}}, |
| {COLUMN_PINGCTLBYPASSROUTETABLE, ASN_INTEGER, RWRITE, var_pingCtlTable, 2, {1, 21}}, |
| {COLUMN_PINGCTLDSFIELD, ASN_UNSIGNED, RWRITE, var_pingCtlTable, 2, {1, 22}}, |
| {COLUMN_PINGCTLROWSTATUS, ASN_INTEGER, RWRITE, var_pingCtlTable, 2, {1, 23}} |
| }; |
| |
| |
| |
| |
| /* |
| * global storage of our data, saved in and configured by header_complex() |
| */ |
| |
| |
| struct header_complex_index *pingCtlTableStorage = NULL; |
| struct header_complex_index *pingResultsTableStorage = NULL; |
| struct header_complex_index *pingProbeHistoryTableStorage = NULL; |
| |
| void |
| init_pingCtlTable(void) |
| { |
| DEBUGMSGTL(("pingCtlTable", "initializing... ")); |
| /* |
| * register ourselves with the agent to handle our mib tree |
| */ |
| REGISTER_MIB("pingCtlTable", pingCtlTable_variables, variable2, |
| pingCtlTable_variables_oid); |
| |
| |
| /* |
| * register our config handler(s) to deal with registrations |
| */ |
| snmpd_register_config_handler("pingCtlTable", parse_pingCtlTable, |
| NULL, NULL); |
| |
| /* |
| * we need to be called back later to store our data |
| */ |
| snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, |
| store_pingCtlTable, NULL); |
| |
| DEBUGMSGTL(("pingCtlTable", "done.\n")); |
| } |
| |
| struct pingCtlTable_data * |
| create_pingCtlTable_data(void) |
| { |
| struct pingCtlTable_data *StorageNew = NULL; |
| StorageNew = SNMP_MALLOC_STRUCT(pingCtlTable_data); |
| if (StorageNew == NULL) { |
| exit(1); |
| } |
| StorageNew->pingCtlTargetAddressType = 1; |
| StorageNew->pingCtlTargetAddress = strdup(""); |
| StorageNew->pingCtlTargetAddressLen = 0; |
| StorageNew->pingCtlDataSize = 0; |
| StorageNew->pingCtlTimeOut = 3; |
| StorageNew->pingCtlProbeCount = 1; |
| StorageNew->pingCtlAdminStatus = 2; |
| StorageNew->pingCtlDataFill = (char *) malloc(strlen("00") + 1); |
| if (StorageNew->pingCtlDataFill == NULL) { |
| exit(1); |
| } |
| memcpy(StorageNew->pingCtlDataFill, "00", strlen("00") + 1); |
| StorageNew->pingCtlDataFill[strlen("00")] = '\0'; |
| StorageNew->pingCtlDataFillLen = strlen(StorageNew->pingCtlDataFill); |
| StorageNew->pingCtlFrequency = 0; |
| StorageNew->pingCtlMaxRows = 50; |
| StorageNew->pingCtlStorageType = 1; |
| StorageNew->pingCtlTrapGeneration = strdup(""); |
| StorageNew->pingCtlTrapGenerationLen = 0; |
| StorageNew->pingCtlTrapGenerationLen = 0; |
| StorageNew->pingCtlTrapProbeFailureFilter = 1; |
| StorageNew->pingCtlTrapTestFailureFilter = 1; |
| StorageNew->pingCtlType = calloc(1, sizeof(oid) * sizeof(2)); /* 0.0 */ |
| StorageNew->pingCtlTypeLen = 2; |
| StorageNew->pingCtlDescr = strdup(""); |
| StorageNew->pingCtlDescrLen = 0; |
| StorageNew->pingCtlSourceAddressType = 1; |
| StorageNew->pingCtlSourceAddress = strdup(""); |
| StorageNew->pingCtlSourceAddressLen = 0; |
| StorageNew->pingCtlIfIndex = 0; |
| StorageNew->pingCtlByPassRouteTable = 2; |
| StorageNew->pingCtlDSField = 0; |
| StorageNew->pingResults = NULL; |
| StorageNew->pingProbeHis = NULL; |
| |
| StorageNew->storageType = ST_NONVOLATILE; |
| StorageNew->pingProbeHistoryMaxIndex = 0; |
| return StorageNew; |
| } |
| |
| /* |
| * pingCtlTable_add(): adds a structure node to our data set |
| */ |
| int |
| pingCtlTable_add(struct pingCtlTable_data *thedata) |
| { |
| netsnmp_variable_list *vars = NULL; |
| |
| |
| DEBUGMSGTL(("pingCtlTable", "adding data... ")); |
| /* |
| * add the index variables to the varbind list, which is |
| * used by header_complex to index the data |
| */ |
| |
| |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) thedata->pingCtlOwnerIndex, thedata->pingCtlOwnerIndexLen); /* pingCtlOwnerIndex */ |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) thedata->pingCtlTestName, thedata->pingCtlTestNameLen); /* pingCtlOperationName */ |
| |
| |
| header_complex_add_data(&pingCtlTableStorage, vars, thedata); |
| |
| DEBUGMSGTL(("pingCtlTable", "registered an entry\n")); |
| vars = NULL; |
| DEBUGMSGTL(("pingCtlTable", "done.\n")); |
| return SNMPERR_SUCCESS; |
| } |
| |
| int |
| pingResultsTable_add(struct pingCtlTable_data *thedata) |
| { |
| netsnmp_variable_list *vars_list = NULL; |
| struct pingResultsTable_data *p = NULL; |
| p = thedata->pingResults; |
| if (thedata->pingResults != NULL) { |
| |
| snmp_varlist_add_variable(&vars_list, NULL, 0, ASN_OCTET_STR, (char *) p->pingCtlOwnerIndex, p->pingCtlOwnerIndexLen); /* pingCtlOwnerIndex */ |
| snmp_varlist_add_variable(&vars_list, NULL, 0, ASN_OCTET_STR, (char *) p->pingCtlTestName, p->pingCtlTestNameLen); /* pingCtlOperationName */ |
| |
| /* |
| * XXX: fill in default row values here into StorageNew |
| * |
| */ |
| |
| |
| DEBUGMSGTL(("pingResultsTable", "adding data... ")); |
| /* |
| * add the index variables to the varbind list, which is |
| * used by header_complex to index the data |
| */ |
| |
| header_complex_add_data(&pingResultsTableStorage, vars_list, p); |
| |
| DEBUGMSGTL(("pingResultsTable", "out finished\n")); |
| |
| } |
| |
| DEBUGMSGTL(("pingResultsTable", "done.\n")); |
| vars_list = NULL; |
| return SNMPERR_SUCCESS; |
| } |
| |
| |
| int |
| pingProbeHistoryTable_add(struct pingProbeHistoryTable_data *thedata) |
| { |
| netsnmp_variable_list *vars_list; |
| vars_list = NULL; |
| if (thedata != NULL) { |
| snmp_varlist_add_variable(&vars_list, NULL, 0, ASN_OCTET_STR, (char *) thedata->pingCtlOwnerIndex, thedata->pingCtlOwnerIndexLen); /* pingCtlOwnerIndex */ |
| snmp_varlist_add_variable(&vars_list, NULL, 0, ASN_OCTET_STR, (char *) thedata->pingCtlTestName, thedata->pingCtlTestNameLen); /* pingCtlTestName */ |
| snmp_varlist_add_variable(&vars_list, NULL, 0, ASN_UNSIGNED, (char *) &thedata->pingProbeHistoryIndex, sizeof(thedata->pingProbeHistoryIndex)); /* pingProbeHistoryIndex */ |
| |
| /* |
| * XXX: fill in default row values here into StorageNew |
| * |
| */ |
| |
| |
| DEBUGMSGTL(("pingProbeHistoryTable", "adding data... ")); |
| /* |
| * add the index variables to the varbind list, which is |
| * used by header_complex to index the data |
| */ |
| |
| header_complex_add_data(&pingProbeHistoryTableStorage, vars_list, |
| thedata); |
| DEBUGMSGTL(("pingProbeHistoryTable", "out finished\n")); |
| } |
| |
| vars_list = NULL; |
| DEBUGMSGTL(("pingProbeHistoryTable", "done.\n")); |
| return SNMPERR_SUCCESS; |
| } |
| |
| int |
| pingProbeHistoryTable_addall(struct pingCtlTable_data *thedata) |
| { |
| netsnmp_variable_list *vars_list = NULL; |
| struct pingProbeHistoryTable_data *p = NULL; |
| p = thedata->pingProbeHis; |
| if (thedata->pingProbeHis != NULL) |
| do { |
| snmp_varlist_add_variable(&vars_list, NULL, 0, ASN_OCTET_STR, (char *) p->pingCtlOwnerIndex, p->pingCtlOwnerIndexLen); /* pingCtlOwnerIndex */ |
| snmp_varlist_add_variable(&vars_list, NULL, 0, ASN_OCTET_STR, (char *) p->pingCtlTestName, p->pingCtlTestNameLen); /* pingCtlTestName */ |
| snmp_varlist_add_variable(&vars_list, NULL, 0, ASN_UNSIGNED, (char *) &p->pingProbeHistoryIndex, sizeof(p->pingProbeHistoryIndex)); /* pingProbeHistoryIndex */ |
| |
| /* |
| * XXX: fill in default row values here into StorageNew |
| * |
| */ |
| |
| |
| DEBUGMSGTL(("pingProbeHistoryTable", "adding data... ")); |
| /* |
| * add the index variables to the varbind list, which is |
| * used by header_complex to index the data |
| */ |
| |
| header_complex_add_data(&pingProbeHistoryTableStorage, |
| vars_list, p); |
| |
| |
| DEBUGMSGTL(("pingProbeHistoryTable", "out finished\n")); |
| vars_list = NULL; |
| p = p->next; |
| } while (p != NULL); |
| |
| DEBUGMSGTL(("pingProbeHistoryTable", "done.\n")); |
| return SNMPERR_SUCCESS; |
| } |
| |
| void |
| pingCtlTable_cleaner(struct header_complex_index *thestuff) |
| { |
| struct header_complex_index *hciptr; |
| |
| DEBUGMSGTL(("pingProbeHistoryTable", "cleanerout ")); |
| for (hciptr = thestuff; hciptr != NULL; hciptr = hciptr->next) { |
| header_complex_extract_entry(&pingCtlTableStorage, hciptr); |
| DEBUGMSGTL(("pingProbeHistoryTable", "cleaner ")); |
| } |
| } |
| |
| /* |
| * parse_mteObjectsTable(): |
| * parses .conf file entries needed to configure the mib. |
| */ |
| void |
| parse_pingCtlTable(const char *token, char *line) |
| { |
| size_t tmpint; |
| struct pingCtlTable_data *StorageTmp = |
| SNMP_MALLOC_STRUCT(pingCtlTable_data); |
| |
| DEBUGMSGTL(("pingCtlTable", "parsing config... ")); |
| |
| |
| if (StorageTmp == NULL) { |
| config_perror("malloc failure"); |
| return; |
| } |
| |
| |
| line = |
| read_config_read_data(ASN_OCTET_STR, line, |
| &StorageTmp->pingCtlOwnerIndex, |
| &StorageTmp->pingCtlOwnerIndexLen); |
| if (StorageTmp->pingCtlOwnerIndex == NULL) { |
| config_perror("invalid specification for pingCtlOwnerIndex"); |
| return; |
| } |
| |
| line = |
| read_config_read_data(ASN_OCTET_STR, line, |
| &StorageTmp->pingCtlTestName, |
| &StorageTmp->pingCtlTestNameLen); |
| if (StorageTmp->pingCtlTestName == NULL) { |
| config_perror("invalid specification for pingCtlTestName"); |
| return; |
| } |
| |
| line = |
| read_config_read_data(ASN_INTEGER, line, |
| &StorageTmp->pingCtlTargetAddressType, |
| &tmpint); |
| |
| line = |
| read_config_read_data(ASN_OCTET_STR, line, |
| &StorageTmp->pingCtlTargetAddress, |
| &StorageTmp->pingCtlTargetAddressLen); |
| if (StorageTmp->pingCtlTargetAddress == NULL) { |
| config_perror("invalid specification for pingCtlTargetAddress"); |
| return; |
| } |
| |
| line = |
| read_config_read_data(ASN_UNSIGNED, line, |
| &StorageTmp->pingCtlDataSize, &tmpint); |
| |
| line = |
| read_config_read_data(ASN_UNSIGNED, line, |
| &StorageTmp->pingCtlTimeOut, &tmpint); |
| |
| line = |
| read_config_read_data(ASN_UNSIGNED, line, |
| &StorageTmp->pingCtlProbeCount, &tmpint); |
| |
| line = |
| read_config_read_data(ASN_INTEGER, line, |
| &StorageTmp->pingCtlAdminStatus, &tmpint); |
| |
| line = |
| read_config_read_data(ASN_OCTET_STR, line, |
| &StorageTmp->pingCtlDataFill, |
| &StorageTmp->pingCtlDataFillLen); |
| if (StorageTmp->pingCtlDataFill == NULL) { |
| config_perror("invalid specification for pingCtlDataFill"); |
| return; |
| } |
| |
| line = |
| read_config_read_data(ASN_UNSIGNED, line, |
| &StorageTmp->pingCtlFrequency, &tmpint); |
| |
| line = |
| read_config_read_data(ASN_UNSIGNED, line, |
| &StorageTmp->pingCtlMaxRows, &tmpint); |
| |
| line = |
| read_config_read_data(ASN_INTEGER, line, |
| &StorageTmp->pingCtlStorageType, &tmpint); |
| |
| line = |
| read_config_read_data(ASN_OCTET_STR, line, |
| &StorageTmp->pingCtlTrapGeneration, |
| &StorageTmp->pingCtlTrapGenerationLen); |
| if (StorageTmp->pingCtlTrapGeneration == NULL) { |
| config_perror("invalid specification for pingCtlTrapGeneration"); |
| return; |
| } |
| |
| line = |
| read_config_read_data(ASN_UNSIGNED, line, |
| &StorageTmp->pingCtlTrapProbeFailureFilter, |
| &tmpint); |
| |
| line = |
| read_config_read_data(ASN_UNSIGNED, line, |
| &StorageTmp->pingCtlTrapTestFailureFilter, |
| &tmpint); |
| |
| line = |
| read_config_read_data(ASN_OBJECT_ID, line, |
| &StorageTmp->pingCtlType, |
| &StorageTmp->pingCtlTypeLen); |
| if (StorageTmp->pingCtlType == NULL) { |
| config_perror("invalid specification for pingCtlType"); |
| return; |
| } |
| |
| line = |
| read_config_read_data(ASN_OCTET_STR, line, |
| &StorageTmp->pingCtlDescr, |
| &StorageTmp->pingCtlDescrLen); |
| if (StorageTmp->pingCtlDescr == NULL) { |
| config_perror("invalid specification for pingCtlTrapDescr"); |
| return; |
| } |
| |
| line = |
| read_config_read_data(ASN_INTEGER, line, |
| &StorageTmp->pingCtlSourceAddressType, |
| &tmpint); |
| |
| line = |
| read_config_read_data(ASN_OCTET_STR, line, |
| &StorageTmp->pingCtlSourceAddress, |
| &StorageTmp->pingCtlSourceAddressLen); |
| if (StorageTmp->pingCtlSourceAddress == NULL) { |
| config_perror("invalid specification for pingCtlSourceAddress"); |
| return; |
| } |
| |
| line = |
| read_config_read_data(ASN_INTEGER, line, |
| &StorageTmp->pingCtlIfIndex, &tmpint); |
| |
| line = |
| read_config_read_data(ASN_INTEGER, line, |
| &StorageTmp->pingCtlByPassRouteTable, |
| &tmpint); |
| |
| line = |
| read_config_read_data(ASN_UNSIGNED, line, |
| &StorageTmp->pingCtlDSField, &tmpint); |
| |
| line = |
| read_config_read_data(ASN_INTEGER, line, |
| &StorageTmp->pingCtlRowStatus, &tmpint); |
| |
| line = |
| read_config_read_data(ASN_UNSIGNED, line, |
| &StorageTmp->pingProbeHistoryMaxIndex, |
| &tmpint); |
| |
| StorageTmp->storageType = ST_NONVOLATILE; |
| pingCtlTable_add(StorageTmp); |
| /* pingCtlTable_cleaner(pingCtlTableStorage); */ |
| |
| DEBUGMSGTL(("pingCtlTable", "done.\n")); |
| } |
| |
| |
| |
| /* |
| * store_pingCtlTable(): |
| * stores .conf file entries needed to configure the mib. |
| */ |
| int |
| store_pingCtlTable(int majorID, int minorID, void *serverarg, |
| void *clientarg) |
| { |
| char line[SNMP_MAXBUF]; |
| char *cptr = NULL; |
| size_t tmpint; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| struct header_complex_index *hcindex = NULL; |
| |
| |
| DEBUGMSGTL(("pingCtlTable", "storing data... ")); |
| |
| |
| for (hcindex = pingCtlTableStorage; hcindex != NULL; |
| hcindex = hcindex->next) { |
| StorageTmp = (struct pingCtlTable_data *) hcindex->data; |
| |
| if (StorageTmp->storageType != ST_READONLY) { |
| memset(line, 0, sizeof(line)); |
| strcat(line, "pingCtlTable "); |
| cptr = line + strlen(line); |
| |
| |
| cptr = |
| read_config_store_data(ASN_OCTET_STR, cptr, |
| &StorageTmp->pingCtlOwnerIndex, |
| &StorageTmp->pingCtlOwnerIndexLen); |
| cptr = |
| read_config_store_data(ASN_OCTET_STR, cptr, |
| &StorageTmp->pingCtlTestName, |
| &StorageTmp->pingCtlTestNameLen); |
| cptr = |
| read_config_store_data(ASN_INTEGER, cptr, |
| &StorageTmp-> |
| pingCtlTargetAddressType, &tmpint); |
| cptr = |
| read_config_store_data(ASN_OCTET_STR, cptr, |
| &StorageTmp->pingCtlTargetAddress, |
| &StorageTmp-> |
| pingCtlTargetAddressLen); |
| cptr = |
| read_config_store_data(ASN_UNSIGNED, cptr, |
| &StorageTmp->pingCtlDataSize, |
| &tmpint); |
| cptr = |
| read_config_store_data(ASN_UNSIGNED, cptr, |
| &StorageTmp->pingCtlTimeOut, |
| &tmpint); |
| cptr = |
| read_config_store_data(ASN_UNSIGNED, cptr, |
| &StorageTmp->pingCtlProbeCount, |
| &tmpint); |
| |
| cptr = |
| read_config_store_data(ASN_INTEGER, cptr, |
| &StorageTmp->pingCtlAdminStatus, |
| &tmpint); |
| cptr = |
| read_config_store_data(ASN_OCTET_STR, cptr, |
| &StorageTmp->pingCtlDataFill, |
| &StorageTmp->pingCtlDataFillLen); |
| |
| cptr = |
| read_config_store_data(ASN_UNSIGNED, cptr, |
| &StorageTmp->pingCtlFrequency, |
| &tmpint); |
| cptr = |
| read_config_store_data(ASN_UNSIGNED, cptr, |
| &StorageTmp->pingCtlMaxRows, |
| &tmpint); |
| |
| cptr = |
| read_config_store_data(ASN_INTEGER, cptr, |
| &StorageTmp->pingCtlStorageType, |
| &tmpint); |
| cptr = |
| read_config_store_data(ASN_OCTET_STR, cptr, |
| &StorageTmp->pingCtlTrapGeneration, |
| &StorageTmp-> |
| pingCtlTrapGenerationLen); |
| cptr = |
| read_config_store_data(ASN_UNSIGNED, cptr, |
| &StorageTmp-> |
| pingCtlTrapProbeFailureFilter, |
| &tmpint); |
| cptr = |
| read_config_store_data(ASN_UNSIGNED, cptr, |
| &StorageTmp-> |
| pingCtlTrapTestFailureFilter, |
| &tmpint); |
| cptr = |
| read_config_store_data(ASN_OBJECT_ID, cptr, |
| &StorageTmp->pingCtlType, |
| &StorageTmp->pingCtlTypeLen); |
| cptr = |
| read_config_store_data(ASN_OCTET_STR, cptr, |
| &StorageTmp->pingCtlDescr, |
| &StorageTmp->pingCtlDescrLen); |
| cptr = |
| read_config_store_data(ASN_INTEGER, cptr, |
| &StorageTmp-> |
| pingCtlSourceAddressType, &tmpint); |
| cptr = |
| read_config_store_data(ASN_OCTET_STR, cptr, |
| &StorageTmp->pingCtlSourceAddress, |
| &StorageTmp-> |
| pingCtlSourceAddressLen); |
| cptr = |
| read_config_store_data(ASN_INTEGER, cptr, |
| &StorageTmp->pingCtlIfIndex, |
| &tmpint); |
| cptr = |
| read_config_store_data(ASN_INTEGER, cptr, |
| &StorageTmp-> |
| pingCtlByPassRouteTable, &tmpint); |
| cptr = |
| read_config_store_data(ASN_UNSIGNED, cptr, |
| &StorageTmp->pingCtlDSField, |
| &tmpint); |
| |
| if (StorageTmp->pingCtlRowStatus == RS_ACTIVE) |
| StorageTmp->pingCtlRowStatus = RS_NOTINSERVICE; |
| |
| cptr = |
| read_config_store_data(ASN_INTEGER, cptr, |
| &StorageTmp->pingCtlRowStatus, |
| &tmpint); |
| cptr = |
| read_config_store_data(ASN_UNSIGNED, cptr, |
| &StorageTmp-> |
| pingProbeHistoryMaxIndex, &tmpint); |
| |
| |
| |
| snmpd_store_config(line); |
| } |
| } |
| DEBUGMSGTL(("pingCtlTable", "done.\n")); |
| return SNMPERR_SUCCESS; |
| } |
| |
| |
| /* |
| * var_pingCtlTable(): |
| * Handle this table separately from the scalar value case. |
| * The workings of this are basically the same as for var_mteObjectsTable above. |
| */ |
| unsigned char * |
| var_pingCtlTable(struct variable *vp, |
| oid * name, |
| size_t *length, |
| int exact, size_t *var_len, WriteMethod ** write_method) |
| { |
| |
| |
| struct pingCtlTable_data *StorageTmp = NULL; |
| |
| /* |
| * this assumes you have registered all your data properly |
| */ |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, vp, name, length, exact, |
| var_len, write_method)) == NULL) { |
| if (vp->magic == COLUMN_PINGCTLROWSTATUS) |
| *write_method = write_pingCtlRowStatus; |
| return NULL; |
| } |
| |
| /* |
| * this is where we do the value assignments for the mib results. |
| */ |
| switch (vp->magic) { |
| |
| |
| case COLUMN_PINGCTLTARGETADDRESSTYPE: |
| *write_method = write_pingCtlTargetAddressType; |
| *var_len = sizeof(StorageTmp->pingCtlTargetAddressType); |
| return (u_char *) & StorageTmp->pingCtlTargetAddressType; |
| |
| case COLUMN_PINGCTLTARGETADDRESS: |
| *write_method = write_pingCtlTargetAddress; |
| *var_len = (StorageTmp->pingCtlTargetAddressLen); |
| |
| return (u_char *) StorageTmp->pingCtlTargetAddress; |
| |
| case COLUMN_PINGCTLDATASIZE: |
| *write_method = write_pingCtlDataSize; |
| *var_len = sizeof(StorageTmp->pingCtlDataSize); |
| |
| return (u_char *) & StorageTmp->pingCtlDataSize; |
| |
| case COLUMN_PINGCTLTIMEOUT: |
| *write_method = write_pingCtlTimeOut; |
| *var_len = sizeof(StorageTmp->pingCtlTimeOut); |
| |
| return (u_char *) & StorageTmp->pingCtlTimeOut; |
| |
| case COLUMN_PINGCTLPROBECOUNT: |
| *write_method = write_pingCtlProbeCount; |
| *var_len = sizeof(StorageTmp->pingCtlProbeCount); |
| |
| return (u_char *) & StorageTmp->pingCtlProbeCount; |
| |
| case COLUMN_PINGCTLADMINSTATUS: |
| *write_method = write_pingCtlAdminStatus; |
| *var_len = sizeof(StorageTmp->pingCtlAdminStatus); |
| |
| return (u_char *) & StorageTmp->pingCtlAdminStatus; |
| |
| case COLUMN_PINGCTLDATAFILL: |
| *write_method = write_pingCtlDataFill; |
| *var_len = (StorageTmp->pingCtlDataFillLen); |
| |
| return (u_char *) StorageTmp->pingCtlDataFill; |
| |
| case COLUMN_PINGCTLFREQUENCY: |
| *write_method = write_pingCtlFrequency; |
| *var_len = sizeof(StorageTmp->pingCtlFrequency); |
| |
| return (u_char *) & StorageTmp->pingCtlFrequency; |
| |
| case COLUMN_PINGCTLMAXROWS: |
| *write_method = write_pingCtlMaxRows; |
| *var_len = sizeof(StorageTmp->pingCtlMaxRows); |
| |
| return (u_char *) & StorageTmp->pingCtlMaxRows; |
| |
| case COLUMN_PINGCTLSTORAGETYPE: |
| *write_method = write_pingCtlStorageType; |
| *var_len = sizeof(StorageTmp->pingCtlStorageType); |
| |
| return (u_char *) & StorageTmp->pingCtlStorageType; |
| |
| case COLUMN_PINGCTLTRAPGENERATION: |
| *write_method = write_pingCtlTrapGeneration; |
| *var_len = (StorageTmp->pingCtlTrapGenerationLen); |
| |
| return (u_char *) StorageTmp->pingCtlTrapGeneration; |
| |
| case COLUMN_PINGCTLTRAPPROBEFAILUREFILTER: |
| *write_method = write_pingCtlTrapProbeFailureFilter; |
| *var_len = sizeof(StorageTmp->pingCtlTrapProbeFailureFilter); |
| |
| return (u_char *) & StorageTmp->pingCtlTrapProbeFailureFilter; |
| |
| case COLUMN_PINGCTLTRAPTESTFAILUREFILTER: |
| *write_method = write_pingCtlTrapTestFailureFilter; |
| *var_len = sizeof(StorageTmp->pingCtlTrapTestFailureFilter); |
| |
| return (u_char *) & StorageTmp->pingCtlTrapTestFailureFilter; |
| |
| case COLUMN_PINGCTLTYPE: |
| *write_method = write_pingCtlType; |
| *var_len = (StorageTmp->pingCtlTypeLen) * sizeof(oid); |
| |
| return (u_char *) StorageTmp->pingCtlType; |
| |
| case COLUMN_PINGCTLDESCR: |
| *write_method = write_pingCtlDescr; |
| *var_len = (StorageTmp->pingCtlDescrLen); |
| |
| return (u_char *) StorageTmp->pingCtlDescr; |
| |
| case COLUMN_PINGCTLSOURCEADDRESSTYPE: |
| *write_method = write_pingCtlSourceAddressType; |
| *var_len = sizeof(StorageTmp->pingCtlSourceAddressType); |
| |
| return (u_char *) & StorageTmp->pingCtlSourceAddressType; |
| |
| case COLUMN_PINGCTLSOURCEADDRESS: |
| *write_method = write_pingCtlSourceAddress; |
| *var_len = (StorageTmp->pingCtlSourceAddressLen); |
| |
| return (u_char *) StorageTmp->pingCtlSourceAddress; |
| |
| case COLUMN_PINGCTLIFINDEX: |
| *write_method = write_pingCtlIfIndex; |
| *var_len = sizeof(StorageTmp->pingCtlIfIndex); |
| |
| return (u_char *) & StorageTmp->pingCtlIfIndex; |
| |
| case COLUMN_PINGCTLBYPASSROUTETABLE: |
| *write_method = write_pingCtlByPassRouteTable; |
| *var_len = sizeof(StorageTmp->pingCtlByPassRouteTable); |
| |
| return (u_char *) & StorageTmp->pingCtlByPassRouteTable; |
| |
| case COLUMN_PINGCTLDSFIELD: |
| *write_method = write_pingCtlDSField; |
| *var_len = sizeof(StorageTmp->pingCtlDSField); |
| |
| return (u_char *) & StorageTmp->pingCtlDSField; |
| |
| |
| |
| case COLUMN_PINGCTLROWSTATUS: |
| *write_method = write_pingCtlRowStatus; |
| *var_len = sizeof(StorageTmp->pingCtlRowStatus); |
| |
| return (u_char *) & StorageTmp->pingCtlRowStatus; |
| |
| default: |
| ERROR_MSG(""); |
| } |
| return NULL; |
| } |
| |
| |
| unsigned long |
| pingProbeHistoryTable_count(struct pingCtlTable_data *thedata) |
| { |
| struct header_complex_index *hciptr2 = NULL; |
| netsnmp_variable_list *vars = NULL; |
| oid newoid[MAX_OID_LEN]; |
| size_t newoid_len; |
| unsigned long count = 0; |
| |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) thedata->pingCtlOwnerIndex, thedata->pingCtlOwnerIndexLen); /* pingCtlOwnerIndex */ |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) thedata->pingCtlTestName, thedata->pingCtlTestNameLen); /* pingCtlOperationName */ |
| |
| header_complex_generate_oid(newoid, &newoid_len, NULL, 0, vars); |
| |
| for (hciptr2 = pingProbeHistoryTableStorage; hciptr2 != NULL; |
| hciptr2 = hciptr2->next) { |
| if (snmp_oid_compare(newoid, newoid_len, hciptr2->name, newoid_len) |
| == 0) { |
| count = count + 1; |
| } |
| } |
| return count; |
| } |
| |
| |
| void |
| pingProbeHistoryTable_delLast(struct pingCtlTable_data *thedata) |
| { |
| struct header_complex_index *hciptr2 = NULL; |
| struct header_complex_index *hcilast = NULL; |
| struct pingProbeHistoryTable_data *StorageTmp = NULL; |
| netsnmp_variable_list *vars = NULL; |
| oid newoid[MAX_OID_LEN]; |
| size_t newoid_len; |
| time_t last_time = 2147483647; |
| time_t tp; |
| |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) thedata->pingCtlOwnerIndex, thedata->pingCtlOwnerIndexLen); /* pingCtlOwnerIndex */ |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) thedata->pingCtlTestName, thedata->pingCtlTestNameLen); /* pingCtlOperationName */ |
| |
| header_complex_generate_oid(newoid, &newoid_len, NULL, 0, vars); |
| |
| for (hcilast = hciptr2 = pingProbeHistoryTableStorage; hciptr2 != NULL; |
| hciptr2 = hciptr2->next) { |
| if (snmp_oid_compare(newoid, newoid_len, hciptr2->name, newoid_len) |
| == 0) { |
| |
| StorageTmp = |
| header_complex_get_from_oid(pingProbeHistoryTableStorage, |
| hciptr2->name, |
| hciptr2->namelen); |
| tp = StorageTmp->pingProbeHistoryTime_time; |
| |
| if (last_time > tp) { |
| last_time = tp; |
| hcilast = hciptr2; |
| } |
| |
| } |
| } |
| header_complex_extract_entry(&pingProbeHistoryTableStorage, hcilast); |
| DEBUGMSGTL(("pingProbeHistoryTable", |
| "delete the last one success!\n")); |
| } |
| |
| |
| char * |
| sock_ntop_host(const struct sockaddr *sa, socklen_t salen) |
| { |
| static char str[128]; /* Unix domain is largest */ |
| |
| switch (sa->sa_family) { |
| case AF_INET:{ |
| const struct sockaddr_in *sin = (const struct sockaddr_in *) sa; |
| |
| if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == |
| NULL) |
| return (NULL); |
| return (str); |
| } |
| |
| #ifdef IPV6 |
| case AF_INET6:{ |
| const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *) sa; |
| |
| if (inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str)) == |
| NULL) |
| return (NULL); |
| return (str); |
| } |
| #endif |
| |
| #ifdef AF_UNIX |
| case AF_UNIX:{ |
| const struct sockaddr_un *unp = (const struct sockaddr_un *) sa; |
| |
| /* |
| * OK to have no pathname bound to the socket: happens on |
| * every connect() unless client calls bind() first. |
| */ |
| if (unp->sun_path[0] == 0) |
| strcpy(str, "(no pathname bound)"); |
| else |
| snprintf(str, sizeof(str), "%s", unp->sun_path); |
| return (str); |
| } |
| #endif |
| |
| #ifdef HAVE_SOCKADDR_DL_STRUCT |
| case AF_LINK:{ |
| struct sockaddr_dl *sdl = (struct sockaddr_dl *) sa; |
| |
| if (sdl->sdl_nlen > 0) |
| snprintf(str, sizeof(str), "%*s", |
| sdl->sdl_nlen, &sdl->sdl_data[0]); |
| else |
| snprintf(str, sizeof(str), "AF_LINK, index=%d", |
| sdl->sdl_index); |
| return (str); |
| } |
| #endif |
| default: |
| snprintf(str, sizeof(str), |
| "sock_ntop_host: unknown AF_xxx: %d, len %d", |
| sa->sa_family, salen); |
| return (str); |
| } |
| return (NULL); |
| } |
| |
| |
| char * |
| Sock_ntop_host(const struct sockaddr *sa, socklen_t salen) |
| { |
| char *ptr; |
| |
| if ((ptr = sock_ntop_host(sa, salen)) == NULL) |
| printf("sock_ntop_host error"); /* inet_ntop() sets errno */ |
| return (ptr); |
| } |
| |
| |
| |
| unsigned short |
| in_cksum(unsigned short *addr, int len) |
| { |
| int nleft = len; |
| int sum = 0; |
| unsigned short *w = addr; |
| unsigned short answer = 0; |
| |
| /* |
| * Our algorithm is simple, using a 32 bit accumulator (sum), we add |
| * sequential 16 bit words to it, and at the end, fold back all the |
| * carry bits from the top 16 bits into the lower 16 bits. |
| */ |
| while (nleft > 1) { |
| sum += *w++; |
| nleft -= 2; |
| } |
| |
| /* |
| * 4mop up an odd byte, if necessary |
| */ |
| if (nleft == 1) { |
| *(unsigned char *) (&answer) = *(unsigned char *) w; |
| sum += answer; |
| } |
| |
| /* |
| * 4add back carry outs from top 16 bits to low 16 bits |
| */ |
| sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ |
| sum += (sum >> 16); /* add carry */ |
| answer = ~sum; /* truncate to 16 bits */ |
| return (answer); |
| } |
| |
| |
| struct addrinfo * |
| host_serv(const char *host, const char *serv, int family, int socktype) |
| { |
| int n; |
| struct addrinfo hints, *res; |
| |
| memset(&hints, '\0', sizeof(struct addrinfo)); |
| hints.ai_flags = AI_CANONNAME; /* always return canonical name */ |
| hints.ai_family = family; /* AF_UNSPEC, AF_INET, AF_INET6, etc. */ |
| hints.ai_socktype = socktype; /* 0, SOCK_STREAM, SOCK_DGRAM, etc. */ |
| |
| if ((n = getaddrinfo(host, serv, &hints, &res)) != 0) |
| return (NULL); |
| |
| return (res); /* return pointer to first on linked list */ |
| } |
| |
| /* |
| * end host_serv |
| */ |
| |
| /* |
| * There is no easy way to pass back the integer return code from |
| * getaddrinfo() in the function above, short of adding another argument |
| * that is a pointer, so the easiest way to provide the wrapper function |
| * is just to duplicate the simple function as we do here. |
| */ |
| |
| struct addrinfo * |
| Host_serv(const char *host, const char *serv, int family, int socktype) |
| { |
| int n; |
| struct addrinfo hints, *res; |
| |
| memset(&hints, '\0', sizeof(struct addrinfo)); |
| hints.ai_flags = AI_CANONNAME; /* always return canonical name */ |
| hints.ai_family = family; /* 0, AF_INET, AF_INET6, etc. */ |
| hints.ai_socktype = socktype; /* 0, SOCK_STREAM, SOCK_DGRAM, etc. */ |
| |
| if ((n = getaddrinfo(host, serv, &hints, &res)) != 0) |
| #if HAVE_GAI_STRERROR |
| printf("host_serv error for %s, %s: %s", |
| (host == NULL) ? "(no hostname)" : host, |
| (serv == NULL) ? "(no service name)" : serv, |
| gai_strerror(n)); |
| #else |
| printf("host_serv error for %s, %s", |
| (host == NULL) ? "(no hostname)" : host, |
| (serv == NULL) ? "(no service name)" : serv); |
| #endif |
| |
| return (res); /* return pointer to first on linked list */ |
| } |
| |
| int |
| readable_timeo(int fd, int sec) |
| { |
| fd_set rset; |
| struct timeval tv; |
| FD_ZERO(&rset); |
| FD_SET(fd, &rset); |
| tv.tv_sec = sec; |
| tv.tv_usec = 0; |
| return (select(fd + 1, &rset, NULL, NULL, &tv)); |
| |
| } |
| |
| /* |
| * send trap |
| */ |
| void |
| send_ping_trap(struct pingCtlTable_data *item, |
| oid * trap_oid, size_t trap_oid_len) |
| { |
| static oid objid_snmptrap[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 }; /* snmpTrapIOD.0 */ |
| struct pingResultsTable_data *StorageTmp = NULL; |
| netsnmp_variable_list *var_list = NULL, *vars = NULL; |
| oid newoid[MAX_OID_LEN]; |
| size_t newoid_len; |
| |
| oid pingCtlTargetAddress[] = |
| { 1, 3, 6, 1, 2, 1, 80, 1, 2, 1, 4 }; |
| oid pingResultsMinRtt[] = |
| { 1, 3, 6, 1, 2, 1, 80, 1, 3, 1, 4 }; |
| oid pingResultsMaxRtt[] = |
| { 1, 3, 6, 1, 2, 1, 80, 1, 3, 1, 5 }; |
| oid pingResultsAverageRtt[] = |
| { 1, 3, 6, 1, 2, 1, 80, 1, 3, 1, 6 }; |
| oid pingResultsProbeResponses[] = |
| { 1, 3, 6, 1, 2, 1, 80, 1, 3, 1, 7 }; |
| oid pingResultsSendProbes[] = |
| { 1, 3, 6, 1, 2, 1, 80, 1, 3, 1, 8 }; |
| |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) item->pingCtlOwnerIndex, item->pingCtlOwnerIndexLen); /* pingCtlOwnerIndex */ |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) item->pingCtlTestName, item->pingCtlTestNameLen); /* pingCtlOperationName */ |
| StorageTmp = SNMP_MALLOC_STRUCT(pingResultsTable_data); |
| if ((StorageTmp = |
| (struct pingResultsTable_data *) |
| header_complex_get(pingResultsTableStorage, vars)) == NULL) |
| return ; |
| |
| /* |
| * snmpTrap oid |
| */ |
| snmp_varlist_add_variable(&var_list, objid_snmptrap, |
| sizeof(objid_snmptrap) / sizeof(oid), |
| ASN_OBJECT_ID, (u_char *) trap_oid, |
| trap_oid_len * sizeof(oid)); |
| /* |
| * pingCtlTargetAddress |
| */ |
| memset(newoid, '\0', MAX_OID_LEN * sizeof(oid)); |
| header_complex_generate_oid(newoid, &newoid_len, pingCtlTargetAddress, |
| sizeof(pingCtlTargetAddress) / sizeof(oid), |
| vars); |
| |
| snmp_varlist_add_variable(&var_list, newoid, |
| newoid_len, |
| ASN_OCTET_STR, |
| (u_char *) item->pingCtlTargetAddress, |
| item->pingCtlTargetAddressLen); |
| |
| /* |
| * pingResultsMinRtt |
| */ |
| memset(newoid, '\0', newoid_len); |
| header_complex_generate_oid(newoid, &newoid_len, pingResultsMinRtt, |
| sizeof(pingResultsMinRtt) / sizeof(oid), |
| vars); |
| |
| snmp_varlist_add_variable(&var_list, newoid, |
| newoid_len, |
| ASN_UNSIGNED, |
| (u_char *) & (StorageTmp->pingResultsMinRtt), |
| sizeof(StorageTmp->pingResultsMinRtt)); |
| /* |
| * pingResultsMaxRtt |
| */ |
| memset(newoid, '\0', newoid_len); |
| header_complex_generate_oid(newoid, &newoid_len, pingResultsMaxRtt, |
| sizeof(pingResultsMaxRtt) / sizeof(oid), |
| vars); |
| |
| snmp_varlist_add_variable(&var_list, newoid, |
| newoid_len, |
| ASN_UNSIGNED, |
| (u_char *) & (StorageTmp->pingResultsMaxRtt), |
| sizeof(StorageTmp->pingResultsMaxRtt)); |
| |
| /* |
| * pingResultsAverageRtt |
| */ |
| memset(newoid, '\0', newoid_len); |
| header_complex_generate_oid(newoid, &newoid_len, pingResultsAverageRtt, |
| sizeof(pingResultsAverageRtt) / |
| sizeof(oid), vars); |
| |
| snmp_varlist_add_variable(&var_list, newoid, |
| newoid_len, |
| ASN_UNSIGNED, |
| (u_char *) & (StorageTmp-> |
| pingResultsAverageRtt), |
| sizeof(StorageTmp->pingResultsAverageRtt)); |
| |
| /* |
| * pingResultsProbeResponses |
| */ |
| memset(newoid, '\0', newoid_len); |
| header_complex_generate_oid(newoid, &newoid_len, |
| pingResultsProbeResponses, |
| sizeof(pingResultsProbeResponses) / |
| sizeof(oid), vars); |
| |
| snmp_varlist_add_variable(&var_list, newoid, |
| newoid_len, |
| ASN_UNSIGNED, |
| (u_char *) & (StorageTmp-> |
| pingResultsProbeResponses), |
| sizeof(StorageTmp-> |
| pingResultsProbeResponses)); |
| /* |
| * pingResultsSendProbes |
| */ |
| memset(newoid, '\0', newoid_len); |
| header_complex_generate_oid(newoid, &newoid_len, pingResultsSendProbes, |
| sizeof(pingResultsSendProbes) / |
| sizeof(oid), vars); |
| |
| snmp_varlist_add_variable(&var_list, newoid, |
| newoid_len, |
| ASN_UNSIGNED, |
| (u_char *) & (StorageTmp-> |
| pingResultsSendProbes), |
| sizeof(StorageTmp->pingResultsSendProbes)); |
| |
| /* |
| * XXX: stuff based on event table |
| */ |
| |
| DEBUGMSG(("pingTest:send_ping_trap", "success!\n")); |
| |
| send_v2trap(var_list); |
| snmp_free_varbind(vars); |
| vars = NULL; |
| snmp_free_varbind(var_list); |
| vars = NULL; |
| } |
| |
| |
| |
| void |
| readloop(struct pingCtlTable_data *item, struct addrinfo *ai, int datalen, |
| unsigned long *minrtt, unsigned long *maxrtt, |
| unsigned long *averagertt, pid_t pid) |
| { |
| char recvbuf[BUFSIZE]; |
| char sendbuf[BUFSIZE]; |
| int nsent = 1; |
| socklen_t len; |
| ssize_t n; |
| struct timeval tval; |
| /* static int loop_num; */ |
| /* struct pingProbeHistoryTable_data * current=NULL; */ |
| struct pingProbeHistoryTable_data current_var; |
| int sockfd; |
| int current_probe_temp; |
| int success_probe = 0; |
| int fail_probe = 0; |
| int flag; |
| unsigned long *sumrtt; |
| struct timeval tv; |
| |
| sumrtt = (unsigned long *) malloc(sizeof(unsigned long)); |
| sockfd = socket(pr->sasend->sa_family, SOCK_RAW, pr->icmpproto); |
| if (sockfd < 0) { |
| snmp_log_perror("pingCtlTable: failed to create socket"); |
| return; |
| } |
| setuid(getuid()); /* don't need special permissions any more */ |
| |
| tv.tv_sec = 5; |
| tv.tv_usec = 0; |
| setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); |
| |
| for (current_probe_temp = 1; |
| current_probe_temp <= item->pingCtlProbeCount; |
| current_probe_temp++) { |
| time_t timep; |
| (*pr->fsend) (datalen, pid, nsent, sockfd, sendbuf); |
| nsent++; |
| len = pr->salen; |
| if (readable_timeo(sockfd, item->pingCtlTimeOut) == 0) { |
| /* printf("socket timeout!\n"); */ |
| n = -1; |
| fail_probe = fail_probe + 1; |
| flag = 1; |
| } else { |
| n = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, pr->sarecv, |
| &len); |
| success_probe = success_probe + 1; |
| flag = 0; |
| } |
| |
| gettimeofday(&tval, NULL); |
| |
| time(&timep); |
| |
| (*pr->fproc) (recvbuf, n, &tval, timep, item, ai, datalen, minrtt, |
| maxrtt, sumrtt, averagertt, current_probe_temp, |
| success_probe, fail_probe, flag, ¤t_var, pid); |
| if (current_probe_temp >= item->pingCtlProbeCount) { |
| SNMP_FREE(sumrtt); |
| return; |
| } |
| } |
| close(sockfd); |
| } |
| |
| unsigned long |
| round_double(double number) |
| { |
| unsigned long ret_num = 0; |
| if (number - (unsigned long) number < 0.5) |
| ret_num = (unsigned long) number; |
| else |
| ret_num = (unsigned long) number + 1; |
| return ret_num; |
| } |
| |
| int |
| proc_v4(char *ptr, ssize_t len, struct timeval *tvrecv, time_t timep, |
| struct pingCtlTable_data *item, struct addrinfo *ai, int datalen, |
| unsigned long *minrtt, unsigned long *maxrtt, |
| unsigned long *sumrtt, unsigned long *averagertt, |
| unsigned long current_probe, int success_probe, int fail_probe, |
| int flag, struct pingProbeHistoryTable_data *current_temp, |
| pid_t pid) |
| { |
| int hlen1 = 0, icmplen = 0; |
| unsigned long rtt = 0; |
| |
| struct ip *ip = NULL; |
| struct icmp *icmp = NULL; |
| struct timeval *tvsend = NULL; |
| struct pingProbeHistoryTable_data *temp = NULL; |
| static int probeFailed = 0; |
| static int testFailed = 0; |
| static int series = 0; |
| |
| netsnmp_variable_list *vars = NULL; |
| struct pingResultsTable_data *StorageNew = NULL; |
| if (flag == 0) { |
| series = 0; |
| ip = (struct ip *) ptr; /* start of IP header */ |
| hlen1 = ip->ip_hl << 2; /* length of IP header */ |
| |
| icmp = (struct icmp *) (ptr + hlen1); /* start of ICMP header */ |
| if ((icmplen = len - hlen1) < 8) |
| printf("icmplen (%d) < 8", icmplen); |
| |
| if (icmp->icmp_type == ICMP_ECHOREPLY) { |
| if (icmp->icmp_id != pid) |
| return SNMP_ERR_NOERROR; /* not a response to our ECHO_REQUEST */ |
| if (icmplen < 16) |
| printf("icmplen (%d) < 16", icmplen); |
| |
| |
| tvsend = (struct timeval *) icmp->icmp_data; |
| |
| rtt = |
| round_double((1000000 * (tvrecv->tv_sec - tvsend->tv_sec) + |
| tvrecv->tv_usec - tvsend->tv_usec) / 1000); |
| |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) item->pingCtlOwnerIndex, item->pingCtlOwnerIndexLen); /* pingCtlOwnerIndex */ |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) item->pingCtlTestName, item->pingCtlTestNameLen); /* pingCtlTestName */ |
| |
| |
| if ((StorageNew = |
| header_complex_get(pingResultsTableStorage, |
| vars)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; |
| |
| if (current_probe == 1) { |
| *averagertt = rtt; |
| *minrtt = rtt; |
| *maxrtt = rtt; |
| *sumrtt = rtt; |
| } else { |
| printf("else\n"); |
| if (rtt < *minrtt) |
| *minrtt = rtt; |
| if (rtt > *maxrtt) |
| *maxrtt = rtt; |
| *sumrtt = (*sumrtt) + rtt; |
| *averagertt = |
| round_double((*sumrtt) / |
| (StorageNew->pingResultsProbeResponses + |
| 1)); |
| } |
| |
| |
| StorageNew->pingResultsMinRtt = *minrtt; |
| StorageNew->pingResultsMaxRtt = *maxrtt; |
| StorageNew->pingResultsAverageRtt = *averagertt; |
| StorageNew->pingResultsProbeResponses = |
| StorageNew->pingResultsProbeResponses + 1; |
| StorageNew->pingResultsSendProbes = |
| StorageNew->pingResultsSendProbes + 1; |
| StorageNew->pingResultsRttSumOfSquares = |
| StorageNew->pingResultsRttSumOfSquares + rtt * rtt; |
| |
| StorageNew->pingResultsLastGoodProbe_time = timep; |
| StorageNew->pingResultsLastGoodProbe = |
| netsnmp_memdup(date_n_time(&timep, |
| &StorageNew->pingResultsLastGoodProbeLen), |
| 11); |
| |
| temp = SNMP_MALLOC_STRUCT(pingProbeHistoryTable_data); |
| |
| temp->pingCtlOwnerIndex = |
| (char *) malloc(item->pingCtlOwnerIndexLen + 1); |
| memcpy(temp->pingCtlOwnerIndex, item->pingCtlOwnerIndex, |
| item->pingCtlOwnerIndexLen + 1); |
| temp->pingCtlOwnerIndex[item->pingCtlOwnerIndexLen] = '\0'; |
| temp->pingCtlOwnerIndexLen = item->pingCtlOwnerIndexLen; |
| |
| temp->pingCtlTestName = |
| (char *) malloc(item->pingCtlTestNameLen + 1); |
| memcpy(temp->pingCtlTestName, item->pingCtlTestName, |
| item->pingCtlTestNameLen + 1); |
| temp->pingCtlTestName[item->pingCtlTestNameLen] = '\0'; |
| temp->pingCtlTestNameLen = item->pingCtlTestNameLen; |
| |
| /* add lock to protect */ |
| pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER; |
| pthread_mutex_lock(&counter_mutex); |
| if (item->pingProbeHistoryMaxIndex >= |
| (unsigned long) (2147483647)) |
| item->pingProbeHistoryMaxIndex = 0; |
| temp->pingProbeHistoryIndex = |
| ++(item->pingProbeHistoryMaxIndex); |
| pthread_mutex_unlock(&counter_mutex); |
| |
| |
| temp->pingProbeHistoryResponse = rtt; |
| temp->pingProbeHistoryStatus = 1; |
| temp->pingProbeHistoryLastRC = 0; |
| |
| temp->pingProbeHistoryTime_time = timep; |
| temp->pingProbeHistoryTime = |
| netsnmp_memdup(date_n_time(&timep, |
| &temp->pingProbeHistoryTimeLen), |
| 11); |
| |
| if (StorageNew->pingResultsSendProbes == 1) |
| item->pingProbeHis = temp; |
| else { |
| (current_temp)->next = temp; |
| } |
| |
| current_temp = temp; |
| |
| if (StorageNew->pingResultsSendProbes >= |
| item->pingCtlProbeCount) { |
| current_temp->next = NULL; |
| } |
| |
| if (item->pingProbeHis != NULL) { |
| if (pingProbeHistoryTable_count(item) < |
| item->pingCtlMaxRows) { |
| if (pingProbeHistoryTable_add(current_temp) != |
| SNMPERR_SUCCESS) |
| DEBUGMSGTL(("pingProbeHistoryTable", |
| "registered an entry error\n")); |
| } else { |
| pingProbeHistoryTable_delLast(item); |
| if (pingProbeHistoryTable_add(current_temp) != |
| SNMPERR_SUCCESS) |
| DEBUGMSGTL(("pingProbeHistoryTable", |
| "registered an entry error\n")); |
| |
| } |
| } |
| } |
| } |
| |
| else if (flag == 1) |
| { |
| |
| |
| if (series == 0) |
| probeFailed = 1; |
| else |
| probeFailed = probeFailed + 1; |
| series = 1; |
| testFailed = testFailed + 1; |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) item->pingCtlOwnerIndex, item->pingCtlOwnerIndexLen); /* pingCtlOwnerIndex */ |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) item->pingCtlTestName, item->pingCtlTestNameLen); /* pingCtlTestName */ |
| |
| |
| if ((StorageNew = |
| header_complex_get(pingResultsTableStorage, vars)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; |
| |
| if (current_probe == 1) { |
| *averagertt = rtt; |
| *minrtt = rtt; |
| *maxrtt = rtt; |
| *sumrtt = rtt; |
| } |
| StorageNew->pingResultsSendProbes = |
| StorageNew->pingResultsSendProbes + 1; |
| |
| |
| |
| temp = SNMP_MALLOC_STRUCT(pingProbeHistoryTable_data); |
| |
| temp->pingCtlOwnerIndex = |
| (char *) malloc(item->pingCtlOwnerIndexLen + 1); |
| memcpy(temp->pingCtlOwnerIndex, item->pingCtlOwnerIndex, |
| item->pingCtlOwnerIndexLen + 1); |
| temp->pingCtlOwnerIndex[item->pingCtlOwnerIndexLen] = '\0'; |
| temp->pingCtlOwnerIndexLen = item->pingCtlOwnerIndexLen; |
| |
| temp->pingCtlTestName = |
| (char *) malloc(item->pingCtlTestNameLen + 1); |
| memcpy(temp->pingCtlTestName, item->pingCtlTestName, |
| item->pingCtlTestNameLen + 1); |
| temp->pingCtlTestName[item->pingCtlTestNameLen] = '\0'; |
| temp->pingCtlTestNameLen = item->pingCtlTestNameLen; |
| |
| /* add lock to protect */ |
| pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER; |
| pthread_mutex_lock(&counter_mutex); |
| temp->pingProbeHistoryIndex = ++(item->pingProbeHistoryMaxIndex); |
| pthread_mutex_unlock(&counter_mutex); |
| /* end */ |
| |
| temp->pingProbeHistoryResponse = item->pingCtlTimeOut * 1000; |
| temp->pingProbeHistoryStatus = 4; |
| temp->pingProbeHistoryLastRC = 1; |
| |
| temp->pingProbeHistoryTime_time = timep; |
| temp->pingProbeHistoryTime = |
| netsnmp_memdup(date_n_time(&timep, &temp->pingProbeHistoryTimeLen), |
| 11); |
| |
| if (StorageNew->pingResultsSendProbes == 1) |
| item->pingProbeHis = temp; |
| else { |
| (current_temp)->next = temp; |
| } |
| |
| current_temp = temp; |
| |
| if (StorageNew->pingResultsSendProbes >= item->pingCtlProbeCount) { |
| current_temp->next = NULL; |
| } |
| |
| if (item->pingProbeHis != NULL) { |
| if (pingProbeHistoryTable_count(item) < item->pingCtlMaxRows) { |
| if (pingProbeHistoryTable_add(current_temp) != |
| SNMPERR_SUCCESS) |
| DEBUGMSGTL(("pingProbeHistoryTable", |
| "registered an entry error\n")); |
| } else { |
| |
| pingProbeHistoryTable_delLast(item); |
| if (pingProbeHistoryTable_add(current_temp) != |
| SNMPERR_SUCCESS) |
| DEBUGMSGTL(("pingProbeHistoryTable", |
| "registered an entry error\n")); |
| |
| } |
| } |
| |
| if ((item-> |
| pingCtlTrapGeneration[0] & PINGTRAPGENERATION_PROBEFAILED) != |
| 0) { |
| if (probeFailed >= item->pingCtlTrapProbeFailureFilter) |
| send_ping_trap(item, pingProbeFailed, |
| sizeof(pingProbeFailed) / sizeof(oid)); |
| } |
| |
| |
| } |
| |
| if (current_probe == item->pingCtlProbeCount) { |
| if ((item-> |
| pingCtlTrapGeneration[0] & PINGTRAPGENERATION_TESTCOMPLETED) |
| != 0) { |
| send_ping_trap(item, pingTestCompleted, |
| sizeof(pingTestCompleted) / sizeof(oid)); |
| } else |
| if ((item-> |
| pingCtlTrapGeneration[0] & PINGTRAPGENERATION_TESTFAILED) |
| != 0) { |
| |
| if (testFailed >= item->pingCtlTrapTestFailureFilter) |
| send_ping_trap(item, pingTestFailed, |
| sizeof(pingTestFailed) / sizeof(oid)); |
| } |
| |
| else if ((item-> |
| pingCtlTrapGeneration[0] & |
| PINGTRAPGENERATION_PROBEFAILED) != 0) {; |
| } else { |
| ; |
| } |
| |
| series = 0; |
| probeFailed = 0; |
| testFailed = 0; |
| |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| void |
| send_v4(int datalen, pid_t pid, int nsent, int sockfd, char *sendbuf) |
| { |
| int len; |
| struct icmp *icmp = NULL; |
| |
| icmp = (struct icmp *) sendbuf; |
| icmp->icmp_type = ICMP_ECHO; |
| icmp->icmp_code = 0; |
| icmp->icmp_id = pid; |
| icmp->icmp_seq = nsent; |
| gettimeofday((struct timeval *) icmp->icmp_data, NULL); |
| |
| len = 8 + datalen; /* checksum ICMP header and data */ |
| icmp->icmp_cksum = 0; |
| icmp->icmp_cksum = in_cksum((u_short *) icmp, len); |
| |
| sendto(sockfd, sendbuf, len, 0, pr->sasend, pr->salen); |
| } |
| |
| |
| void |
| run_ping(unsigned int clientreg, void *clientarg) |
| /* run_ping(struct pingCtlTable_data *item) */ |
| { |
| struct pingCtlTable_data *item = clientarg; |
| netsnmp_variable_list *vars = NULL; |
| struct pingResultsTable_data *StorageNew = NULL; |
| |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) item->pingCtlOwnerIndex, item->pingCtlOwnerIndexLen); /* pingCtlOwnerIndex */ |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) item->pingCtlTestName, item->pingCtlTestNameLen); /* pingCtlTestName */ |
| |
| |
| if ((StorageNew = |
| header_complex_get(pingResultsTableStorage, vars)) == NULL) |
| return; |
| |
| StorageNew->pingResultsSendProbes = 0; |
| StorageNew->pingResultsProbeResponses = 0; |
| |
| if (item->pingCtlTargetAddressType == 1 |
| || item->pingCtlTargetAddressType == 16) { |
| struct proto proto_v4 = |
| { proc_v4, send_v4, NULL, NULL, 0, IPPROTO_ICMP }; |
| char *host = NULL; |
| pid_t pid; /* our PID */ |
| |
| int datalen; |
| unsigned long *minrtt = NULL; |
| unsigned long *maxrtt = NULL; |
| unsigned long *averagertt = NULL; |
| |
| datalen = 56; /* data that goes with ICMP echo request */ |
| struct addrinfo *ai = NULL; |
| minrtt = malloc(sizeof(unsigned long)); |
| maxrtt = malloc(sizeof(unsigned long)); |
| averagertt = malloc(sizeof(unsigned long)); |
| host = item->pingCtlTargetAddress; |
| pid = getpid(); |
| |
| ai = host_serv(host, NULL, 0, 0); |
| |
| printf("PING %s (%s): %d data bytes\n", ai->ai_canonname, |
| sock_ntop_host(ai->ai_addr, ai->ai_addrlen), datalen); |
| |
| /* |
| * 4initialize according to protocol |
| */ |
| if (ai->ai_family == AF_INET) { |
| pr = &proto_v4; |
| #ifdef IPV6 |
| } else if (ai->ai_family == AF_INET6) { |
| pr = &proto_v6; |
| |
| if (IN6_IS_ADDR_V4MAPPED(&(((struct sockaddr_in6 *) |
| ai->ai_addr)->sin6_addr))) |
| printf("cannot ping IPv4-mapped IPv6 address"); |
| #endif |
| } else |
| printf("unknown address family %d", ai->ai_family); |
| |
| pr->sasend = ai->ai_addr; |
| pr->sarecv = calloc(1, ai->ai_addrlen); |
| pr->salen = ai->ai_addrlen; |
| readloop(item, ai, datalen, minrtt, maxrtt, averagertt, pid); |
| |
| SNMP_FREE(minrtt); |
| SNMP_FREE(maxrtt); |
| SNMP_FREE(averagertt); |
| SNMP_FREE(ai); |
| } |
| |
| else if (item->pingCtlTargetAddressType == 2) { |
| |
| int hold = 0, packlen = 0; |
| u_char *packet = NULL; |
| char *target = NULL; |
| struct sockaddr_in6 firsthop; |
| int socket_errno = 0; |
| struct icmp6_filter filter; |
| int err = 0, csum_offset = 0, sz_opt = 0; |
| |
| static int icmp_sock = 0; |
| int uid = 0; |
| struct sockaddr_in6 source; |
| int preload = 0; |
| static unsigned char cmsgbuf[4096]; |
| static int cmsglen = 0; |
| struct sockaddr_in6 whereto; /* who to ping */ |
| int options = 0; |
| char *hostname = NULL; |
| char *device = NULL; |
| int interval = 1000; /* interval between packets (msec) */ |
| int pmtudisc = -1; |
| int datalen = DEFDATALEN; |
| int timing = 0; /* flag to do timing */ |
| int working_recverr = 0; |
| __u32 flowlabel = 0; |
| |
| int ident = 0; /* process id to identify our packets */ |
| u_char outpack[MAX_PACKET]; |
| struct timeval start_time; |
| static int screen_width = INT_MAX; |
| int deadline = 0; /* time to die */ |
| int timeout = 0; |
| |
| timeout = item->pingCtlTimeOut; |
| memset(&source, 0, sizeof(source)); |
| icmp_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); |
| socket_errno = errno; |
| |
| uid = getuid(); |
| setuid(uid); |
| |
| source.sin6_family = AF_INET6; |
| memset(&firsthop, 0, sizeof(firsthop)); |
| firsthop.sin6_family = AF_INET6; |
| preload = 1; |
| |
| target = item->pingCtlTargetAddress; |
| |
| memset(&whereto, 0, sizeof(struct sockaddr_in6)); |
| whereto.sin6_family = AF_INET6; |
| whereto.sin6_port = htons(IPPROTO_ICMPV6); |
| |
| if (inet_pton(AF_INET6, target, &whereto.sin6_addr) <= 0) { |
| struct hostent *hp = NULL; |
| |
| hp = gethostbyname2(target, AF_INET6); |
| |
| if (hp == NULL) { |
| fprintf(stderr, "unknown host\n"); |
| return; |
| } |
| |
| memcpy(&whereto.sin6_addr, hp->h_addr_list[0], 16); |
| } else { |
| options |= F_NUMERIC; |
| } |
| if (ipv6_addr_any(&firsthop.sin6_addr)) |
| memcpy(&firsthop.sin6_addr, &whereto.sin6_addr, 16); |
| |
| hostname = target; |
| |
| if (ipv6_addr_any(&source.sin6_addr)) { |
| |
| socklen_t alen; |
| int probe_fd = socket(AF_INET6, SOCK_DGRAM, 0); |
| |
| if (probe_fd < 0) { |
| printf("error!\n"); |
| perror("socket"); |
| return; |
| } |
| if (device) { |
| struct ifreq ifr; |
| memset(&ifr, 0, sizeof(ifr)); |
| strlcpy(ifr.ifr_name, device, IFNAMSIZ); |
| if (setsockopt |
| (probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, |
| strlen(device) + 1) == -1) { |
| #ifdef HAVE_SIN6_SCOPEID |
| if ((firsthop.sin6_addr. |
| s6_addr16[0] & htons(0xffc0)) == htons(0xfe80) |
| || (firsthop.sin6_addr. |
| s6_addr16[0] & htons(0xffff)) == |
| htons(0xff02)) { |
| if (ioctl(probe_fd, SIOCGIFINDEX, &ifr) < 0) { |
| fprintf(stderr, "ping: unknown iface %s\n", |
| device); |
| return; |
| } |
| firsthop.sin6_scope_id = ifr.ifr_ifindex; |
| } |
| #endif |
| } |
| } |
| firsthop.sin6_port = htons(1025); |
| if (connect |
| (probe_fd, (struct sockaddr *) &firsthop, |
| sizeof(firsthop)) == -1) { |
| perror("connect"); |
| return; |
| } |
| alen = sizeof(source); |
| if (getsockname(probe_fd, (struct sockaddr *) &source, &alen) |
| == -1) { |
| perror("getsockname"); |
| return; |
| } |
| source.sin6_port = 0; |
| close(probe_fd); |
| } |
| |
| if (icmp_sock < 0) { |
| errno = socket_errno; |
| perror("ping: icmp open socket"); |
| return; |
| } |
| |
| if ((whereto.sin6_addr.s6_addr16[0] & htons(0xff00)) == |
| htons(0xff00)) { |
| if (uid) { |
| if (interval < 1000) { |
| fprintf(stderr, |
| "ping: multicast ping with too short interval.\n"); |
| return; |
| } |
| if (pmtudisc >= 0 && pmtudisc != IPV6_PMTUDISC_DO) { |
| fprintf(stderr, |
| "ping: multicast ping does not fragment.\n"); |
| return; |
| } |
| } |
| if (pmtudisc < 0) |
| pmtudisc = IPV6_PMTUDISC_DO; |
| } |
| |
| if (pmtudisc >= 0) { |
| if (setsockopt |
| (icmp_sock, SOL_IPV6, IPV6_MTU_DISCOVER, &pmtudisc, |
| sizeof(pmtudisc)) == -1) { |
| perror("ping: IPV6_MTU_DISCOVER"); |
| return; |
| } |
| } |
| if (bind(icmp_sock, (struct sockaddr *) &source, sizeof(source)) == |
| -1) { |
| perror("ping: bind icmp socket"); |
| return; |
| } |
| if (datalen >= sizeof(struct timeval)) /* can we time transfer */ |
| timing = 1; |
| packlen = datalen + 8 + 4096 + 40 + 8; /* 4096 for rthdr */ |
| if (!(packet = (u_char *) malloc((u_int) packlen))) { |
| fprintf(stderr, "ping: out of memory.\n"); |
| return; |
| } |
| |
| working_recverr = 1; |
| hold = 1; |
| if (setsockopt |
| (icmp_sock, SOL_IPV6, IPV6_RECVERR, (char *) &hold, |
| sizeof(hold))) { |
| fprintf(stderr, |
| "WARNING: your kernel is veeery old. No problems.\n"); |
| working_recverr = 0; |
| } |
| |
| /* |
| * Estimate memory eaten by single packet. It is rough estimate. |
| * * Actually, for small datalen's it depends on kernel side a lot. |
| */ |
| hold = datalen + 8; |
| hold += ((hold + 511) / 512) * (40 + 16 + 64 + 160); |
| sock_setbufs(icmp_sock, hold, preload); |
| |
| csum_offset = 2; |
| sz_opt = sizeof(int); |
| |
| err = |
| setsockopt(icmp_sock, SOL_RAW, IPV6_CHECKSUM, &csum_offset, |
| sz_opt); |
| if (err < 0) { |
| perror("setsockopt(RAW_CHECKSUM)"); |
| return; |
| } |
| |
| /* |
| * select icmp echo reply as icmp type to receive |
| */ |
| |
| ICMPV6_FILTER_SETBLOCKALL(&filter); |
| |
| if (!working_recverr) { |
| ICMPV6_FILTER_SETPASS(ICMP6_DST_UNREACH, &filter); |
| ICMPV6_FILTER_SETPASS(ICMP6_PACKET_TOO_BIG, &filter); |
| ICMPV6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &filter); |
| ICMPV6_FILTER_SETPASS(ICMP6_PARAM_PROB, &filter); |
| } |
| |
| ICMPV6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter); |
| |
| err = setsockopt(icmp_sock, SOL_ICMPV6, ICMP6_FILTER, &filter, |
| sizeof(struct icmp6_filter)); |
| |
| if (err < 0) { |
| perror("setsockopt(ICMP6_FILTER)"); |
| return; |
| } |
| |
| if (1) { |
| int on = 1; |
| if (setsockopt(icmp_sock, IPPROTO_IPV6, IPV6_HOPLIMIT, |
| &on, sizeof(on)) == -1) { |
| perror("can't receive hop limit"); |
| return; |
| } |
| } |
| |
| printf("PING %s(%s) ", hostname, |
| pr_addr(&whereto.sin6_addr, options)); |
| if (flowlabel) |
| printf(", flow 0x%05x, ", (unsigned) ntohl(flowlabel)); |
| if (device || (options & F_NUMERIC)) { |
| printf("from %s %s: ", |
| pr_addr_n(&source.sin6_addr), device ? : ""); |
| } |
| printf("%d data bytes\n", datalen); |
| |
| setup(icmp_sock, options, uid, timeout, preload, interval, datalen, |
| (char *) outpack, &ident, &start_time, &screen_width, |
| &deadline); |
| |
| main_loop(item, icmp_sock, preload, packet, packlen, cmsglen, |
| (char *) cmsgbuf, &whereto, options, uid, hostname, |
| interval, datalen, timing, working_recverr, |
| (char *) outpack, &ident, &start_time, &screen_width, |
| &deadline); |
| |
| close(icmp_sock); |
| } |
| return; |
| } |
| |
| void |
| init_resultsTable(struct pingCtlTable_data *item) |
| { |
| struct pingResultsTable_data *StorageTmp = NULL; |
| struct pingResultsTable_data *StorageNew = NULL; |
| struct addrinfo *ai = NULL; |
| char *host = NULL; |
| netsnmp_variable_list *vars = NULL; |
| |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) item->pingCtlOwnerIndex, item->pingCtlOwnerIndexLen); /* pingCtlOwnerIndex */ |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) item->pingCtlTestName, item->pingCtlTestNameLen); /* pingCtlTestName */ |
| |
| |
| if ((StorageNew = |
| header_complex_get(pingResultsTableStorage, vars)) != NULL) { |
| StorageNew->pingResultsSendProbes = 0; |
| StorageNew->pingResultsProbeResponses = 0; |
| return; |
| |
| } |
| ai = malloc(sizeof(struct addrinfo)); |
| host = item->pingCtlTargetAddress; |
| ai = host_serv(host, NULL, 0, 0); |
| StorageTmp = SNMP_MALLOC_STRUCT(pingResultsTable_data); |
| |
| StorageTmp->pingCtlOwnerIndex = |
| (char *) malloc(item->pingCtlOwnerIndexLen + 1); |
| memcpy(StorageTmp->pingCtlOwnerIndex, item->pingCtlOwnerIndex, |
| item->pingCtlOwnerIndexLen + 1); |
| StorageTmp->pingCtlOwnerIndex[item->pingCtlOwnerIndexLen] = '\0'; |
| StorageTmp->pingCtlOwnerIndexLen = item->pingCtlOwnerIndexLen; |
| |
| StorageTmp->pingCtlTestName = |
| (char *) malloc(item->pingCtlTestNameLen + 1); |
| memcpy(StorageTmp->pingCtlTestName, item->pingCtlTestName, |
| item->pingCtlTestNameLen + 1); |
| StorageTmp->pingCtlTestName[item->pingCtlTestNameLen] = '\0'; |
| StorageTmp->pingCtlTestNameLen = item->pingCtlTestNameLen; |
| |
| StorageTmp->pingResultsOperStatus = 1; |
| |
| if (item->pingCtlTargetAddressType == 1 |
| || item->pingCtlTargetAddressType == 16) { |
| if (ai == NULL) { |
| StorageTmp->pingResultsIpTargetAddressType = 0; |
| StorageTmp->pingResultsIpTargetAddress = strdup(""); |
| StorageTmp->pingResultsIpTargetAddressLen = 0; |
| } else { |
| StorageTmp->pingResultsIpTargetAddressType = 1; |
| StorageTmp->pingResultsIpTargetAddress = |
| (char *) |
| malloc(strlen(sock_ntop_host(ai->ai_addr, ai->ai_addrlen)) |
| + 1); |
| StorageTmp->pingResultsIpTargetAddress = |
| strdup(sock_ntop_host(ai->ai_addr, ai->ai_addrlen)); |
| StorageTmp-> |
| pingResultsIpTargetAddress[strlen |
| (sock_ntop_host |
| (ai->ai_addr, |
| ai->ai_addrlen))] = '\0'; |
| StorageTmp->pingResultsIpTargetAddressLen = |
| strlen(sock_ntop_host(ai->ai_addr, ai->ai_addrlen)); |
| } |
| } |
| if (item->pingCtlTargetAddressType == 2) { |
| |
| struct sockaddr_in6 whereto; /* Who to try to reach */ |
| register struct sockaddr_in6 *to = |
| (struct sockaddr_in6 *) &whereto; |
| struct hostent *hp = NULL; |
| char pa[64]; |
| |
| to->sin6_family = AF_INET6; |
| to->sin6_port = htons(33434); |
| |
| if (inet_pton(AF_INET6, host, &to->sin6_addr) > 0) { |
| StorageTmp->pingResultsIpTargetAddressType = 2; |
| StorageTmp->pingResultsIpTargetAddress = |
| (char *) malloc(strlen(host) + 1); |
| StorageTmp->pingResultsIpTargetAddress = strdup(host); |
| StorageTmp->pingResultsIpTargetAddress[strlen(host)] = '\0'; |
| StorageTmp->pingResultsIpTargetAddressLen = strlen(host); |
| } else { |
| hp = gethostbyname2(host, AF_INET6); |
| if (hp != NULL) { |
| const char *hostname = NULL; |
| memmove((caddr_t) & to->sin6_addr, hp->h_addr, 16); |
| hostname = inet_ntop(AF_INET6, &to->sin6_addr, pa, 64); |
| StorageTmp->pingResultsIpTargetAddressType = 2; |
| StorageTmp->pingResultsIpTargetAddress = |
| (char *) malloc(strlen(hostname) + 1); |
| StorageTmp->pingResultsIpTargetAddress = strdup(hostname); |
| StorageTmp->pingResultsIpTargetAddress[strlen(hostname)] = |
| '\0'; |
| StorageTmp->pingResultsIpTargetAddressLen = |
| strlen(hostname); |
| } else { |
| (void) fprintf(stderr, |
| "traceroute: unknown host %s\n", host); |
| StorageTmp->pingResultsIpTargetAddressType = 0; |
| StorageTmp->pingResultsIpTargetAddress = strdup(""); |
| StorageTmp->pingResultsIpTargetAddressLen = 0; |
| } |
| } |
| } |
| |
| |
| StorageTmp->pingResultsMinRtt = 0; |
| StorageTmp->pingResultsMaxRtt = 0; |
| StorageTmp->pingResultsAverageRtt = 0; |
| StorageTmp->pingResultsProbeResponses = 0; |
| StorageTmp->pingResultsSendProbes = 0; |
| StorageTmp->pingResultsRttSumOfSquares = 0; |
| |
| StorageTmp->pingResultsLastGoodProbeLen = 0; |
| |
| item->pingResults = StorageTmp; |
| if (item->pingProbeHistoryMaxIndex == 0) { |
| if (item->pingResults != NULL) { |
| if (pingResultsTable_add(item) != SNMPERR_SUCCESS) { |
| DEBUGMSGTL(("pingResultsTable", "init an entry error\n")); |
| } |
| } |
| } |
| SNMP_FREE(ai); |
| |
| } |
| |
| |
| int |
| modify_ResultsOper(struct pingCtlTable_data *thedata, long val) |
| { |
| netsnmp_variable_list *vars = NULL; |
| struct pingResultsTable_data *StorageTmp = NULL; |
| |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) thedata->pingCtlOwnerIndex, thedata->pingCtlOwnerIndexLen); /* pingCtlOwnerIndex */ |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) thedata->pingCtlTestName, thedata->pingCtlTestNameLen); /* pingCtlTestName */ |
| |
| |
| if ((StorageTmp = |
| header_complex_get(pingResultsTableStorage, vars)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; |
| StorageTmp->pingResultsOperStatus = val; |
| |
| DEBUGMSGTL(("pingResultsOperStatus", "done.\n")); |
| return SNMPERR_SUCCESS; |
| } |
| |
| |
| int |
| pingResultsTable_del(struct pingCtlTable_data *thedata) |
| { |
| struct header_complex_index *hciptr2 = NULL; |
| struct pingResultsTable_data *StorageDel = NULL; |
| netsnmp_variable_list *vars = NULL; |
| oid newoid[MAX_OID_LEN]; |
| size_t newoid_len; |
| |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) thedata->pingCtlOwnerIndex, thedata->pingCtlOwnerIndexLen); /* pingCtlOwnerIndex */ |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) thedata->pingCtlTestName, thedata->pingCtlTestNameLen); /* pingCtlOperationName */ |
| |
| header_complex_generate_oid(newoid, &newoid_len, NULL, 0, vars); |
| |
| for (hciptr2 = pingResultsTableStorage; hciptr2 != NULL; |
| hciptr2 = hciptr2->next) { |
| if (snmp_oid_compare(newoid, newoid_len, hciptr2->name, newoid_len) |
| == 0) { |
| StorageDel = |
| header_complex_extract_entry(&pingResultsTableStorage, |
| hciptr2); |
| if (StorageDel != NULL) { |
| SNMP_FREE(StorageDel->pingCtlOwnerIndex); |
| SNMP_FREE(StorageDel->pingCtlTestName); |
| SNMP_FREE(StorageDel->pingResultsIpTargetAddress); |
| SNMP_FREE(StorageDel->pingResultsLastGoodProbe); |
| SNMP_FREE(StorageDel); |
| } |
| DEBUGMSGTL(("pingResultsTable", "delete success!\n")); |
| |
| } |
| } |
| return SNMPERR_SUCCESS; |
| } |
| |
| |
| int |
| pingProbeHistoryTable_del(struct pingCtlTable_data *thedata) |
| { |
| struct header_complex_index *hciptr2 = NULL; |
| struct pingProbeHistoryTable_data *StorageDel = NULL; |
| netsnmp_variable_list *vars = NULL; |
| oid newoid[MAX_OID_LEN]; |
| size_t newoid_len; |
| |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) thedata->pingCtlOwnerIndex, thedata->pingCtlOwnerIndexLen); /* pingCtlOwnerIndex */ |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) thedata->pingCtlTestName, thedata->pingCtlTestNameLen); /* pingCtlOperationName */ |
| |
| header_complex_generate_oid(newoid, &newoid_len, NULL, 0, vars); |
| |
| for (hciptr2 = pingProbeHistoryTableStorage; hciptr2 != NULL; |
| hciptr2 = hciptr2->next) { |
| if (snmp_oid_compare(newoid, newoid_len, hciptr2->name, newoid_len) |
| == 0) { |
| StorageDel = |
| header_complex_extract_entry(&pingProbeHistoryTableStorage, |
| hciptr2); |
| if (StorageDel != NULL) { |
| SNMP_FREE(StorageDel->pingCtlOwnerIndex); |
| SNMP_FREE(StorageDel->pingCtlTestName); |
| SNMP_FREE(StorageDel->pingProbeHistoryTime); |
| SNMP_FREE(StorageDel); |
| } |
| DEBUGMSGTL(("pingProbeHistoryTable", "delete success!\n")); |
| |
| } |
| } |
| return SNMPERR_SUCCESS; |
| } |
| |
| |
| int |
| write_pingCtlTargetAddressType(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static size_t tmpvar; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| |
| DEBUGMSGTL(("pingCtlTable", |
| "write_pingCtlTargetAddressType entering action=%d... \n", |
| action)); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_INTEGER) { |
| snmp_log(LOG_ERR, |
| "write to pingCtlTargetAddressType not ASN_INTEGER\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in objid for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlTargetAddressType; |
| StorageTmp->pingCtlTargetAddressType = *((long *) var_val); |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| StorageTmp->pingCtlTargetAddressType = tmpvar; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| int |
| write_pingCtlTargetAddress(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static char *tmpvar; |
| static size_t tmplen; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_OCTET_STR) { |
| snmp_log(LOG_ERR, |
| "write to pingCtlTargetAddress not ASN_OCTET_STR\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in long_ret for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlTargetAddress; |
| tmplen = StorageTmp->pingCtlTargetAddressLen; |
| |
| StorageTmp->pingCtlTargetAddress = |
| (char *) malloc(var_val_len + 1); |
| if (StorageTmp->pingCtlTargetAddress == NULL) { |
| exit(1); |
| } |
| memcpy(StorageTmp->pingCtlTargetAddress, var_val, var_val_len); |
| StorageTmp->pingCtlTargetAddress[var_val_len] = '\0'; |
| StorageTmp->pingCtlTargetAddressLen = var_val_len; |
| |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| SNMP_FREE(StorageTmp->pingCtlTargetAddress); |
| StorageTmp->pingCtlTargetAddress = tmpvar; |
| StorageTmp->pingCtlTargetAddressLen = tmplen; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| SNMP_FREE(tmpvar); |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| int |
| write_pingCtlDataSize(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static size_t tmpvar; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| |
| DEBUGMSGTL(("pingCtlTable", |
| "pingCtlDataSize entering action=%d... \n", action)); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_UNSIGNED) { |
| snmp_log(LOG_ERR, |
| "write to pingCtlDataSize not ASN_UNSIGNED\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in objid for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlDataSize; |
| if ((*((long *) var_val)) >= 0 && (*((long *) var_val)) <= 65507) |
| StorageTmp->pingCtlDataSize = *((long *) var_val); |
| else |
| StorageTmp->pingCtlDataSize = 56; |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| StorageTmp->pingCtlDataSize = tmpvar; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| |
| int |
| write_pingCtlTimeOut(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static size_t tmpvar; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| |
| DEBUGMSGTL(("pingCtlTable", |
| "pingCtlTimeOut entering action=%d... \n", action)); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_UNSIGNED) { |
| snmp_log(LOG_ERR, |
| "write to pingCtlDataSize not ASN_UNSIGNED\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in objid for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlTimeOut; |
| if ((*((long *) var_val)) >= 1 && (*((long *) var_val)) <= 60) |
| StorageTmp->pingCtlTimeOut = *((long *) var_val); |
| else |
| StorageTmp->pingCtlTimeOut = 3; |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| StorageTmp->pingCtlTimeOut = tmpvar; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| |
| |
| int |
| write_pingCtlProbeCount(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static size_t tmpvar; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| |
| DEBUGMSGTL(("pingCtlTable", |
| "pingCtlProbeCount entering action=%d... \n", action)); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_UNSIGNED) { |
| snmp_log(LOG_ERR, |
| "write to pingCtlDataSize not ASN_UNSIGNED\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in objid for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlProbeCount; |
| |
| if ((*((long *) var_val)) >= 1 && (*((long *) var_val)) <= 15) |
| StorageTmp->pingCtlProbeCount = *((long *) var_val); |
| else |
| StorageTmp->pingCtlProbeCount = 15; |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| StorageTmp->pingCtlProbeCount = tmpvar; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| int |
| write_pingCtlAdminStatus(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static size_t tmpvar; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| |
| DEBUGMSGTL(("pingCtlTable", |
| "pingCtlAdminStatus entering action=%d... \n", action)); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_INTEGER) { |
| snmp_log(LOG_ERR, |
| "write to pingCtlTargetAddressType not ASN_INTEGER\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in objid for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlAdminStatus; |
| StorageTmp->pingCtlAdminStatus = *((long *) var_val); |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| StorageTmp->pingCtlAdminStatus = tmpvar; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| if (StorageTmp->pingCtlAdminStatus == 1 |
| && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| StorageTmp->pingResults->pingResultsOperStatus = 1; |
| modify_ResultsOper(StorageTmp, 1); |
| if (StorageTmp->pingCtlFrequency != 0) |
| StorageTmp->timer_id = |
| snmp_alarm_register(StorageTmp->pingCtlFrequency, |
| SA_REPEAT, run_ping, StorageTmp); |
| else |
| StorageTmp->timer_id = snmp_alarm_register(1, 0, run_ping, |
| StorageTmp); |
| |
| } else if (StorageTmp->pingCtlAdminStatus == 2 |
| && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| snmp_alarm_unregister(StorageTmp->timer_id); |
| StorageTmp->pingResults->pingResultsOperStatus = 2; |
| modify_ResultsOper(StorageTmp, 2); |
| } |
| |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| |
| int |
| write_pingCtlDataFill(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static char *tmpvar; |
| static size_t tmplen; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_OCTET_STR) { |
| snmp_log(LOG_ERR, |
| "write to pingCtlTargetAddress not ASN_OCTET_STR\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in long_ret for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlDataFill; |
| tmplen = StorageTmp->pingCtlDataFillLen; |
| StorageTmp->pingCtlDataFill = (char *) malloc(var_val_len + 1); |
| if (StorageTmp->pingCtlDataFill == NULL) { |
| exit(1); |
| } |
| memcpy(StorageTmp->pingCtlDataFill, var_val, var_val_len); |
| StorageTmp->pingCtlDataFill[var_val_len] = '\0'; |
| StorageTmp->pingCtlDataFillLen = var_val_len; |
| |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| SNMP_FREE(StorageTmp->pingCtlDataFill); |
| StorageTmp->pingCtlDataFill = tmpvar; |
| StorageTmp->pingCtlDataFillLen = tmplen; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| SNMP_FREE(tmpvar); |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| int |
| write_pingCtlFrequency(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static size_t tmpvar; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| |
| DEBUGMSGTL(("pingCtlTable", |
| "pingCtlFrequency entering action=%d... \n", action)); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_UNSIGNED) { |
| snmp_log(LOG_ERR, |
| "write to pingCtlDataSize not ASN_UNSIGNED\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in objid for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlFrequency; |
| StorageTmp->pingCtlFrequency = *((long *) var_val); |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| StorageTmp->pingCtlFrequency = tmpvar; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| int |
| write_pingCtlMaxRows(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static size_t tmpvar; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| |
| DEBUGMSGTL(("pingCtlTable", |
| "pingCtlMaxRows entering action=%d... \n", action)); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_UNSIGNED) { |
| snmp_log(LOG_ERR, |
| "write to pingCtlMaxRows not ASN_UNSIGNED\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in objid for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlMaxRows; |
| StorageTmp->pingCtlMaxRows = *((long *) var_val); |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| StorageTmp->pingCtlMaxRows = tmpvar; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| |
| int |
| write_pingCtlStorageType(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static size_t tmpvar; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| |
| DEBUGMSGTL(("pingCtlTable", |
| "pingCtlStorageType entering action=%d... \n", action)); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_INTEGER) { |
| snmp_log(LOG_ERR, |
| "write to pingCtlStorageType not ASN_INTEGER\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in objid for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlStorageType; |
| StorageTmp->pingCtlStorageType = *((long *) var_val); |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| StorageTmp->pingCtlStorageType = tmpvar; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| |
| int |
| write_pingCtlTrapGeneration(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static char *tmpvar; |
| static size_t tmplen; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_OCTET_STR) { |
| snmp_log(LOG_ERR, |
| "write to pingCtlTargetAddress not ASN_OCTET_STR\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in long_ret for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlTrapGeneration; |
| tmplen = StorageTmp->pingCtlTrapGenerationLen; |
| |
| StorageTmp->pingCtlTrapGeneration = |
| (char *) malloc(var_val_len + 1); |
| if (StorageTmp->pingCtlTrapGeneration == NULL) { |
| exit(1); |
| } |
| memcpy(StorageTmp->pingCtlTrapGeneration, var_val, var_val_len); |
| StorageTmp->pingCtlTrapGeneration[var_val_len] = '\0'; |
| StorageTmp->pingCtlTrapGenerationLen = var_val_len; |
| |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| SNMP_FREE(StorageTmp->pingCtlTrapGeneration); |
| StorageTmp->pingCtlTrapGeneration = tmpvar; |
| StorageTmp->pingCtlTrapGenerationLen = tmplen; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| SNMP_FREE(tmpvar); |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| int |
| write_pingCtlTrapProbeFailureFilter(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, |
| size_t name_len) |
| { |
| static size_t tmpvar; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| |
| DEBUGMSGTL(("pingCtlTable", |
| "pingCtlTrapProbeFailureFilter entering action=%d... \n", |
| action)); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_UNSIGNED) { |
| snmp_log(LOG_ERR, |
| "write to pingCtlTrapProbeFailureFilter not ASN_UNSIGNED\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in objid for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlTrapProbeFailureFilter; |
| |
| if ((*((long *) var_val)) >= 0 && (*((long *) var_val)) <= 15) |
| StorageTmp->pingCtlTrapProbeFailureFilter = |
| *((long *) var_val); |
| else |
| StorageTmp->pingCtlTrapProbeFailureFilter = 1; |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| StorageTmp->pingCtlTrapProbeFailureFilter = tmpvar; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| int |
| write_pingCtlTrapTestFailureFilter(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, |
| size_t name_len) |
| { |
| static size_t tmpvar; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| |
| DEBUGMSGTL(("pingCtlTable", |
| "pingCtlTrapTestFailureFilter entering action=%d... \n", |
| action)); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_UNSIGNED) { |
| snmp_log(LOG_ERR, |
| "write to pingCtlTrapTestFailureFilter not ASN_UNSIGNED\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in objid for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlTrapTestFailureFilter; |
| |
| if ((*((long *) var_val)) >= 0 && (*((long *) var_val)) <= 15) |
| StorageTmp->pingCtlTrapTestFailureFilter = *((long *) var_val); |
| else |
| StorageTmp->pingCtlTrapTestFailureFilter = 1; |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| StorageTmp->pingCtlTrapTestFailureFilter = tmpvar; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| |
| |
| int |
| write_pingCtlType(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static oid *tmpvar; |
| static size_t tmplen; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_OBJECT_ID) { |
| snmp_log(LOG_ERR, "write to pingCtlType not ASN_OBJECT_ID\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in long_ret for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlType; |
| tmplen = StorageTmp->pingCtlTypeLen; |
| |
| StorageTmp->pingCtlType = (oid *) malloc(var_val_len); |
| if (StorageTmp->pingCtlType == NULL) { |
| exit(1); |
| } |
| memcpy(StorageTmp->pingCtlType, var_val, var_val_len); |
| |
| StorageTmp->pingCtlTypeLen = var_val_len / sizeof(oid); |
| |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| SNMP_FREE(StorageTmp->pingCtlType); |
| StorageTmp->pingCtlType = tmpvar; |
| StorageTmp->pingCtlTypeLen = tmplen; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| SNMP_FREE(tmpvar); |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| |
| int |
| write_pingCtlDescr(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static char *tmpvar; |
| static size_t tmplen; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_OCTET_STR) { |
| snmp_log(LOG_ERR, "write to pingCtlDescr not ASN_OCTET_STR\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in long_ret for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlDescr; |
| tmplen = StorageTmp->pingCtlDescrLen; |
| |
| StorageTmp->pingCtlDescr = (char *) malloc(var_val_len + 1); |
| if (StorageTmp->pingCtlDescr == NULL) { |
| exit(1); |
| } |
| memcpy(StorageTmp->pingCtlDescr, var_val, var_val_len); |
| StorageTmp->pingCtlDescr[var_val_len] = '\0'; |
| StorageTmp->pingCtlDescrLen = var_val_len; |
| |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| SNMP_FREE(StorageTmp->pingCtlDescr); |
| StorageTmp->pingCtlDescr = tmpvar; |
| StorageTmp->pingCtlDescrLen = tmplen; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| SNMP_FREE(tmpvar); |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| int |
| write_pingCtlSourceAddressType(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static size_t tmpvar; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| |
| DEBUGMSGTL(("pingCtlTable", |
| "pingCtlSourceAddressType entering action=%d... \n", |
| action)); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_INTEGER) { |
| snmp_log(LOG_ERR, |
| "write to pingCtlSourceAddressType not ASN_INTEGER\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in objid for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlSourceAddressType; |
| StorageTmp->pingCtlSourceAddressType = *((long *) var_val); |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| StorageTmp->pingCtlSourceAddressType = tmpvar; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| |
| int |
| write_pingCtlSourceAddress(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static char *tmpvar; |
| static size_t tmplen; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_OCTET_STR) { |
| snmp_log(LOG_ERR, |
| "write to pingCtlSourceAddress not ASN_OCTET_STR\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in long_ret for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlSourceAddress; |
| tmplen = StorageTmp->pingCtlSourceAddressLen; |
| |
| StorageTmp->pingCtlSourceAddress = |
| (char *) malloc(var_val_len + 1); |
| if (StorageTmp->pingCtlSourceAddress == NULL) { |
| exit(1); |
| } |
| memcpy(StorageTmp->pingCtlSourceAddress, var_val, var_val_len); |
| StorageTmp->pingCtlSourceAddress[var_val_len] = '\0'; |
| StorageTmp->pingCtlSourceAddressLen = var_val_len; |
| |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| SNMP_FREE(StorageTmp->pingCtlSourceAddress); |
| StorageTmp->pingCtlSourceAddress = tmpvar; |
| StorageTmp->pingCtlSourceAddressLen = tmplen; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| SNMP_FREE(tmpvar); |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| int |
| write_pingCtlIfIndex(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static size_t tmpvar; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| |
| DEBUGMSGTL(("pingCtlTable", |
| "pingCtlIfIndex entering action=%d... \n", action)); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_INTEGER) { |
| snmp_log(LOG_ERR, "write to pingCtlIfIndex not ASN_INTEGER\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in objid for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlIfIndex; |
| StorageTmp->pingCtlIfIndex = *((long *) var_val); |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| StorageTmp->pingCtlIfIndex = tmpvar; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| |
| int |
| write_pingCtlByPassRouteTable(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static size_t tmpvar; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| |
| DEBUGMSGTL(("pingCtlTable", |
| "pingCtlByPassRouteTable entering action=%d... \n", |
| action)); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_INTEGER) { |
| snmp_log(LOG_ERR, |
| "write to pingCtlByPassRouteTable not ASN_INTEGER\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in objid for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlByPassRouteTable; |
| StorageTmp->pingCtlByPassRouteTable = *((long *) var_val); |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| StorageTmp->pingCtlByPassRouteTable = tmpvar; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| |
| |
| |
| int |
| write_pingCtlDSField(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| static size_t tmpvar; |
| struct pingCtlTable_data *StorageTmp = NULL; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| |
| |
| DEBUGMSGTL(("pingCtlTable", |
| "pingCtlDSField entering action=%d... \n", action)); |
| |
| if ((StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, |
| NULL)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ |
| |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| switch (action) { |
| case RESERVE1: |
| if (var_val_type != ASN_UNSIGNED) { |
| snmp_log(LOG_ERR, |
| "write to pingCtlDSField not ASN_UNSIGNED\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| break; |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| break; |
| |
| |
| case FREE: |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in objid for |
| * you to use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in the UNDO case |
| */ |
| tmpvar = StorageTmp->pingCtlDSField; |
| StorageTmp->pingCtlDSField = *((long *) var_val); |
| break; |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| StorageTmp->pingCtlDSField = tmpvar; |
| break; |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| int |
| write_pingCtlRowStatus(int action, |
| u_char * var_val, |
| u_char var_val_type, |
| size_t var_val_len, |
| u_char * statP, oid * name, size_t name_len) |
| { |
| struct pingCtlTable_data *StorageTmp = NULL; |
| static struct pingCtlTable_data *StorageNew, *StorageDel; |
| size_t newlen = |
| name_len - (sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 3 - 1); |
| static int old_value; |
| int set_value; |
| static netsnmp_variable_list *vars, *vp; |
| struct header_complex_index *hciptr = NULL; |
| |
| DEBUGMSGTL(("pingCtlTable", |
| "var_pingCtlTable: Entering... action=%ul\n", action)); |
| StorageTmp = |
| header_complex(pingCtlTableStorage, NULL, |
| &name[sizeof(pingCtlTable_variables_oid) / |
| sizeof(oid) + 3 - 1], &newlen, 1, NULL, NULL); |
| |
| if (var_val_type != ASN_INTEGER || var_val == NULL) { |
| snmp_log(LOG_ERR, "write to pingCtlRowStatus not ASN_INTEGER\n"); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| if (StorageTmp && StorageTmp->storageType == ST_READONLY) { |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| set_value = *((long *) var_val); |
| |
| |
| /* |
| * check legal range, and notReady is reserved for us, not a user |
| */ |
| if (set_value < 1 || set_value > 6 || set_value == RS_NOTREADY) |
| return SNMP_ERR_INCONSISTENTVALUE; |
| |
| |
| switch (action) { |
| case RESERVE1: |
| /* |
| * stage one: test validity |
| */ |
| if (StorageTmp == NULL) { |
| /* |
| * create the row now? |
| */ |
| |
| |
| /* |
| * ditch illegal values now |
| */ |
| if (set_value == RS_ACTIVE || set_value == RS_NOTINSERVICE) { |
| |
| return SNMP_ERR_INCONSISTENTVALUE; |
| } |
| |
| /* |
| * destroying a non-existent row is actually legal |
| */ |
| if (set_value == RS_DESTROY) { |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| /* |
| * illegal creation values |
| */ |
| if (set_value == RS_ACTIVE || set_value == RS_NOTINSERVICE) { |
| return SNMP_ERR_INCONSISTENTVALUE; |
| } |
| } else { |
| /* |
| * row exists. Check for a valid state change |
| */ |
| if (set_value == RS_CREATEANDGO |
| || set_value == RS_CREATEANDWAIT) { |
| /* |
| * can't create a row that exists |
| */ |
| return SNMP_ERR_INCONSISTENTVALUE; |
| } |
| |
| /* |
| * XXX: interaction with row storage type needed |
| */ |
| |
| if (StorageTmp->pingCtlRowStatus == RS_ACTIVE && |
| set_value != RS_DESTROY) { |
| /* |
| * "Once made active an entry may not be modified except to |
| * delete it." XXX: doesn't this in fact apply to ALL |
| * columns of the table and not just this one? |
| */ |
| return SNMP_ERR_INCONSISTENTVALUE; |
| } |
| if (StorageTmp->storageType != ST_NONVOLATILE) |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| break; |
| |
| |
| |
| |
| case RESERVE2: |
| /* |
| * memory reseveration, final preparation... |
| */ |
| if (StorageTmp == NULL) { |
| if (set_value == RS_DESTROY) { |
| return SNMP_ERR_NOERROR; |
| } |
| /* |
| * creation |
| */ |
| vars = NULL; |
| |
| /* |
| * ½«nameΪ¿ÕµÄÈý¸öË÷Òý×ֶμӵ½var±äÁ¿ÁбíµÄĩβ |
| */ |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, NULL, 0); /* pingCtlOwnerIndex */ |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, NULL, 0); /* pingCtlTestName */ |
| |
| if (header_complex_parse_oid |
| (& |
| (name |
| [sizeof(pingCtlTable_variables_oid) / sizeof(oid) + |
| 2]), newlen, vars) != SNMPERR_SUCCESS) { |
| /* |
| * XXX: free, zero vars |
| */ |
| /* snmp_free_varbind(vars); */ |
| return SNMP_ERR_INCONSISTENTNAME; |
| } |
| vp = vars; |
| |
| StorageNew = create_pingCtlTable_data(); |
| if (vp->val_len <= 32) { |
| StorageNew->pingCtlOwnerIndex = malloc(vp->val_len + 1); |
| memcpy(StorageNew->pingCtlOwnerIndex, vp->val.string, |
| vp->val_len); |
| StorageNew->pingCtlOwnerIndex[vp->val_len] = '\0'; |
| StorageNew->pingCtlOwnerIndexLen = vp->val_len; |
| } else { |
| StorageNew->pingCtlOwnerIndex = malloc(33); |
| memcpy(StorageNew->pingCtlOwnerIndex, vp->val.string, 32); |
| StorageNew->pingCtlOwnerIndex[32] = '\0'; |
| StorageNew->pingCtlOwnerIndexLen = 32; |
| } |
| |
| vp = vp->next_variable; |
| |
| if (vp->val_len <= 32) { |
| StorageNew->pingCtlTestName = malloc(vp->val_len + 1); |
| memcpy(StorageNew->pingCtlTestName, vp->val.string, |
| vp->val_len); |
| StorageNew->pingCtlTestName[vp->val_len] = '\0'; |
| StorageNew->pingCtlTestNameLen = vp->val_len; |
| } else { |
| StorageNew->pingCtlTestName = malloc(33); |
| memcpy(StorageNew->pingCtlTestName, vp->val.string, 32); |
| StorageNew->pingCtlTestName[32] = '\0'; |
| StorageNew->pingCtlTestNameLen = 32; |
| } |
| vp = vp->next_variable; |
| |
| /* |
| * XXX: fill in default row values here into StorageNew |
| */ |
| |
| StorageNew->pingCtlRowStatus = set_value; |
| |
| |
| /* |
| * XXX: free, zero vars, no longer needed? |
| */ |
| /* snmp_free_varbind(vars); */ |
| } |
| |
| |
| break; |
| |
| |
| |
| |
| case FREE: |
| /* |
| * XXX: free, zero vars |
| */ |
| |
| /* |
| * Release any resources that have been allocated |
| */ |
| break; |
| |
| |
| |
| |
| case ACTION: |
| /* |
| * The variable has been stored in set_value for you to |
| * use, and you have just been asked to do something with |
| * it. Note that anything done here must be reversable in |
| * the UNDO case |
| */ |
| |
| if (StorageTmp == NULL) { |
| if (set_value == RS_DESTROY) { |
| return SNMP_ERR_NOERROR; |
| } |
| /* |
| * row creation, so add it |
| */ |
| if (StorageNew != NULL) |
| #if 1 |
| DEBUGMSGTL(("pingCtlTable", |
| "write_pingCtlRowStatus entering new=%d... \n", |
| action)); |
| #endif |
| pingCtlTable_add(StorageNew); |
| /* |
| * XXX: ack, and if it is NULL? |
| */ |
| } else if (set_value != RS_DESTROY) { |
| /* |
| * set the flag? |
| */ |
| old_value = StorageTmp->pingCtlRowStatus; |
| StorageTmp->pingCtlRowStatus = *((long *) var_val); |
| } else { |
| /* |
| * destroy... extract it for now |
| */ |
| |
| hciptr = |
| header_complex_find_entry(pingCtlTableStorage, StorageTmp); |
| StorageDel = |
| header_complex_extract_entry(&pingCtlTableStorage, hciptr); |
| snmp_alarm_unregister(StorageDel->timer_id); |
| |
| pingResultsTable_del(StorageTmp); |
| pingProbeHistoryTable_del(StorageTmp); |
| } |
| break; |
| |
| |
| |
| |
| case UNDO: |
| /* |
| * Back out any changes made in the ACTION case |
| */ |
| if (StorageTmp == NULL) { |
| if (set_value == RS_DESTROY) { |
| return SNMP_ERR_NOERROR; |
| } |
| /* |
| * row creation, so remove it again |
| */ |
| hciptr = |
| header_complex_find_entry(pingCtlTableStorage, StorageNew); |
| StorageDel = |
| header_complex_extract_entry(&pingCtlTableStorage, hciptr); |
| |
| /* |
| * XXX: free it |
| */ |
| } else if (StorageDel != NULL) { |
| /* |
| * row deletion, so add it again |
| */ |
| pingCtlTable_add(StorageDel); |
| pingResultsTable_add(StorageDel); |
| pingProbeHistoryTable_addall(StorageDel); |
| } else { |
| StorageTmp->pingCtlRowStatus = old_value; |
| } |
| break; |
| |
| |
| |
| |
| case COMMIT: |
| /* |
| * Things are working well, so it's now safe to make the change |
| * permanently. Make sure that anything done here can't fail! |
| */ |
| |
| if (StorageTmp == NULL) { |
| if (set_value == RS_DESTROY) { |
| return SNMP_ERR_NOERROR; |
| } |
| } |
| |
| if (StorageDel != NULL) { |
| /* |
| * if(strlen(StorageDel->pingCtlOwnerIndex)!=0) |
| * SNMP_FREE(StorageDel->pingCtlOwnerIndex); |
| * printf("COMMIT1 \n"); |
| * if(strlen(StorageDel->pingCtlTestName)!=0) |
| * SNMP_FREE(StorageDel->pingCtlTestName); |
| * printf("COMMIT2 \n"); |
| * if(strlen(StorageDel->pingCtlTargetAddress)!=0) |
| * SNMP_FREE(StorageDel->pingCtlTargetAddress); |
| * printf("COMMIT3 \n"); |
| * if(strlen(StorageDel->pingCtlDataFill)!=0) |
| * SNMP_FREE(StorageDel->pingCtlDataFill); |
| * printf("COMMIT4 \n"); |
| * if(strlen(StorageDel->pingCtlTrapGeneration)!=0) |
| * SNMP_FREE(StorageDel->pingCtlTrapGeneration); |
| * printf("COMMIT5 \n"); |
| * if(StorageDel->pingCtlTypeLen!=0) |
| * SNMP_FREE(StorageDel->pingCtlType); |
| * printf("COMMIT6 \n"); |
| * if(strlen(StorageDel->pingCtlDescr)!=0) |
| * SNMP_FREE(StorageDel->pingCtlDescr); |
| * printf("COMMIT7 \n"); |
| * if(strlen(StorageDel->pingCtlSourceAddress)!=0) |
| * SNMP_FREE(StorageDel->pingCtlSourceAddress); |
| * printf("COMMIT8 \n"); |
| */ |
| StorageDel = NULL; |
| /* StorageDel = 0; */ |
| /* |
| * XXX: free it, its dead |
| */ |
| } else { |
| if (StorageTmp |
| && StorageTmp->pingCtlRowStatus == RS_CREATEANDGO) { |
| StorageTmp->pingCtlRowStatus = RS_ACTIVE; |
| } else if (StorageTmp && |
| StorageTmp->pingCtlRowStatus == RS_CREATEANDWAIT) { |
| DEBUGMSGTL(("pingCtlTable", |
| "write_pingCtlRowStatus entering pingCtlRowStatus=%ld... \n", |
| StorageTmp->pingCtlRowStatus)); |
| |
| StorageTmp->pingCtlRowStatus = RS_NOTINSERVICE; |
| } |
| } |
| if (StorageTmp && StorageTmp->pingCtlRowStatus == RS_ACTIVE) { |
| #if 1 |
| DEBUGMSGTL(("pingCtlTable", |
| "write_pingCtlRowStatus entering runbefore \n")); |
| |
| #endif |
| |
| if (StorageTmp->pingCtlAdminStatus == 1) { |
| init_resultsTable(StorageTmp); |
| if (StorageTmp->pingCtlFrequency != 0) |
| StorageTmp->timer_id = |
| snmp_alarm_register(StorageTmp->pingCtlFrequency, |
| SA_REPEAT, run_ping, |
| StorageTmp); |
| else |
| StorageTmp->timer_id = |
| snmp_alarm_register(1, 0, run_ping, StorageTmp); |
| |
| } |
| |
| } |
| |
| break; |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| static inline void |
| tvsub(struct timeval *out, struct timeval *in) |
| { |
| if ((out->tv_usec -= in->tv_usec) < 0) { |
| --out->tv_sec; |
| out->tv_usec += 1000000; |
| } |
| out->tv_sec -= in->tv_sec; |
| } |
| |
| |
| static inline int |
| schedule_exit(int next, int *deadline, long *npackets, long *nreceived, |
| long *ntransmitted, long *tmax) |
| { |
| if ((*npackets) && (*ntransmitted) >= (*npackets) && !(*deadline)) |
| next = __schedule_exit(next, nreceived, tmax); |
| return next; |
| } |
| |
| static inline int |
| in_flight(__u16 * acked, long *nreceived, long *ntransmitted, |
| long *nerrors) |
| { |
| __u16 diff = (__u16) (*ntransmitted) - (*acked); |
| return (diff <= |
| 0x7FFF) ? diff : (*ntransmitted) - (*nreceived) - (*nerrors); |
| } |
| |
| static inline void |
| acknowledge(__u16 seq, __u16 * acked, long *ntransmitted, int *pipesize) |
| { |
| __u16 diff = (__u16) (*ntransmitted) - seq; |
| if (diff <= 0x7FFF) { |
| if ((int) diff + 1 > (*pipesize)) |
| (*pipesize) = (int) diff + 1; |
| if ((__s16) (seq - (*acked)) > 0 || |
| (__u16) (*ntransmitted) - (*acked) > 0x7FFF) |
| *acked = seq; |
| } |
| } |
| |
| static inline void |
| advance_ntransmitted(__u16 * acked, long *ntransmitted) |
| { |
| (*ntransmitted)++; |
| /* |
| * Invalidate acked, if 16 bit seq overflows. |
| */ |
| if ((__u16) (*ntransmitted) - (*acked) > 0x7FFF) |
| *acked = (__u16) (*ntransmitted) + 1; |
| } |
| |
| |
| static inline void |
| update_interval(int uid, int interval, int *rtt_addend, int *rtt) |
| { |
| int est = (*rtt) ? (*rtt) / 8 : interval * 1000; |
| |
| interval = (est + (*rtt_addend) + 500) / 1000; |
| if (uid && interval < MINUSERINTERVAL) |
| interval = MINUSERINTERVAL; |
| } |
| |
| |
| |
| int |
| __schedule_exit(int next, long *nreceived, long *tmax) |
| { |
| unsigned long waittime; |
| #if 0 |
| struct itimerval it; |
| #endif |
| |
| if (*nreceived) { |
| waittime = 2 * (*tmax); |
| if (waittime < 1000000) |
| waittime = 1000000; |
| } else |
| waittime = MAXWAIT * 1000000; |
| |
| if (next < 0 || next < waittime / 1000) |
| next = waittime / 1000; |
| |
| #if 0 |
| it.it_interval.tv_sec = 0; |
| it.it_interval.tv_usec = 0; |
| it.it_value.tv_sec = waittime / 1000000; |
| it.it_value.tv_usec = waittime % 1000000; |
| setitimer(ITIMER_REAL, &it, NULL); |
| #endif |
| return next; |
| } |
| |
| |
| /* |
| * pinger -- |
| * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet |
| * will be added on by the kernel. The ID field is our UNIX process ID, |
| * and the sequence number is an ascending integer. The first 8 bytes |
| * of the data portion are used to hold a UNIX "timeval" struct in VAX |
| * byte-order, to compute the round-trip time. |
| */ |
| |
| int |
| pinger(int icmp_sock, int preload, int cmsglen, char *cmsgbuf, |
| struct sockaddr_in6 *whereto, int *rtt_addend, int options, int uid, |
| int interval, int datalen, int timing, char *outpack, int *rtt, |
| int *ident, int *screen_width, int *deadline, __u16 * acked, |
| long *npackets, long *nreceived, long *ntransmitted, long *nerrors, |
| int *confirm_flag, int *confirm, int *pipesize, |
| struct timeval *cur_time) |
| { |
| static int tokens; |
| int i; |
| |
| /* |
| * Have we already sent enough? If we have, return an arbitrary positive value. |
| */ |
| |
| if (exiting |
| || ((*npackets) && (*ntransmitted) >= (*npackets) |
| && !(*deadline))) { |
| |
| return 1000; |
| } |
| /* |
| * Check that packets < rate*time + preload |
| */ |
| if ((*cur_time).tv_sec == 0) { |
| |
| gettimeofday(cur_time, NULL); |
| tokens = interval * (preload - 1); |
| } else { |
| long ntokens; |
| struct timeval tv; |
| |
| gettimeofday(&tv, NULL); |
| ntokens = (tv.tv_sec - (*cur_time).tv_sec) * 1000 + |
| (tv.tv_usec - (*cur_time).tv_usec) / 1000; |
| if (!interval) { |
| /* |
| * Case of unlimited flood is special; |
| * * if we see no reply, they are limited to 100pps |
| */ |
| if (ntokens < MININTERVAL |
| && in_flight(acked, nreceived, ntransmitted, |
| nerrors) >= preload) |
| return MININTERVAL - ntokens; |
| } |
| ntokens += tokens; |
| |
| if (ntokens > interval * preload) |
| ntokens = interval * preload; |
| |
| if (ntokens < interval) { |
| return interval - ntokens; |
| } |
| *cur_time = tv; |
| tokens = ntokens - interval; |
| } |
| |
| resend: |
| i = send_v6(icmp_sock, cmsglen, cmsgbuf, whereto, datalen, timing, |
| outpack, ident, ntransmitted, confirm); |
| |
| if (i == 0) { |
| advance_ntransmitted(acked, ntransmitted); |
| if (!(options & F_QUIET) && (options & F_FLOOD)) { |
| /* |
| * Very silly, but without this output with |
| * * high preload or pipe size is very confusing. |
| */ |
| if ((preload < (*screen_width) |
| && (*pipesize) < (*screen_width)) |
| || in_flight(acked, nreceived, ntransmitted, |
| nerrors) < (*screen_width)) |
| write(STDOUT_FILENO, ".", 1); |
| } |
| |
| return interval - tokens; |
| } |
| |
| /* |
| * And handle various errors... |
| */ |
| if (i > 0) { |
| /* |
| * Apparently, it is some fatal bug. |
| */ |
| abort(); |
| } else if (errno == ENOBUFS || errno == ENOMEM) { |
| /* |
| * Device queue overflow or OOM. Packet is not sent. |
| */ |
| tokens = 0; |
| /* |
| * Slowdown. This works only in adaptive mode (option -A) |
| */ |
| (*rtt_addend) += ((*rtt) < 8 * 50000 ? (*rtt) / 8 : 50000); |
| if (options & F_ADAPTIVE) |
| update_interval(uid, interval, rtt_addend, rtt); |
| |
| return SCHINT(interval); |
| } else if (errno == EAGAIN) { |
| /* |
| * Socket buffer is full. |
| */ |
| tokens += interval; |
| |
| return MININTERVAL; |
| } else { |
| if ((i = |
| receive_error_msg(icmp_sock, whereto, options, ident, |
| nerrors)) > 0) { |
| /* |
| * An ICMP error arrived. |
| */ |
| tokens += interval; |
| |
| return MININTERVAL; |
| } |
| /* |
| * Compatibility with old linuces. |
| */ |
| if (i == 0 && (*confirm_flag) && errno == EINVAL) { |
| *confirm_flag = 0; |
| errno = 0; |
| } |
| if (!errno) |
| goto resend; |
| |
| /* |
| * Hard local error. Pretend we sent packet. |
| */ |
| advance_ntransmitted(acked, ntransmitted); |
| |
| if (i == 0 && !(options & F_QUIET)) { |
| if (options & F_FLOOD) |
| write(STDOUT_FILENO, "E", 1); |
| else |
| perror("ping: sendmsg"); |
| } |
| tokens = 0; |
| |
| return SCHINT(interval); |
| } |
| } |
| |
| /* |
| * Set socket buffers, "alloc" is an esimate of memory taken by single packet. |
| */ |
| |
| void |
| sock_setbufs(int icmp_sock, int alloc, int preload) |
| { |
| int rcvbuf, hold; |
| socklen_t tmplen = sizeof(hold); |
| int sndbuf; |
| |
| if (!sndbuf) |
| sndbuf = alloc; |
| setsockopt(icmp_sock, SOL_SOCKET, SO_SNDBUF, (char *) &sndbuf, |
| sizeof(sndbuf)); |
| |
| rcvbuf = hold = alloc * preload; |
| if (hold < 65536) |
| hold = 65536; |
| setsockopt(icmp_sock, SOL_SOCKET, SO_RCVBUF, (char *) &hold, |
| sizeof(hold)); |
| if (getsockopt |
| (icmp_sock, SOL_SOCKET, SO_RCVBUF, (char *) &hold, &tmplen) == 0) { |
| if (hold < rcvbuf) |
| fprintf(stderr, |
| "WARNING: probably, rcvbuf is not enough to hold preload.\n"); |
| } |
| } |
| |
| /* |
| * Protocol independent setup and parameter checks. |
| */ |
| |
| void |
| setup(int icmp_sock, int options, int uid, int timeout, int preload, |
| int interval, int datalen, char *outpack, int *ident, |
| struct timeval *start_time, int *screen_width, int *deadline) |
| { |
| int hold; |
| struct timeval tv; |
| |
| if ((options & F_FLOOD) && !(options & F_INTERVAL)) |
| interval = 0; |
| |
| if (uid && interval < MINUSERINTERVAL) { |
| fprintf(stderr, |
| "ping: cannot flood; minimal interval, allowed for user, is %dms\n", |
| MINUSERINTERVAL); |
| return; |
| } |
| |
| if (interval >= INT_MAX / preload) { |
| fprintf(stderr, "ping: illegal preload and/or interval\n"); |
| return; |
| } |
| |
| hold = 1; |
| if (options & F_SO_DEBUG) |
| setsockopt(icmp_sock, SOL_SOCKET, SO_DEBUG, (char *) &hold, |
| sizeof(hold)); |
| if (options & F_SO_DONTROUTE) |
| setsockopt(icmp_sock, SOL_SOCKET, SO_DONTROUTE, (char *) &hold, |
| sizeof(hold)); |
| |
| #ifdef SO_TIMESTAMP |
| if (!(options & F_LATENCY)) { |
| int on = 1; |
| if (setsockopt |
| (icmp_sock, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on))) |
| fprintf(stderr, |
| "Warning: no SO_TIMESTAMP support, falling back to SIOCGSTAMP\n"); |
| } |
| #endif |
| |
| /* |
| * Set some SNDTIMEO to prevent blocking forever |
| * * on sends, when device is too slow or stalls. Just put limit |
| * * of one second, or "interval", if it is less. |
| */ |
| tv.tv_sec = 1; |
| tv.tv_usec = 0; |
| if (interval < 1000) { |
| tv.tv_sec = 0; |
| tv.tv_usec = 1000 * SCHINT(interval); |
| } |
| setsockopt(icmp_sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &tv, |
| sizeof(tv)); |
| |
| /* |
| * Set RCVTIMEO to "interval". Note, it is just an optimization |
| * * allowing to avoid redundant poll(). |
| */ |
| |
| tv.tv_sec = timeout; |
| tv.tv_usec = 0; |
| if (setsockopt |
| (icmp_sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof(tv))) |
| options |= F_FLOOD_POLL; |
| |
| if (!(options & F_PINGFILLED)) { |
| int i; |
| char *p = outpack + 8; |
| |
| /* |
| * Do not forget about case of small datalen, |
| * * fill timestamp area too! |
| */ |
| for (i = 0; i < datalen; ++i) |
| *p++ = i; |
| } |
| |
| *ident = getpid() & 0xFFFF; |
| |
| gettimeofday(start_time, NULL); |
| |
| #if 0 |
| if (*deadline) { |
| struct itimerval it; |
| |
| it.it_interval.tv_sec = 0; |
| it.it_interval.tv_usec = 0; |
| it.it_value.tv_sec = (*deadline); |
| it.it_value.tv_usec = 0; |
| } |
| #endif |
| |
| if (isatty(STDOUT_FILENO)) { |
| struct winsize w; |
| |
| if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) { |
| if (w.ws_col > 0) |
| *screen_width = w.ws_col; |
| } |
| } |
| } |
| |
| void |
| main_loop(struct pingCtlTable_data *item, int icmp_sock, int preload, |
| __u8 * packet, int packlen, int cmsglen, char *cmsgbuf, |
| struct sockaddr_in6 *whereto, int options, int uid, |
| char *hostname, int interval, int datalen, int timing, |
| int working_recverr, char *outpack, int *ident, |
| struct timeval *start_time, int *screen_width, int *deadline) |
| { |
| char addrbuf[128]; |
| char ans_data[4096]; |
| struct iovec iov; |
| struct msghdr msg; |
| struct cmsghdr *c; |
| int cc = 0; |
| int next = 0; |
| int polling = 0; |
| int rtt = 0; |
| int rtt_addend = 0; |
| |
| __u16 acked = 0; |
| /* |
| * counters |
| */ |
| long npackets = 0; /* max packets to transmit */ |
| long nreceived = 0; /* # of packets we got back */ |
| long nrepeats = 0; /* number of duplicates */ |
| long ntransmitted = 0; /* sequence # for outbound packets = #sent */ |
| long nchecksum = 0; /* replies with bad checksum */ |
| long nerrors = 0; /* icmp errors */ |
| |
| /* |
| * timing |
| */ |
| long tmin = LONG_MAX; /* minimum round trip time */ |
| long tmax = 0; /* maximum round trip time */ |
| long long tsum = 0; /* sum of all times, for doing average */ |
| long long tsum2 = 0; |
| |
| int confirm_flag = MSG_CONFIRM; |
| int confirm = 0; |
| |
| int pipesize = -1; |
| struct timeval cur_time; |
| cur_time.tv_sec = 0; |
| cur_time.tv_usec = 0; |
| |
| struct pingProbeHistoryTable_data current_temp; |
| static int probeFailed = 0; |
| static int testFailed = 0; |
| static int series = 0; |
| |
| iov.iov_base = (char *) packet; |
| npackets = item->pingCtlProbeCount; |
| for (;;) { |
| /* |
| * Check exit conditions. |
| */ |
| if (exiting) { |
| break; |
| } |
| if (npackets && nreceived >= npackets) { |
| printf("npackets,nreceived=%ld\n", nreceived); |
| break; |
| } |
| if (deadline && nerrors) { |
| printf("deadline\n"); |
| break; |
| } |
| |
| /* |
| * Check for and do special actions. |
| */ |
| if (status_snapshot) |
| status(timing, &rtt, &nreceived, &nrepeats, &ntransmitted, |
| &tmin, &tmax, &tsum, &tsum2); |
| |
| /* |
| * Send probes scheduled to this time. |
| */ |
| do { |
| printf("pinger\n"); |
| next = |
| pinger(icmp_sock, preload, cmsglen, cmsgbuf, whereto, |
| &rtt_addend, uid, options, interval, datalen, |
| timing, outpack, &rtt, ident, screen_width, |
| deadline, &acked, &npackets, &nreceived, |
| &ntransmitted, &nerrors, &confirm_flag, &confirm, |
| &pipesize, &cur_time); |
| printf("1:next=%d\n", next); |
| next = |
| schedule_exit(next, deadline, &npackets, &nreceived, |
| &ntransmitted, &tmax); |
| printf("2:next=%d\n", next); |
| } while (next <= 0); |
| |
| /* |
| * "next" is time to send next probe, if positive. |
| * * If next<=0 send now or as soon as possible. |
| */ |
| |
| /* |
| * Technical part. Looks wicked. Could be dropped, |
| * * if everyone used the newest kernel. :-) |
| * * Its purpose is: |
| * * 1. Provide intervals less than resolution of scheduler. |
| * * Solution: spinning. |
| * * 2. Avoid use of poll(), when recvmsg() can provide |
| * * timed waiting (SO_RCVTIMEO). |
| */ |
| polling = 0; |
| if ((options & (F_ADAPTIVE | F_FLOOD_POLL)) |
| || next < SCHINT(interval)) { |
| int recv_expected = |
| in_flight(&acked, &nreceived, &ntransmitted, &nerrors); |
| |
| /* |
| * If we are here, recvmsg() is unable to wait for |
| * * required timeout. |
| */ |
| if (1000 * next <= 1000000 / (int) HZ) { |
| /* |
| * Very short timeout... So, if we wait for |
| * * something, we sleep for MININTERVAL. |
| * * Otherwise, spin! |
| */ |
| if (recv_expected) { |
| next = MININTERVAL; |
| } else { |
| next = 0; |
| /* |
| * When spinning, no reasons to poll. |
| * * Use nonblocking recvmsg() instead. |
| */ |
| polling = MSG_DONTWAIT; |
| /* |
| * But yield yet. |
| */ |
| sched_yield(); |
| } |
| } |
| |
| if (!polling && |
| ((options & (F_ADAPTIVE | F_FLOOD_POLL)) || interval)) { |
| struct pollfd pset; |
| pset.fd = icmp_sock; |
| pset.events = POLLIN | POLLERR; |
| pset.revents = 0; |
| if (poll(&pset, 1, next) < 1 || |
| !(pset.revents & (POLLIN | POLLERR))) |
| continue; |
| polling = MSG_DONTWAIT; |
| } |
| } |
| |
| for (;;) { |
| struct timeval *recv_timep = NULL; |
| struct timeval recv_time; |
| int not_ours = 0; /* Raw socket can receive messages |
| * destined to other running pings. */ |
| |
| iov.iov_len = packlen; |
| msg.msg_name = addrbuf; |
| msg.msg_namelen = sizeof(addrbuf); |
| msg.msg_iov = &iov; |
| msg.msg_iovlen = 1; |
| msg.msg_control = ans_data; |
| msg.msg_controllen = sizeof(ans_data); |
| |
| cc = recvmsg(icmp_sock, &msg, polling); |
| time_t timep; |
| time(&timep); |
| polling = MSG_DONTWAIT; |
| |
| if (cc < 0) { |
| if (errno == EAGAIN || errno == EINTR) |
| break; |
| if (errno == EWOULDBLOCK) { |
| struct pingResultsTable_data *StorageNew = NULL; |
| struct pingProbeHistoryTable_data *temp = NULL; |
| netsnmp_variable_list *vars = NULL; |
| |
| |
| |
| if (series == 0) |
| probeFailed = 1; |
| else |
| probeFailed = probeFailed + 1; |
| series = 1; |
| testFailed = testFailed + 1; |
| |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) item->pingCtlOwnerIndex, item->pingCtlOwnerIndexLen); /* pingCtlOwnerIndex */ |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) item->pingCtlTestName, item->pingCtlTestNameLen); /* pingCtlTestName */ |
| |
| |
| if ((StorageNew = |
| header_complex_get(pingResultsTableStorage, |
| vars)) == NULL) |
| return; |
| |
| StorageNew->pingResultsSendProbes = |
| StorageNew->pingResultsSendProbes + 1; |
| |
| temp = SNMP_MALLOC_STRUCT(pingProbeHistoryTable_data); |
| |
| temp->pingCtlOwnerIndex = |
| (char *) malloc(item->pingCtlOwnerIndexLen + 1); |
| memcpy(temp->pingCtlOwnerIndex, |
| item->pingCtlOwnerIndex, |
| item->pingCtlOwnerIndexLen + 1); |
| temp->pingCtlOwnerIndex[item->pingCtlOwnerIndexLen] = |
| '\0'; |
| temp->pingCtlOwnerIndexLen = |
| item->pingCtlOwnerIndexLen; |
| |
| temp->pingCtlTestName = |
| (char *) malloc(item->pingCtlTestNameLen + 1); |
| memcpy(temp->pingCtlTestName, item->pingCtlTestName, |
| item->pingCtlTestNameLen + 1); |
| temp->pingCtlTestName[item->pingCtlTestNameLen] = '\0'; |
| temp->pingCtlTestNameLen = item->pingCtlTestNameLen; |
| |
| /* add lock to protect */ |
| pthread_mutex_t counter_mutex = |
| PTHREAD_MUTEX_INITIALIZER; |
| pthread_mutex_lock(&counter_mutex); |
| temp->pingProbeHistoryIndex = |
| ++(item->pingProbeHistoryMaxIndex); |
| pthread_mutex_unlock(&counter_mutex); |
| /* end */ |
| |
| temp->pingProbeHistoryResponse = |
| item->pingCtlTimeOut * 1000; |
| temp->pingProbeHistoryStatus = 4; |
| temp->pingProbeHistoryLastRC = 1; |
| |
| temp->pingProbeHistoryTime_time = timep; |
| temp->pingProbeHistoryTime = |
| netsnmp_memdup(date_n_time(&timep, |
| &temp->pingProbeHistoryTimeLen), |
| 11); |
| |
| if (StorageNew->pingResultsSendProbes == 1) |
| item->pingProbeHis = temp; |
| else { |
| (current_temp).next = temp; |
| } |
| |
| current_temp = (*temp); |
| |
| if (StorageNew->pingResultsSendProbes >= |
| item->pingCtlProbeCount) { |
| current_temp.next = NULL; |
| } |
| |
| if (item->pingProbeHis != NULL) { |
| if (pingProbeHistoryTable_count(item) < |
| item->pingCtlMaxRows) { |
| if (pingProbeHistoryTable_add(¤t_temp) != |
| SNMPERR_SUCCESS) |
| DEBUGMSGTL(("pingProbeHistoryTable", |
| "registered an entry error\n")); |
| } else { |
| pingProbeHistoryTable_delLast(item); |
| if (pingProbeHistoryTable_add(¤t_temp) != |
| SNMPERR_SUCCESS) |
| DEBUGMSGTL(("pingProbeHistoryTable", |
| "registered an entry error\n")); |
| |
| } |
| } |
| if ((item-> |
| pingCtlTrapGeneration[0] & |
| PINGTRAPGENERATION_PROBEFAILED) != 0) { |
| if (probeFailed >= |
| item->pingCtlTrapProbeFailureFilter) |
| send_ping_trap(item, pingProbeFailed, |
| sizeof(pingProbeFailed) / |
| sizeof(oid)); |
| } |
| break; |
| } |
| /* timeout finish */ |
| if (!receive_error_msg |
| (icmp_sock, whereto, options, ident, &nerrors)) { |
| if (errno) { |
| perror("ping: recvmsg"); |
| break; |
| } |
| not_ours = 1; |
| } |
| } else { |
| printf("cc>=0,else\n"); |
| #ifdef SO_TIMESTAMP |
| for (c = CMSG_FIRSTHDR(&msg); c; c = CMSG_NXTHDR(&msg, c)) { |
| if (c->cmsg_level != SOL_SOCKET || |
| c->cmsg_type != SO_TIMESTAMP) |
| continue; |
| if (c->cmsg_len < CMSG_LEN(sizeof(struct timeval))) |
| continue; |
| recv_timep = (struct timeval *) CMSG_DATA(c); |
| } |
| #endif |
| |
| if ((options & F_LATENCY) || recv_timep == NULL) { |
| if ((options & F_LATENCY) || |
| ioctl(icmp_sock, SIOCGSTAMP, &recv_time)) |
| gettimeofday(&recv_time, NULL); |
| recv_timep = &recv_time; |
| } |
| |
| not_ours = |
| parse_reply(&series, item, &msg, cc, addrbuf, |
| recv_timep, timep, uid, whereto, |
| &rtt_addend, options, interval, datalen, |
| timing, working_recverr, outpack, &rtt, |
| ident, &acked, &nreceived, &nrepeats, |
| &ntransmitted, &nchecksum, &nerrors, &tmin, |
| &tmax, &tsum, &tsum2, &confirm_flag, |
| &confirm, &pipesize, ¤t_temp); |
| } |
| |
| /* |
| * See? ... someone runs another ping on this host. |
| */ |
| if (not_ours) |
| install_filter(icmp_sock, ident); |
| |
| /* |
| * If nothing is in flight, "break" returns us to pinger. |
| */ |
| if (in_flight(&acked, &nreceived, &ntransmitted, &nerrors) == |
| 0) |
| break; |
| |
| /* |
| * Otherwise, try to recvmsg() again. recvmsg() |
| * * is nonblocking after the first iteration, so that |
| * * if nothing is queued, it will receive EAGAIN |
| * * and return to pinger. |
| */ |
| } |
| } |
| |
| if (ntransmitted == item->pingCtlProbeCount) { |
| |
| if ((item-> |
| pingCtlTrapGeneration[0] & PINGTRAPGENERATION_TESTCOMPLETED) |
| != 0) { |
| send_ping_trap(item, pingTestCompleted, |
| sizeof(pingTestCompleted) / sizeof(oid)); |
| } else |
| if ((item-> |
| pingCtlTrapGeneration[0] & PINGTRAPGENERATION_TESTFAILED) |
| != 0) { |
| |
| if (testFailed >= item->pingCtlTrapTestFailureFilter) |
| send_ping_trap(item, pingTestFailed, |
| sizeof(pingTestFailed) / sizeof(oid)); |
| } |
| |
| else if ((item-> |
| pingCtlTrapGeneration[0] & |
| PINGTRAPGENERATION_PROBEFAILED) != 0) {; |
| } else { |
| ; |
| } |
| |
| series = 0; |
| probeFailed = 0; |
| testFailed = 0; |
| |
| } |
| |
| finish(options, hostname, interval, timing, &rtt, start_time, deadline, |
| &npackets, &nreceived, &nrepeats, &ntransmitted, &nchecksum, |
| &nerrors, &tmin, &tmax, &tsum, &tsum2, &pipesize, &cur_time); |
| } |
| |
| int |
| gather_statistics(int *series, struct pingCtlTable_data *item, __u8 * ptr, |
| int cc, __u16 seq, int hops, int csfailed, |
| struct timeval *tv, time_t timep, int *rtt_addend, |
| int uid, int options, char *from, int interval, |
| int datalen, int timing, char *outpack, int *rtt, |
| __u16 * acked, long *nreceived, long *nrepeats, |
| long *ntransmitted, long *nchecksum, long *tmin, |
| long *tmax, long long *tsum, long long *tsum2, |
| int *confirm_flag, int *confirm, int *pipesize, |
| struct pingProbeHistoryTable_data *current_temp) |
| { |
| int dupflag = 0; |
| long triptime = 0; |
| int mx_dup_ck = MAX_DUP_CHK; |
| |
| netsnmp_variable_list *vars = NULL; |
| struct pingResultsTable_data *StorageNew = NULL; |
| struct pingProbeHistoryTable_data *temp = NULL; |
| ++(*nreceived); |
| *series = 0; |
| if (!csfailed) |
| acknowledge(seq, acked, ntransmitted, pipesize); |
| |
| if (timing && cc >= 8 + sizeof(struct timeval)) { |
| struct timeval tmp_tv; |
| memcpy(&tmp_tv, ptr, sizeof(tmp_tv)); |
| |
| restamp: |
| tvsub(tv, &tmp_tv); |
| triptime = tv->tv_sec * 1000000 + tv->tv_usec; |
| if (triptime < 0) { |
| fprintf(stderr, |
| "Warning: time of day goes back (%ldus), taking countermeasures.\n", |
| triptime); |
| triptime = 0; |
| if (!(options & F_LATENCY)) { |
| gettimeofday(tv, NULL); |
| options |= F_LATENCY; |
| goto restamp; |
| } |
| } |
| if (!csfailed) { |
| (*tsum) += triptime; |
| (*tsum2) += (long long) triptime *(long long) triptime; |
| if (triptime < (*tmin)) |
| (*tmin) = triptime; |
| if (triptime > (*tmax)) |
| (*tmax) = triptime; |
| if (!(*rtt)) |
| *rtt = triptime * 8; |
| else |
| *rtt += triptime - (*rtt) / 8; |
| if (options & F_ADAPTIVE) |
| update_interval(uid, interval, rtt_addend, rtt); |
| } |
| } |
| |
| if (csfailed) { |
| ++(*nchecksum); |
| --(*nreceived); |
| } else if (TST(seq % mx_dup_ck)) { |
| ++(*nrepeats); |
| --(*nreceived); |
| dupflag = 1; |
| } else { |
| SET(seq % mx_dup_ck); |
| dupflag = 0; |
| } |
| *confirm = *confirm_flag; |
| |
| if (options & F_QUIET) |
| return 1; |
| |
| if (options & F_FLOOD) { |
| if (!csfailed) |
| write(STDOUT_FILENO, "\b \b", 3); |
| else |
| write(STDOUT_FILENO, "\bC", 1); |
| } else { |
| int i; |
| __u8 *cp, *dp; |
| printf("%d bytes from %s: icmp_seq=%u", cc, from, seq); |
| |
| if (hops >= 0) |
| printf(" ttl=%d", hops); |
| |
| if (cc < datalen + 8) { |
| printf(" (truncated)\n"); |
| return 1; |
| } |
| if (timing) { |
| if (triptime >= 100000) |
| printf(" time=%ld ms", triptime / 1000); |
| else if (triptime >= 10000) |
| printf(" time=%ld.%01ld ms", triptime / 1000, |
| (triptime % 1000) / 100); |
| else if (triptime >= 1000) |
| printf(" time=%ld.%02ld ms", triptime / 1000, |
| (triptime % 1000) / 10); |
| else |
| printf(" time=%ld.%03ld ms", triptime / 1000, |
| triptime % 1000); |
| } |
| if (dupflag) |
| printf(" (DUP!)"); |
| if (csfailed) |
| printf(" (BAD CHECKSUM!)"); |
| |
| /* |
| * check the data |
| */ |
| cp = ((u_char *) ptr) + sizeof(struct timeval); |
| dp = (u_char *)&outpack[8 + sizeof(struct timeval)]; |
| for (i = sizeof(struct timeval); i < datalen; ++i, ++cp, ++dp) { |
| if (*cp != *dp) { |
| printf("\nwrong data byte #%d should be 0x%x but was 0x%x", |
| i, *dp, *cp); |
| cp = (u_char *) ptr + sizeof(struct timeval); |
| for (i = sizeof(struct timeval); i < datalen; ++i, ++cp) { |
| if ((i % 32) == sizeof(struct timeval)) |
| printf("\n#%d\t", i); |
| printf("%x ", *cp); |
| } |
| break; |
| } |
| } |
| } |
| |
| |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) item->pingCtlOwnerIndex, item->pingCtlOwnerIndexLen); /* pingCtlOwnerIndex */ |
| snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, (char *) item->pingCtlTestName, item->pingCtlTestNameLen); /* pingCtlTestName */ |
| |
| |
| if ((StorageNew = |
| header_complex_get(pingResultsTableStorage, vars)) == NULL) |
| return SNMP_ERR_NOSUCHNAME; |
| |
| |
| StorageNew->pingResultsMinRtt = *tmin; |
| StorageNew->pingResultsMaxRtt = *tmax; |
| StorageNew->pingResultsAverageRtt = |
| (*tsum) / (StorageNew->pingResultsProbeResponses + 1); |
| StorageNew->pingResultsProbeResponses = |
| StorageNew->pingResultsProbeResponses + 1; |
| StorageNew->pingResultsSendProbes = |
| StorageNew->pingResultsSendProbes + 1; |
| StorageNew->pingResultsRttSumOfSquares = *tsum2; |
| |
| StorageNew->pingResultsLastGoodProbe_time = timep; |
| StorageNew->pingResultsLastGoodProbe = |
| netsnmp_memdup(date_n_time(&timep, |
| &StorageNew->pingResultsLastGoodProbeLen), |
| 11); |
| |
| /* ProbeHistory */ |
| if (item->pingCtlMaxRows != 0) { |
| temp = SNMP_MALLOC_STRUCT(pingProbeHistoryTable_data); |
| |
| temp->pingCtlOwnerIndex = |
| (char *) malloc(item->pingCtlOwnerIndexLen + 1); |
| memcpy(temp->pingCtlOwnerIndex, item->pingCtlOwnerIndex, |
| item->pingCtlOwnerIndexLen + 1); |
| temp->pingCtlOwnerIndex[item->pingCtlOwnerIndexLen] = '\0'; |
| temp->pingCtlOwnerIndexLen = item->pingCtlOwnerIndexLen; |
| |
| temp->pingCtlTestName = |
| (char *) malloc(item->pingCtlTestNameLen + 1); |
| memcpy(temp->pingCtlTestName, item->pingCtlTestName, |
| item->pingCtlTestNameLen + 1); |
| temp->pingCtlTestName[item->pingCtlTestNameLen] = '\0'; |
| temp->pingCtlTestNameLen = item->pingCtlTestNameLen; |
| |
| /* add lock to protect */ |
| pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER; |
| pthread_mutex_lock(&counter_mutex); |
| if (item->pingProbeHistoryMaxIndex >= (unsigned long) (2147483647)) |
| item->pingProbeHistoryMaxIndex = 0; |
| temp->pingProbeHistoryIndex = ++(item->pingProbeHistoryMaxIndex); |
| pthread_mutex_unlock(&counter_mutex); |
| /* end */ |
| |
| |
| temp->pingProbeHistoryResponse = triptime; |
| temp->pingProbeHistoryStatus = 1; |
| temp->pingProbeHistoryLastRC = 0; |
| |
| temp->pingProbeHistoryTime_time = timep; |
| temp->pingProbeHistoryTime = |
| netsnmp_memdup(date_n_time(&timep, &temp->pingProbeHistoryTimeLen), |
| 11); |
| |
| if (StorageNew->pingResultsSendProbes == 1) |
| item->pingProbeHis = temp; |
| else { |
| (current_temp)->next = temp; |
| } |
| |
| current_temp = temp; |
| |
| if (StorageNew->pingResultsSendProbes >= item->pingCtlProbeCount) { |
| current_temp->next = NULL; |
| } |
| |
| if (item->pingProbeHis != NULL) { |
| |
| if (pingProbeHistoryTable_count(item) < item->pingCtlMaxRows) { |
| if (pingProbeHistoryTable_add(current_temp) != |
| SNMPERR_SUCCESS) |
| DEBUGMSGTL(("pingProbeHistoryTable", |
| "registered an entry error\n")); |
| } else { |
| pingProbeHistoryTable_delLast(item); |
| |
| if (pingProbeHistoryTable_add(current_temp) != |
| SNMPERR_SUCCESS) |
| DEBUGMSGTL(("pingProbeHistoryTable", |
| "registered an entry error\n")); |
| |
| } |
| |
| } |
| } |
| return 0; |
| } |
| |
| static long |
| llsqrt(long long a) |
| { |
| long long prev = ~((long long) 1 << 63); |
| long long x = a; |
| |
| if (x > 0) { |
| while (x < prev) { |
| prev = x; |
| x = (x + (a / x)) / 2; |
| } |
| } |
| |
| return (long) x; |
| } |
| |
| /* |
| * finish -- |
| * Print out statistics, and give up. |
| */ |
| void |
| finish(int options, char *hostname, int interval, int timing, int *rtt, |
| struct timeval *start_time, int *deadline, long *npackets, |
| long *nreceived, long *nrepeats, long *ntransmitted, |
| long *nchecksum, long *nerrors, long *tmin, long *tmax, |
| long long *tsum, long long *tsum2, int *pipesize, |
| struct timeval *cur_time) |
| { |
| struct timeval tv = *cur_time; |
| |
| tvsub(&tv, start_time); |
| |
| putchar('\n'); |
| fflush(stdout); |
| printf("--- %s ping statistics ---\n", hostname); |
| |
| if (*nrepeats) |
| printf(", +%ld duplicates", *nrepeats); |
| if (*nchecksum) |
| printf(", +%ld corrupted", *nchecksum); |
| if (*nerrors) |
| printf(", +%ld errors", *nerrors); |
| if (*ntransmitted) { |
| printf(", %d%% loss", |
| (int) ((((long long) ((*ntransmitted) - |
| (*nreceived))) * 100) / |
| (*ntransmitted))); |
| printf(", time %ldms", 1000 * tv.tv_sec + tv.tv_usec / 1000); |
| } |
| putchar('\n'); |
| |
| if ((*nreceived) && timing) { |
| long tmdev; |
| |
| (*tsum) /= (*nreceived) + (*nrepeats); |
| (*tsum2) /= (*nreceived) + (*nrepeats); |
| tmdev = llsqrt((*tsum2) - (*tsum) * (*tsum)); |
| |
| printf |
| ("rtt min/avg/max/mdev = %ld.%03ld/%lu.%03ld/%ld.%03ld/%ld.%03ld ms", |
| (*tmin) / 1000, (*tmin) % 1000, |
| (unsigned long) ((*tsum) / 1000), (long) ((*tsum) % 1000), |
| (*tmax) / 1000, (*tmax) % 1000, tmdev / 1000, tmdev % 1000); |
| } |
| if ((*pipesize) > 1) |
| printf(", pipe %d", *pipesize); |
| if ((*ntransmitted) > 1 |
| && (!interval || (options & (F_FLOOD | F_ADAPTIVE)))) { |
| int ipg = |
| (1000000 * (long long) tv.tv_sec + |
| tv.tv_usec) / ((*ntransmitted) - 1); |
| printf(", ipg/ewma %d.%03d/%d.%03d ms", ipg / 1000, ipg % 1000, |
| (*rtt) / 8000, ((*rtt) / 8) % 1000); |
| } |
| putchar('\n'); |
| return; |
| /* return(deadline ? (*nreceived)<(*npackets) : (*nreceived)==0); */ |
| } |
| |
| |
| void |
| status(int timing, int *rtt, long *nreceived, long *nrepeats, |
| long *ntransmitted, long *tmin, long *tmax, long long *tsum, |
| long long *tsum2) |
| { |
| int loss = 0; |
| long tavg = 0; |
| |
| status_snapshot = 0; |
| |
| if (*ntransmitted) |
| loss = |
| (((long long) ((*ntransmitted) - |
| (*nreceived))) * 100) / (*ntransmitted); |
| |
| fprintf(stderr, "\r%ld/%ld packets, %d%% loss", *ntransmitted, |
| *nreceived, loss); |
| |
| if ((*nreceived) && timing) { |
| tavg = (*tsum) / ((*nreceived) + (*nrepeats)); |
| |
| fprintf(stderr, |
| ", min/avg/ewma/max = %ld.%03ld/%lu.%03ld/%d.%03d/%ld.%03ld ms", |
| (*tmin) / 1000, (*tmin) % 1000, tavg / 1000, tavg % 1000, |
| (*rtt) / 8000, ((*rtt) / 8) % 1000, (*tmax) / 1000, |
| (*tmax) % 1000); |
| } |
| fprintf(stderr, "\n"); |
| } |
| |
| |
| static __inline__ int |
| ipv6_addr_any(struct in6_addr *addr) |
| { |
| static struct in6_addr in6_anyaddr; |
| return (memcmp(addr, &in6_anyaddr, 16) == 0); |
| } |
| |
| int |
| receive_error_msg(int icmp_sock, struct sockaddr_in6 *whereto, int options, |
| int *ident, long *nerrors) |
| { |
| int res; |
| char cbuf[512]; |
| struct iovec iov; |
| struct msghdr msg; |
| struct cmsghdr *cmsg; |
| struct sock_extended_err *e; |
| struct icmp6_hdr icmph; |
| struct sockaddr_in6 target; |
| int net_errors = 0; |
| int local_errors = 0; |
| int saved_errno = errno; |
| |
| iov.iov_base = &icmph; |
| iov.iov_len = sizeof(icmph); |
| msg.msg_name = (void *) ⌖ |
| msg.msg_namelen = sizeof(target); |
| msg.msg_iov = &iov; |
| msg.msg_iovlen = 1; |
| msg.msg_flags = 0; |
| msg.msg_control = cbuf; |
| msg.msg_controllen = sizeof(cbuf); |
| |
| res = recvmsg(icmp_sock, &msg, MSG_ERRQUEUE | MSG_DONTWAIT); |
| if (res < 0) |
| goto out; |
| |
| e = NULL; |
| for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { |
| if (cmsg->cmsg_level == SOL_IPV6) { |
| if (cmsg->cmsg_type == IPV6_RECVERR) |
| e = (struct sock_extended_err *) CMSG_DATA(cmsg); |
| } |
| } |
| if (e == NULL) |
| abort(); |
| |
| if (e->ee_origin == SO_EE_ORIGIN_LOCAL) { |
| local_errors++; |
| if (options & F_QUIET) |
| goto out; |
| if (options & F_FLOOD) |
| write(STDOUT_FILENO, "E", 1); |
| else if (e->ee_errno != EMSGSIZE) |
| fprintf(stderr, "ping: local error: %s\n", |
| strerror(e->ee_errno)); |
| else |
| fprintf(stderr, |
| "ping: local error: Message too long, mtu=%u\n", |
| e->ee_info); |
| (*nerrors)++; |
| } else if (e->ee_origin == SO_EE_ORIGIN_ICMP6) { |
| if (res < sizeof(icmph) || |
| memcmp(&target.sin6_addr, &(whereto->sin6_addr), 16) || |
| icmph.icmp6_type != ICMP6_ECHO_REQUEST || |
| icmph.icmp6_id != *ident) { |
| /* |
| * Not our error, not an error at all. Clear. |
| */ |
| saved_errno = 0; |
| goto out; |
| } |
| |
| net_errors++; |
| (*nerrors)++; |
| if (options & F_QUIET) |
| goto out; |
| if (options & F_FLOOD) { |
| write(STDOUT_FILENO, "\bE", 2); |
| } else { |
| fflush(stdout); |
| } |
| } |
| |
| out: |
| errno = saved_errno; |
| return net_errors ? : -local_errors; |
| } |
| |
| int |
| send_v6(int icmp_sock, int cmsglen, char *cmsgbuf, |
| struct sockaddr_in6 *whereto, int datalen, int timing, |
| char *outpack, int *ident, long *ntransmitted, int *confirm) |
| { |
| struct icmp6_hdr *icmph; |
| int cc; |
| int i; |
| int mx_dup_ck = MAX_DUP_CHK; |
| |
| icmph = (struct icmp6_hdr *) outpack; |
| icmph->icmp6_type = ICMP6_ECHO_REQUEST; |
| icmph->icmp6_code = 0; |
| icmph->icmp6_cksum = 0; |
| icmph->icmp6_seq = (*ntransmitted) + 1; |
| icmph->icmp6_id = *ident; |
| |
| CLR(icmph->icmp6_seq % mx_dup_ck); |
| |
| if (timing) |
| gettimeofday((struct timeval *) &outpack[8], |
| (struct timezone *) NULL); |
| |
| cc = datalen + 8; /* skips ICMP portion */ |
| |
| if (cmsglen == 0) { |
| i = sendto(icmp_sock, (char *) outpack, cc, *confirm, |
| (struct sockaddr *) whereto, |
| sizeof(struct sockaddr_in6)); |
| } else { |
| struct msghdr mhdr; |
| struct iovec iov; |
| |
| iov.iov_len = cc; |
| iov.iov_base = outpack; |
| |
| mhdr.msg_name = whereto; |
| mhdr.msg_namelen = sizeof(struct sockaddr_in6); |
| mhdr.msg_iov = &iov; |
| mhdr.msg_iovlen = 1; |
| mhdr.msg_control = cmsgbuf; |
| mhdr.msg_controllen = cmsglen; |
| |
| i = sendmsg(icmp_sock, &mhdr, *confirm); |
| } |
| *confirm = 0; |
| |
| return (cc == i ? 0 : i); |
| } |
| |
| /* |
| * parse_reply -- |
| * Print out the packet, if it came from us. This logic is necessary |
| * because ALL readers of the ICMP socket get a copy of ALL ICMP packets |
| * which arrive ('tis only fair). This permits multiple copies of this |
| * program to be run without having intermingled output (or statistics!). |
| */ |
| int |
| parse_reply(int *series, struct pingCtlTable_data *item, |
| struct msghdr *msg, int cc, void *addr, struct timeval *tv, |
| time_t timep, int uid, struct sockaddr_in6 *whereto, |
| int *rtt_addend, int options, int interval, int datalen, |
| int timing, int working_recverr, char *outpack, int *rtt, |
| int *ident, __u16 * acked, long *nreceived, long *nrepeats, |
| long *ntransmitted, long *nchecksum, long *nerrors, long *tmin, |
| long *tmax, long long *tsum, long long *tsum2, |
| int *confirm_flag, int *confirm, int *pipesize, |
| struct pingProbeHistoryTable_data *current_temp) |
| { |
| struct sockaddr_in6 *from = addr; |
| __u8 *buf = msg->msg_iov->iov_base; |
| struct cmsghdr *c; |
| struct icmp6_hdr *icmph; |
| int hops = -1; |
| |
| |
| for (c = CMSG_FIRSTHDR(msg); c; c = CMSG_NXTHDR(msg, c)) { |
| if (c->cmsg_level != SOL_IPV6 || c->cmsg_type != IPV6_HOPLIMIT) |
| continue; |
| if (c->cmsg_len < CMSG_LEN(sizeof(int))) |
| continue; |
| hops = *(int *) CMSG_DATA(c); |
| } |
| |
| |
| /* |
| * Now the ICMP part |
| */ |
| |
| icmph = (struct icmp6_hdr *) buf; |
| if (cc < 8) { |
| if (options & F_VERBOSE) |
| fprintf(stderr, "ping: packet too short (%d bytes)\n", cc); |
| return 1; |
| } |
| if (icmph->icmp6_type == ICMP6_ECHO_REPLY) { |
| if (icmph->icmp6_id != *ident) |
| return 1; |
| if (gather_statistics(series, item, (__u8 *) (icmph + 1), cc, |
| icmph->icmp6_seq, |
| hops, 0, tv, timep, rtt_addend, uid, options, |
| pr_addr(&from->sin6_addr, options), interval, |
| datalen, timing, outpack, rtt, acked, |
| nreceived, nrepeats, ntransmitted, nchecksum, |
| tmin, tmax, tsum, tsum2, confirm_flag, |
| confirm, pipesize, current_temp)) |
| return 0; |
| } else { |
| int nexthdr; |
| struct ip6_hdr *iph1 = (struct ip6_hdr *) (icmph + 1); |
| struct icmp6_hdr *icmph1 = (struct icmp6_hdr *) (iph1 + 1); |
| |
| /* |
| * We must not ever fall here. All the messages but |
| * * echo reply are blocked by filter and error are |
| * * received with IPV6_RECVERR. Ugly code is preserved |
| * * however, just to remember what crap we avoided |
| * * using RECVRERR. :-) |
| */ |
| |
| if (cc < 8 + sizeof(struct ip6_hdr) + 8) |
| return 1; |
| |
| if (memcmp(&iph1->ip6_dst, &(whereto->sin6_addr), 16)) |
| return 1; |
| |
| nexthdr = iph1->ip6_nxt; |
| |
| if (nexthdr == 44) { |
| nexthdr = *(__u8 *) icmph1; |
| icmph1++; |
| } |
| if (nexthdr == IPPROTO_ICMPV6) { |
| if (icmph1->icmp6_type != ICMP6_ECHO_REQUEST || |
| icmph1->icmp6_id != *ident) |
| return 1; |
| acknowledge(icmph1->icmp6_seq, acked, ntransmitted, |
| pipesize); |
| if (working_recverr) |
| return 0; |
| (*nerrors)++; |
| if (options & F_FLOOD) { |
| write(STDOUT_FILENO, "\bE", 2); |
| return 0; |
| } |
| printf("From %s: icmp_seq=%u ", |
| pr_addr(&from->sin6_addr, options), |
| icmph1->icmp6_seq); |
| } else { |
| /* |
| * We've got something other than an ECHOREPLY |
| */ |
| if (!(options & F_VERBOSE) || uid) |
| return 1; |
| printf("From %s: ", pr_addr(&from->sin6_addr, options)); |
| } |
| /* pr_icmph(icmph->icmp6_type, icmph->icmp6_code, ntohl(icmph->icmp6_mtu)); */ |
| } |
| |
| if (!(options & F_FLOOD)) { |
| if (options & F_AUDIBLE) |
| putchar('\a'); |
| putchar('\n'); |
| fflush(stdout); |
| } |
| return 0; |
| } |
| |
| |
| |
| #include <linux/filter.h> |
| void |
| install_filter(int icmp_sock, int *ident) |
| { |
| static int once; |
| static struct sock_filter insns[] = { |
| BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 4), /* Load icmp echo ident */ |
| BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 0, 1), /* Ours? */ |
| BPF_STMT(BPF_RET | BPF_K, ~0U), /* Yes, it passes. */ |
| BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 0), /* Load icmp type */ |
| BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP6_ECHO_REPLY, 1, 0), /* Echo? */ |
| BPF_STMT(BPF_RET | BPF_K, ~0U), /* No. It passes. This must not happen. */ |
| BPF_STMT(BPF_RET | BPF_K, 0), /* Echo with wrong ident. Reject. */ |
| }; |
| static struct sock_fprog filter = { |
| sizeof insns / sizeof(insns[0]), |
| insns |
| }; |
| int id; |
| |
| if (once) |
| return; |
| once = 1; |
| |
| /* |
| * Patch bpflet for current identifier. |
| */ |
| id = htons( *ident ); |
| insns[1] = |
| (struct sock_filter) BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, |
| id, 0, 1); |
| |
| if (setsockopt |
| (icmp_sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) |
| perror("WARNING: failed to install socket filter\n"); |
| } |
| |
| |
| /* |
| * pr_addr -- |
| * Return an ascii host address as a dotted quad and optionally with |
| * a hostname. |
| */ |
| static char * |
| pr_addr(struct in6_addr *addr, int options) |
| { |
| struct hostent *hp = NULL; |
| |
| if (!(options & F_NUMERIC)) |
| hp = gethostbyaddr((__u8 *) addr, sizeof(struct in6_addr), |
| AF_INET6); |
| |
| return hp ? hp->h_name : pr_addr_n(addr); |
| } |
| |
| static char * |
| pr_addr_n(struct in6_addr *addr) |
| { |
| static char str[64]; |
| inet_ntop(AF_INET6, addr, str, sizeof(str)); |
| return str; |
| } |