Logo Search packages:      
Sourcecode: s390-tools version File versions  Download package

ibmOSAMibUtil.c

/*
 * File...........: ibmOSAMibUtil.c
 * Author(s)......: Thomas Weber <tweber@de.ibm.com>
 * Copyright IBM Corp. 2002,2007
 *
 * History of changes:
 * 07/29 added '-x agentx_socket' parm to usage message
 *  
 * Collection of utility functions used by the MIB implementation 
 * module. 
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stddef.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include "ibmOSAMibUtil.h"
#include "ibmOSAMib.h"

/* ptr to interface information on this system */
extern IF_LIST* if_list;
extern int ifNumber;
extern TABLE_OID* oid_list_head;

/* proc file filedescriptor. opened in osasnmpd.c */
extern int proc_fd;




/**********************************************************************
 * str_to_oid_conv():
 *  This function converts an OID string in an OID u_long array used
 *  by ucd-snmp. 
 *  parameters:
 *  IN  char* uc_oid: OID string separated by dots  
 *  OUT oid*  ul_oid: OID u_long array
 *  returns: int count - number of OID identifiers found within OID 
 *                       string; 0 if OID string was invalid
 *********************************************************************/
int str_to_oid_conv ( char* uc_oid, oid* ul_oid )
{
  short valid  = TRUE;
  int   count = 0;
  char* pos_strt = uc_oid; 
  char* pos_end;
  
  /* got non-empty oid string */   
  if ( strlen( uc_oid ) > 0 )
    {
      do {  
          /* found a dot, skip it */
          if ( *pos_strt == '.' )
           {    
            pos_strt++; 
            if ( *pos_strt == '\0')   /* found ending dot - valid - */
              break;
           } 
         
          /* found no dot and but expected one, indicate invalid OID */  
        else if (count > 0)
            {
              valid = FALSE;
              break;
            } /* end if */

          /* convert oid digit into data type oid (unsigned long) */ 
          ul_oid[count] = (oid) strtoul( pos_strt, &pos_end, 10); 
 
          /* check result from conversion */         
          if (pos_strt == pos_end || ul_oid[count] == ULONG_MAX) 
            {
              valid = FALSE;
              break;
            }
        
          /* adjust to next OID digit */  
          pos_strt = pos_end;
          count++;          
         } 
      while ( *pos_end != '\0' && count < MAX_OID_LEN );               
    }
  else
    /* indicate invalid OID */
    valid = FALSE;

  /* if OID was valid, return number of OID identifiers */
  if (!valid)
    return 0;
  else 
    return count;

} /* end str_to_oid_conv() */


/**********************************************************************
 * oid_to_str_conv():
 *  This function converts a ucd-snmp OID u_long array into an OID        
 *  string separated by dots.
 *  parameters:
 *  IN  oid*    ul_oid: OID u_long array
 *  IN  size_t  length: OID length
 *  OUT char*   uc_oid: OID string including dots (no leading dot)   
 *  returns:  TRUE  -  conversion was successful                        
 *            FALSE -  conversion failed
 *********************************************************************/
int oid_to_str_conv (oid* ul_oid, size_t length, char* uc_oid )
{
  #define MAX_CHARS 50           /* size of buffer */
  int i;
  short  valid = TRUE;
  char   buffer[MAX_CHARS];      /* buffer used for conversion */

  /* got invalid OID length */
  if ( length != 0 && length <= MAX_OID_LEN )
    {
      /* init return string */      
      uc_oid[0] = '\0'; 

      for ( i=0; i < (int)length; i++)
        {
          /* convert and append OID digit to return string */ 
          if (i == 0)       
            sprintf( buffer, "%lu", ul_oid[i] );
          else 
            sprintf( buffer, ".%lu", ul_oid[i] );   
         
          strcat( uc_oid, buffer ); 
        } /* end for */
    }
  else
    /* indicate invalid OID */
    valid = FALSE;

  /* if OID conversion was successful, indicate success */
  return valid;

} /* end oid_to_str_conv() */
 

/**********************************************************************
 * init_oid_list():
 *  This function initializes the head of the linked list structure to
 *  maintain the IPAssists MIB information. It is called at subagent
 *  startup.
 *
 *  parameters:
 *  INOUT    none
 *  returns: TABLE_OID* - head of linked list (pseudo node)
 *           NULL       - if malloc() for head failed
 *
 *********************************************************************/
TABLE_OID* init_oid_list ()
{
  TABLE_OID* head;

  /* allocate list head */
  head = (TABLE_OID*) malloc( sizeof *head );

  if ( head != NULL )
    head->next = NULL;

  return head;

} /* init_oid_list() */


/**********************************************************************
 * search_oid():  
 *  This function searches the linked OID list for a given OID and
 *  returns a ptr to the element if it is an exact match, otherwise the 
 *  previous (smaller) OID in the list is returned.
 *                                   
 *  parameters:
 *  IN   oid*   s_oid      - Toplevel OID to search for 
 *  IN   size_t len        - length of this OID 
 *  IN   TABLE_OID*  lhead - ptr to list head
 *  OUT  TABLE_OID** curr  - ptr to entry in list      
 *  returns:  0 - exact match - OID exists in list
 *            1 - not found, curr point to possible insertion point 
 *           -1 - got unexpected return code from snmp_oid_compare()     
 *                                                            
 *********************************************************************/
int search_oid ( oid* s_oid, size_t len, TABLE_OID* lhead, TABLE_OID** curr  )
{

  /* loop through list and compare OIDs */
  /* fyi - snmp_oid_compare() is a function from the ucd-snmp agent extension API */
  for( *curr=lhead; (*curr)->next != NULL; *curr=(*curr)->next )    
    {
      switch
      ( snmp_oid_compare( s_oid, len, (*curr)->next->pObjid, 
                      (*curr)->next->length )) 
      {
      case  0:      /* exact OID match - curr->next points to entry */
          *curr = (*curr)->next;
        return OID_FOUND;
          break;
      case  1:      /* search OID still greater - goto next entry */
        break;
      case -1:      /* next entry is greater than search OID */
        return OID_NOT_FOUND;   
        break;
      default:      /* unexpected return code from snmp_oid_compare */
        return UNEXP_ERROR; 
      } /* end switch */

    } /* end for */

  /* we're at the head or the end of linked list */
  /* curr points to head or last element in list, good insertion points */
  return OID_NOT_FOUND;
  
} /* search_oid() */


/**********************************************************************
 * search_top_oid():  
 *  This function searches for a fully qualified OID a matching Toplevel  
 *  OID from the linked list.
 *  It returns a pointer to the element if it is an exact match. 
 *  Otherwise the return OID is set to NULL.
 *                                   
 *  parameters:
 *  IN   oid*   s_oid      - Fully qualified OID 
 *  IN   size_t len        - length of this OID 
 *  IN   TABLE_OID*  lhead - ptr to list head
 *  OUT  TABLE_OID** curr  - ptr to entry in list      
 *  returns:  0 - exact match - appropriate Toplevel OID found
 *            1 - not found, curr set to NULL 
 *           -1 - got unexpected return code from snmp_oid_compare()     
 *                                                            
 *********************************************************************/
int search_top_oid ( oid* s_oid, size_t len, 
                 TABLE_OID* lhead, TABLE_OID** curr  )
{

  /* loop through list and compare OIDs */
  /* snmp_oid_compare() is a taken from the ucd-snmp agent extension API */
  for( *curr=lhead; (*curr)->next != NULL; *curr=(*curr)->next )    
    {
      /* fully qualified OID must be greater than our Toplevel OID */
      if ( len > (*curr)->next->length ) {

      switch
        ( snmp_oid_compare( s_oid, (*curr)->next->length , 
                        (*curr)->next->pObjid, (*curr)->next->length )) 
        {
        case  0:      /* exact OID match - curr->next points to entry */
          *curr = (*curr)->next;
          return OID_FOUND;
          break;
        case  1:      /* search OID still greater - goto next entry */
          break;
        case -1:      /* next entry is greater than search OID */
          *curr = NULL;
          return OID_NOT_FOUND;   
          break;
        default:      /* unexpected return code from snmp_oid_compare */
          *curr = NULL;
          return UNEXP_ERROR; 
      } /* end switch */

      } /* end if */

    } /* end for */


  /* we're at the head or the end of linked list */
  /* curr points to head or last element in list */
  *curr = NULL;
  return OID_NOT_FOUND;
  
} /* search_top_oid() */


/**********************************************************************
 * oid_insert_after():  
 *  This function initializes and adds a new entry to the OID linked   
 *  list after entry pre_oid.
 *                                   
 *  parameters:
 *  IN   oid* i_oid         - Toplevel OID to add
 *  IN   size_t len         - length of this OID
 *  IN   TABLE_OID* pre_oid - add Toplevel OID after this entry           
 *  returns: TABLE_OID* - PTR to newly inserted entry
 *           NULL       - if malloc() for new entry failed
 *********************************************************************/
TABLE_OID* oid_insert_after ( oid* i_oid, size_t len, TABLE_OID* pre_oid )
{
  TABLE_OID *new_entry;

  new_entry = (TABLE_OID*) malloc( sizeof *new_entry );
  if ( new_entry == NULL )
    return NULL;

  /* allocate head for index list */
  new_entry->ind_list = init_ind_list();
  if ( new_entry->ind_list == NULL )
    { 
      free ( new_entry );   
      return NULL;
    } /* end if */

  /* assign OID and length */
  new_entry->pObjid = i_oid;  
  new_entry->length = len;
  new_entry->var13ptr = NULL;

  /* insert */
  new_entry->next = pre_oid->next;
  pre_oid->next = new_entry;

  return new_entry;
 
} /* oid_insert_after()*/


/**********************************************************************
 * delete_oid():  
 *  This function deletes a Toplevel OID entry from the Toplevel OID 
 *  linked list.
 *                                   
 *  parameters:
 *  IN       oid         *d_oid   - Toplevel OID to delete
 *  IN       size_t      len      - length of this OID 
 *  IN       TABLE_OID   *lhead   - head of Toplevel OID linked list
 *  returns: none
 *                                                            
 *********************************************************************/
int delete_oid( oid* d_oid, size_t len, TABLE_OID* lhead )
{
  TABLE_OID *curr, *del_entry;

  /* loop through list and compare OIDs  */
  /* snmp_oid_compare() is taken from the ucd-snmp agent extension API */
  for( curr=lhead; curr->next != NULL; curr=curr->next )    
    {
      if ( snmp_oid_compare( d_oid, len, curr->next->pObjid, 
                       curr->next->length ) == 0 ) 
      {
        del_entry = curr->next;
        curr->next = curr->next->next;
        free( del_entry->pObjid );
        free( del_entry->var13ptr );

        /* index list not empty, free index list first */
        if ( del_entry->ind_list->next != NULL )
          delete_index( del_entry->ind_list, 0, IND_LIST );

        /* free index list head */
        free( del_entry->ind_list );

        free( del_entry );
        break;
      } /* end if */
    } /* end for */
  
  return 0; 
 
} /* delete_oid() */


/**********************************************************************
 * clear_oid_list():
 *  This function removes all index entries from the Toplevel OID  
 *  linked list.            
 *
 *  parameters:
 *  IN       TABLE_OID   *lhead   - head of Toplevel OID linked list
 *  returns: none
 *
 *********************************************************************/
int clear_oid_list( TABLE_OID* lhead )
{
  TABLE_OID *curr, *clr_entry;
  
  /* loop through list and clean entries */
  for( curr=lhead; curr->next != NULL; curr=curr->next )
    {
       clr_entry = curr->next;
       
       /* index list not empty, free index list first */
       if ( clr_entry->ind_list->next != NULL )
          delete_index( clr_entry->ind_list, 0, IND_LIST );

    } /* end for */

  return 0;

} /* clear_oid_list() */

/**********************************************************************
 * init_ind_list():  
 *  This function initializes the head of the linked list structure to
 *  maintain index portion information. This is called when a new
 *  Toplevel OID is inserted in the Toplevel OID linked list.  
 *                                   
 *  parameters:
 *  INOUT    none 
 *  returns: TABLE_OID* - head of linked list (pseudo node)
 *           NULL       - if malloc() for head failed
 *                                                            
 *********************************************************************/
REG_INDICES* init_ind_list ( )
{
  REG_INDICES* ihead;

  /* allocate list head */
  ihead = (REG_INDICES*) malloc( sizeof *ihead );

  if ( ihead != NULL )  
    ihead->next = NULL;

  return ihead; 
 
} /* init_ind_list() */


/**********************************************************************
 * index_insert_after():  
 *  This function adds a new index entry to the index linked list   
 *                                   
 *  parameters:
 *  IN   char* i_index        - index to add
 *  IN   int   ifIndex        - appropriate IF-MIB ifIndex 
 *  IN   REG_INDICES* pre_ind - add index after this entry           
 *  returns: REG_INDICES*     - PTR to newly inserted entry
 *           NULL             - if malloc() for new entry failed
 *********************************************************************/
REG_INDICES* index_insert_after ( char* i_index, int ifIndex,  
                          REG_INDICES* pre_ind )
{
  REG_INDICES *new_entry;

  new_entry = (REG_INDICES*) malloc( sizeof *new_entry );
  if ( new_entry == NULL )
    return NULL;

  /* assign index and ifIndex */
  new_entry->full_index = i_index;  
  new_entry->ifIndex = ifIndex;

  /* insert */
  new_entry->next = pre_ind->next;
  pre_ind->next = new_entry;

  return new_entry;
 
} /* index_insert_after()*/


/**********************************************************************
 * delete_index():  
 *  This function deletes an entry in the index linked list indexed by
 *  ifIndex or removes the whole index linked list if desired.
 *                                   
 *  parameters:
 *  IN       REG_INDICES *lhead   - head of index linked list
 *  IN       int         ifIndex  - ifIndex to remove from list
 *  IN       int         del_type - deletion type (IF_ENTRY/IND_LIST) 
 *  returns: none
 *                                                            
 *********************************************************************/
int delete_index( REG_INDICES* lhead, int ifIndex, int del_type )
{
  REG_INDICES *curr, *del_entry;

  if (del_type == IF_ENTRY ) {
    
    /* loop through list and compare ifIndex */
    curr = lhead;    
    while ( curr->next != NULL )
      {
      if ( curr->next->ifIndex == ifIndex ) {
        del_entry = curr->next;
        curr->next = curr->next->next;
        free( del_entry->full_index );
        free( del_entry );
      } /* end if */
      else
        curr=curr->next;
      } /* end while */
  }
  else if ( del_type == IND_LIST ) {
    
    /* loop through list delete one entry after another */
    curr = lhead;
    while ( curr->next !=NULL )
      {
      del_entry = curr->next;
      curr->next = curr->next->next;
      free( del_entry->full_index );
      free( del_entry );
      } /* end while */
  } /* end if */

  return 0; 
 
} /* delete_index() */


/**********************************************************************
 * search_index():  
 *  This function searches the linked index list for a given index and
 *  returns a ptr to the element if it is an exact match, otherwise the 
 *  previous (smaller) index in the list is returned.
 *                                   
 *  parameters:
 *  IN   index*       s_index    - index to search for 
 *  IN   REG_INDICES* lhead  - ptr to list head
 *  OUT  REG_INDICES** curr  - ptr to entry in list      
 *  returns:  0 - exact match - index exists in list
 *            1 - not found, curr point to possible insertion point 
 *                                                            
 *********************************************************************/
int search_index ( char* s_index, REG_INDICES* lhead, REG_INDICES** curr  )
{

  int  oid_len1, oid_len2;
  oid  ind_oid1[MAX_OID_LEN];           /* temporary ucd-snmp oids */
  oid  ind_oid2[MAX_OID_LEN];

  /* loop through list and compare indices */
  for( *curr=lhead; (*curr)->next != NULL; *curr=(*curr)->next )    
    {
      oid_len1 = str_to_oid_conv( (char*) s_index, ind_oid1 );
      oid_len2 = str_to_oid_conv( (char*) (*curr)->next->full_index,
                          ind_oid2 );

      switch
        ( snmp_oid_compare( ind_oid1, oid_len1, ind_oid2, oid_len2 ) )
        {
        case  0:      /* exact index match - curr->next points to entry */
          /* exact index match - curr-> points to entry */
          *curr = (*curr)->next;
          return INDEX_FOUND;
          break;
        case  1:      /* search index still greater - goto next entry */
          continue;
          break;
        case -1:      /* next entry is greater than search index */
          /* next entry is greater than search index */
          return INDEX_NOT_FOUND; 
          break;
        default:      /* unexpected return code from snmp_oid_compare */
          return UNEXP_ERROR;
        } /* end switch */
    } /* end for */

  /* we're at the head or the end of linked list */
  /* curr points to head or last element in list, good insertion points */
  return INDEX_NOT_FOUND;
  
} /* search_index() */ 


/**********************************************************************
 * register_tables()
 *  Parses MIB information returned by IPAssists and registers OID 
 *  suffixes with ucd-snmp subagent driving code using the REGISTER_MIB
 *  macro. Also puts data from the MIB information returned by IPAssists
 *  into local data structures to maintain index information.
 *  
 *  This functions only maps the header of the IPAssists MIB info.
 *  The table data is parsed through the void mib_data_ptr.
 *
 *  IPAssists MIB information layout:
 *  
 *  header information:
 *  INOUT int request  
 *  INOUT int interface number/ifIndex
 *  INOUT int return code from IPAssists
 *  INOUT int IPAssists version
 *  INOUT int sequence number of this response
 *  OUT   int number of returned table information for that interface
 *  
 *  Repeated information:
 *  OUT string Toplevel OID for a table (including dots)
 *  OUT int    number of OID suffixes for that table
 *    
 *  Repeated OID suffix information for a single table and every index: 
 *  OUT int    object access type
 *  OUT int    object data type
 *  OUT string OID suffix for object
 *  OUT string OID index portion                                 
 *                                                                   
 *  parameters:
 *  IN  struct table:     MIB information returned by IPAssists 
 *  IN  TABLE_OID* lhead: head of toplevel OID linked list        
 *  returns: 0 - SUCCESS
 *          -1 - Registration not performed due to error; 
 *               an appropriate log entry is made                        
 *                                                                             
 *********************************************************************/
int register_tables ( void* mib_data,
                      TABLE_OID* lhead ) 
{ 
  int  i, j, suf_def, suf_cnt, src_oid, src_ind;   
  int  oid_len, oid_acc, oid_typ;         

  oid  t_oid[MAX_OID_LEN];           /* temporary ucd-snmp oid */
  oid  *top_oid;
  char *new_index;                         
  char toid_str[MAX_OID_STR_LEN];
  char time_buf[TIME_BUF_SIZE];   /* date/time buffer */
  
  IPA_CMD_REG *mib_data_hdr;      /* ptr to IPAssists hdr information */   
  char        *last_suffix;       /* last suffix in suffix list */
  void        *mib_data_ptr;      /* ptr to parse IPAssists MIB info */

  TABLE_OID      *oid_ptr, *ins_oid = NULL; /* ptr into Toplevel OID linked list */
  REG_INDICES    *ind_ptr, *ins_ind; /* ptr into index linked list */
 
  /* ptr to ucd-snmp variable13 structs that will contain the suffix
     information registered with subagent driving code */
  struct variable13 *table_vars, *new_area;

  /* point to beginning of MIB information (header) */
  mib_data_hdr = ( IPA_CMD_REG* ) mib_data;    

  /* set parse ptr behind header information; first Toplevel OID */ 
  mib_data_ptr = ( char* ) mib_data_hdr + sizeof( IPA_CMD_REG ); 

  /************************************/                                       
  /* loop through returned table data */
  /************************************/
  for ( i=0; i < mib_data_hdr->table_cnt; i++ ) {

    /****************************************************/
    /* get Toplevel oid that we want to register under  */
    /****************************************************/
    /* adjust parse ptr to next Toplevel OID (skip padding) */      
    mib_data_ptr = (int*) (PTR_ALIGN4(mib_data_ptr));   
    
    /* convert string OID to ucd-snmp oid type */
    strncpy( toid_str, (char*) mib_data_ptr, MAX_OID_STR_LEN ); 
    toid_str[ MAX_OID_STR_LEN-1 ] = '\0';
    oid_len = str_to_oid_conv( (char*) mib_data_ptr, t_oid ); 
    if ( oid_len == 0 ) {
      get_time( time_buf );       
      snmp_log( LOG_ERR, 
            "%s register_tables(): str to oid conversion failed "
            "(Toplvl OID) .%s\nOSA Subagent MIB information may be incomplete!\n"
            ,time_buf, toid_str ); 
      return -1;
    } /* end if */

    /* save Toplevel OID in order to register it later */
    top_oid = (oid*) malloc ( oid_len * sizeof(oid) );
    if ( top_oid == NULL ) {
      get_time( time_buf );       
      snmp_log( LOG_ERR, 
            "%s register_tables(): malloc() for variable top_oid failed\n"
            "register_tables(): Toplevel OID .%s\n"
            "OSA Subagent MIB information may be incomplete!\n", 
            time_buf, toid_str ); 
      return -1;
    } /* end if */
    memcpy( top_oid, t_oid, oid_len * sizeof(oid) );
    
    /* is retrieved Toplevel OID already in linked list? */
    src_oid = search_oid( top_oid, oid_len, lhead, &oid_ptr );
    if ( src_oid == UNEXP_ERROR ) { 
      get_time( time_buf );       
      snmp_log( LOG_ERR, 
            "%s register_tables(): Unexpected return code from"
            " function search_oid() for Toplevel OID .%s\n"
            "OSA Subagent MIB information may be incomplete!\n", 
            time_buf, toid_str );
      free( top_oid ); 
      return -1;
    }

    /* put this Toplevel OID into the linked list, if OID was not found */
    else if ( src_oid == OID_NOT_FOUND ) { 
      ins_oid = oid_insert_after( top_oid, oid_len, oid_ptr );
      if ( ins_oid == NULL ) {
      get_time( time_buf );         
      snmp_log( LOG_ERR, 
              "%s register_tables(): malloc() for new entry in "
              "OID list failed for Toplevel OID .%s\nOSA Subagent "
              "MIB information may be incomplete!\n", time_buf, toid_str );
      free( top_oid ); 
      return -1;
      } /* end if */
    } /* end if */
    /* if OID was found, set insert OID to exact match OID */
    else   /* src_oid == OID_FOUND */
      ins_oid = oid_ptr;  
    
    /****************************************************************/
    /* add suffixes to variable_x structure for macro REGISTER_MIB  */
    /****************************************************************/
    last_suffix = NULL;                  /* initialize compare ptr */
    table_vars = NULL;                   /* initialize variable_x ptr */ 
    suf_def = 0;                         /* number of suffixes */
    
    /* point to suffix entries */
    mib_data_ptr += (strlen(mib_data_ptr)+1);
    mib_data_ptr = (int*) (PTR_ALIGN4(mib_data_ptr));

    /* get number of attached suffix OIDs */
    suf_cnt = *((int*) mib_data_ptr);       

    /* loop through suffix list */    
    for ( j=0;j < suf_cnt; j++ ) 
      {
      /* adjust parse ptr to access type 
         (align pointer if it follows a string) */ 
      if ( j == 0 )
        mib_data_ptr += sizeof( int );    
      else
        {
          mib_data_ptr += (strlen(mib_data_ptr)+1);
          mib_data_ptr = (int*) (PTR_ALIGN4(mib_data_ptr));
        } /* end if */

      /* save object access type for registering later */
      oid_acc = *((int*) mib_data_ptr); 

      /* adjust ptr and save object data type for registering later */
      mib_data_ptr += sizeof( int );    
      oid_typ = *((int*) mib_data_ptr); 

      /* adjust ptr to OID suffix string */
      mib_data_ptr += sizeof( int );    
        
        /* need to register suffixes only, if I have a new Toplevel OID */
        if ( src_oid == OID_NOT_FOUND ) {     

        /* init last_suffix here, if loop entered the first time */
        if ( j==0 )
          last_suffix = (char*) mib_data_ptr;         

        /* check wether last and current OID suffixes match */
        /* yes-don't need to register suffix again, goto register index portion */
        /* no -add suffix to variable_x list */
        if ( (strcmp( last_suffix, (char*) mib_data_ptr ) !=0)  || j==0 )
          {
            suf_def++;      /* increase count of suffix definitions */
            last_suffix = (char*) mib_data_ptr; /* save suffix */
            
            /* allocate one entry within variable_x struct */
            new_area = (struct variable13*) 
                      realloc( table_vars, suf_def * sizeof( struct variable13));
            if ( new_area == NULL )
            {
              get_time( time_buf ); 
              snmp_log( LOG_ERR, "%s register_tables(): "
                      "realloc() for variable_x structure failed\n"
                      "register_tables(): for Toplevel OID .%s\n"
                      "OSA Subagent MIB information may be incomplete!\n", 
                      time_buf, toid_str );
             
              /* remove all memory for this Toplevel OID allocated so far */ 
              free(table_vars);
              delete_oid( ins_oid->pObjid, ins_oid->length, lhead );
              return -1;
            } /* end if */
              else
            /* reassign table_vars */
                table_vars = new_area;

            /* convert suffix OID string to ucd-snmp oid type */
            oid_len = str_to_oid_conv( (char*) mib_data_ptr, t_oid ); 
            if ( oid_len == 0 ) {
            get_time( time_buf );      
            snmp_log( LOG_ERR, "%s register_tables(): "
                    "suffix str to oid conversion failed "
                    "for Toplevel OID .%s\nOSA Subagent MIB information may "
                    "be incomplete!\n", time_buf, toid_str );

            /* remove all memory for this Toplevel OID allocated so far */ 
            free(table_vars);
            delete_oid( ins_oid->pObjid, ins_oid->length, lhead );
            return -1;
            } /* end if */
               
              /*******************************/
            /* set up variable_x structure */
            /*******************************/
            table_vars[suf_def-1].magic = 0;            /* magic is not used */
                 
            if ( oid_typ == IPA_DISPLAYSTR )            /* set object type */
            table_vars[suf_def-1].type = ASN_OCTET_STR;
            else
            table_vars[suf_def-1].type = oid_typ;     

            if ( oid_acc == IPA_WRONLY )                /* have no WRITE ONLY */
            table_vars[suf_def-1].acl =  RWRITE;      /* set to type RWRITE */
              else
            table_vars[suf_def-1].acl =  oid_acc;     /* set given object type */

            if ( oid_typ == IPA_DISPLAYSTR )       /* set callback functions */
            table_vars[suf_def-1].findVar = var_DisplayStr;
            else 
            table_vars[suf_def-1].findVar = var_ibmOSAMib;

            table_vars[suf_def-1].namelen = oid_len;    /* OID suffix len */
            if ( oid_len <= SUFFIX_MAXLEN )             /* set OID suffix */ 
               memcpy( table_vars[suf_def-1].name, t_oid, oid_len * sizeof( oid ));
            else 
            {
              get_time( time_buf ); 
              snmp_log( LOG_ERR, 
                      "%s register_tables(): OID suffix length exceeded "
                      "for Toplevel OID .%s\nSuffix OID length %d\n"
                      "OSA Subagent MIB information may be incomplete!\n",
                      time_buf, toid_str, oid_len );

              /* remove all memory for this Toplevel OID allocated so far */ 
              free(table_vars);
              delete_oid( ins_oid->pObjid, ins_oid->length, lhead );
              return -1;
            } /* end if */
          } /* end if  */
      } /* end if register_suffix part */

        /****************************************************************/
      /* add index to index linked list under this Toplevel OID entry */
        /****************************************************************/

        /* adjust ptr to index portion */
      mib_data_ptr = (char*) (mib_data_ptr + (strlen(mib_data_ptr)+1));
      
        /* search index list for this index */
      src_ind = search_index( (char*) mib_data_ptr, ins_oid->ind_list, &ind_ptr );

        /* if index is not found in the linked list, add index */
        if ( src_ind == INDEX_NOT_FOUND ) {
        new_index = (char*) malloc( strlen( (char*) mib_data_ptr ) + 1 ); 
        if ( new_index == NULL ) {
          get_time( time_buf );       
          snmp_log( LOG_ERR, "%s register_tables(): "
                  "malloc() for new index entry failed\n"
                  "register_tables(): for Toplevel OID .%s\n"
                  "OSA Subagent MIB information may be incomplete!\n", 
                  time_buf, toid_str); 
          if ( src_oid == OID_NOT_FOUND ) {
            free(table_vars);
            delete_oid( ins_oid->pObjid, ins_oid->length, lhead );
          }
          return -1;
        } /* end if */

        strcpy( new_index, (char*) mib_data_ptr );
        ins_ind = index_insert_after( new_index,
                              mib_data_hdr->ioctl_cmd.ipa_cmd_hdr.ifIndex,
                              ind_ptr );
      } /* end if */      

      } /* end for (j) */

    /* new Toplevel OID?: yes, then register with agent to add this table */
    /* note - register_mib() is taken from the ucd-snmp agent extension API */
    
    if ( src_oid == OID_NOT_FOUND )  
      {         
        if ( register_mib( "ibmOSAMib",(struct variable*) table_vars, 
                     sizeof(struct variable13), suf_def,
                     top_oid, ins_oid->length ) != MIB_REGISTERED_OK )
        { 
          get_time( time_buf );     
          snmp_log( LOG_ERR, "%s register_tables(): "
                  "API function register_mib() failed\n"
                  "register_tables(): for Toplevel OID .%s\n"
                      "OSA Subagent MIB information may be incomplete!\n",
                  time_buf, toid_str );
          /* remove all memory for this Toplevel OID allocated so far */ 
          free(table_vars);
          delete_oid( ins_oid->pObjid, ins_oid->length, lhead );
          return -1;
        } /* end if */
        else
          {
          get_time( time_buf );     
          snmp_log( LOG_INFO, "%s registered Toplevel OID .%s\n",
                      time_buf, toid_str );
          } /* end if */
      } /* end if */

    /* save variable_x ptr to free allocated memory later, if needed */
    ins_oid->var13ptr = table_vars; 
    
    /* adjust ptr to next Toplevel OID */
    mib_data_ptr = (char*) (mib_data_ptr + (strlen(mib_data_ptr)+1));
    
  } /* end for (i) */
  
  return 0;
  
} /* end register_tables() */
 

/************************************************************************
 * header_osa_table()
 * Compare 'name' to vp->name for the best match or an exact match.
 * Store result OID in 'name', including the index that matches best.
 * Return matching ucd-snmp ifIndex to caller.
 * 
 * parameters:
 * IN    struct variable *vp      - ptr to registered subagent MIB data
 * INOUT oid             *name    - fully instantiated OID name
 * INOUT size_t          *length  - length of this OID
 * IN    int             exact    - TRUE if an GET match is desired
 * OUT   size_t          *var_len - hook for size of returned data type
 * IN    WriteMethod     **write_method - hook for write method (UNUSED)
 * IN    TABLE_OID       *lhead   - ptr to Toplevel OID list head
 *
 * returns:
 *   ifIndex              - ifIndex in this OID 
 *   -1 (MATCH_FAILED)    - no suitable match found
 *
 ************************************************************************/
int header_osa_table( struct variable *vp, oid *name, size_t *length,
                  int exact, size_t *var_len, 
                  WriteMethod **write_method, TABLE_OID *lhead )
{
  int interface = -1;
  int   i, res, conv;
  size_t  index_len;              /* length of index portion */
  oid newname[MAX_OID_LEN];       /* temporary return OID */
  oid buffer[MAX_OID_LEN];        /* temporary converion buffer */
  char name_index[MAX_OID_STR_LEN]; 
  char time_buf[TIME_BUF_SIZE];   /* date/time buffer */
  
  /* ptr into OID and index linked lists */
  TABLE_OID   *ptr_oid;
  REG_INDICES *ptr_ind;

  int found_OID = FALSE;
 
  /* some debugging calls */
  DEBUGMSGTL(("ibmOSAMib-Subagent", "header_osa_table: "));
  DEBUGMSGOID(("ibmOSAMib-Subagent", name, *length));
  DEBUGMSG(("ibmOSAMib-Subagent"," exact=%d\n", exact)); 

  /* OID compare                      */
  /* set 'res' to -1  name < vp->name */
  /*               1  name > vp->name */
  /*               0  exact match     */ 
  for ( i=0, res=0; (i < (int) vp->namelen) && (i < (int) (*length)) && !res; i++ )
    {
      if ( name[i] != vp->name[i] ) {
      if ( name[i] < vp->name[i] )
        res = -1;
      else 
        res = 1;
      } /* end if */
    } /* end for */      

  DEBUGMSG(("ibmOSAMib-Subagent", " snmp_oid_compare: %d\n", res));
 
  /* (GETNEXT AND search OID still greater) OR (GET AND not-exact OIDs) */
  /* yes - indicate match failed */ 
  if ( (!exact && (res > 0)) || (exact && (res != 0)) ) {
    if (var_len)
      *var_len = 0;
     return MATCH_FAILED;
  } /* end if */
 
  /* init temporary return OID */
  memset(newname, 0, sizeof(newname));

  /******************************************/
  /* handle GET requests with matching OIDs */
  /******************************************/
  if ( exact && res == 0 )
    {
       /* got a too short OID */
      if ( (*length) <=  vp->namelen ) {
      if (var_len)
        *var_len = 0;
      return MATCH_FAILED;
      }
      else 
      /* determine length of attached index */
      index_len = (int) (*length) - (int) vp->namelen;
      
      DEBUGMSG(("ibmOSAMib-Subagent", 
              " header_osa_table - GET index length: %zd\n", index_len));
 
      /* search our internal linked list for a matching Toplevel OID */
      res = search_top_oid ( (oid*) vp->name, (size_t) vp->namelen,
                       lhead, &ptr_oid );
      
      /* found a matching Toplevel OID, now look for index portion */
      if ( res == OID_FOUND ) {
      DEBUGMSGOID(("ibmOSAMib-Subagent:header_osa_table - Toplevel OID found", 
                 ptr_oid->pObjid, ptr_oid->length));

      /* convert index portion to string */
      conv = oid_to_str_conv ( (oid*) &name[vp->namelen], 
                         index_len, name_index );
      DEBUGMSG(("ibmOSAMib-Subagent"," index portion=%s\n", name_index));

      if (conv == TRUE) {
        res = search_index ( name_index,
                         (REG_INDICES*) ptr_oid->ind_list, &ptr_ind );

        /* found a matching index, OID for GET request exists! */
        if ( res == INDEX_FOUND ) {
          DEBUGMSG(("ibmOSAMib-Subagent"," index found in linked list\n"));

          /* return appropriate ifIndex responsible for that OID */
          interface = ptr_ind->ifIndex;
            
          /* set up return OID */
          memmove( newname, name, (*length) * sizeof(oid) );
          
          found_OID = TRUE;
        } /* end if */
      } /* end if */
      } /* end if */
    } /* end if */

  /***************************/
  /* handle GETNEXT requests */
  /***************************/
  else if ( !exact && res <= 0 )
    {
      /* OID too short or switched to next suffix */
      /* adjust length and attach first index     */
      if ( (int) (*length) <= (int) vp->namelen || res < 0 )
      {
        DEBUGMSG(("ibmOSAMib-Subagent", 
                  " GETNEXT - length <= vp->namelen OR snmp_oid_compare < 0"));
        /* search our internal linked list for a matching Toplevel OID */
        res = search_top_oid ( (oid*) vp->name, vp->namelen, lhead, &ptr_oid );
      
        /* found a matching Toplevel OID, now look for index portion */
        if ( res == OID_FOUND ) {
          DEBUGMSGOID(("ibmOSAMib-Subagent:header_osa_table - Toplevel OID found", 
                   ptr_oid->pObjid, ptr_oid->length));
          
          /* set up return OID */
          memmove( newname, vp->name, (int) vp->namelen * sizeof(oid) );
          *length = vp->namelen;
          
          /* retrieve first index under this Toplevel OID and attach to newname */
          if ( ptr_oid->ind_list->next != NULL ) {
            index_len = str_to_oid_conv ( ptr_oid->ind_list->next->full_index, 
                                  buffer );

            if ( index_len != 0 && ( (vp->namelen + index_len) <= MAX_OID_LEN ) ) {
            memmove ( &newname[vp->namelen], buffer, index_len * sizeof(oid) );
            *length = *length + index_len;
            DEBUGMSG(("ibmOSAMib-Subagent"," index portion to attach=%s\n"
                    ,ptr_oid->ind_list->next->full_index ));

            /* return appropriate ifIndex responsible for that OID */
            interface = ptr_oid->ind_list->next->ifIndex;
      
            found_OID = TRUE;
            } 
            else
            {
              get_time( time_buf );       
            snmp_log( LOG_ERR, "%s header_osa_table(): "
                    "(GETNEXT-1) index list corrupted\n"
                        "OSA Subagent MIB information may be incomplete!\n", 
                    time_buf );
            } /* end if */    
          } /* end if */
        } /* end if */
      } 
      /* 'true' GETNEXT case */
      else  
      {
        DEBUGMSG(("ibmOSAMib-Subagent", 
                " GETNEXT - length > vp->namelen"));
        /* search our internal linked list for a matching Toplevel OID */
        res = search_top_oid ( (oid*) name, (int) (*length), 
                         lhead, &ptr_oid );

        /* found a matching Toplevel OID, now look for index portion */
        if ( res == OID_FOUND ) {
          DEBUGMSGOID(("ibmOSAMib-Subagent: "
                   "header_osa_table - Toplevel OID found", 
                   ptr_oid->pObjid, ptr_oid->length));
          
          /* search the index attached to 'name' in the index list */
          /* determine length of attached index and convert to a string */
          index_len = (int) (*length) - (int) vp->namelen;
          conv = oid_to_str_conv ( (oid*) &name[vp->namelen], 
                             index_len, name_index );

          if (conv == TRUE) {
            res = search_index ( name_index, 
                           (REG_INDICES*) ptr_oid->ind_list, &ptr_ind );
            
            /* next index is the one we're looking for */
            /* if next index is NULL; return MATCH FAILED(goto next suffix) */
            if( ptr_ind->next != NULL ) {
            index_len = str_to_oid_conv( ptr_ind->next->full_index, buffer);

            if ( index_len != 0 && ( (vp->namelen + index_len) <= MAX_OID_LEN ) ) {
              DEBUGMSG(("ibmOSAMib-Subagent"," index portion to attach=%s\n"
                      ,ptr_ind->next->full_index ));
              
              /* set up return OID */
              *length = vp->namelen;
              memmove( newname, name, vp->namelen * sizeof(oid) );
              memmove( &newname[vp->namelen], buffer, index_len * sizeof(oid) );
              *length = *length + index_len;

              /* return appropriate ifIndex responsible for that OID */
              interface = ptr_ind->next->ifIndex;
      
              found_OID = TRUE;
            } /* end if */
            else
            {
              get_time( time_buf ); 
              snmp_log( LOG_ERR, "%s header_osa_table(): "
                      "(GETNEXT-2) index list corrupted\n"
                      "OSA Subagent MIB information may be incomplete!\n", 
                      time_buf );
            } /* end if */
            } /* end if */
          } /* end */
        } 
        else
        {
          get_time( time_buf );         
          snmp_log( LOG_ERR, "%s header_osa_table(): "
                  "(GETNEXT-2) Toplevel OID not found\n"
                  "OSA Subagent MIB information may be incomplete!\n", 
                  time_buf );
        } /* end if */
      } /* end if - handle GETNEXT requests */
    }

  /* return MATCH_FAILED, if no appropriate OID was found */
  if ( !found_OID )
    {
      if (var_len)
      *var_len = 0;
      return MATCH_FAILED;
    }
  else
    {
      /* finalize OID to be returned */
      memmove(name, newname, (*length) * sizeof(oid));
      if (write_method)
      *write_method = 0;
      if (var_len)
      *var_len = sizeof(long);   /* default data type long */

      return interface;
    } /* end if */

} /* end header_osa_table */

/************************************************************************
 * update_mib_info()
 * Whenever a network interface appears or disappears the MIB and/or 
 * interface information has to be updated, this fuction is called.
 *
 * parameters:
 *   none
 * returns:
 *   none
 *
 ************************************************************************/
void update_mib_info ()
{
      TABLE_OID *mib_info = oid_list_head;  

      char time_buf[TIME_BUF_SIZE];  /* date/time buffer */
  
      int i, retc,
            sd,           /* socket descriptors */
            error_code,       /* used to save errno */  
            if_num,           /* number of network interfaces */   
            osaexp_num;       /* number of OSA-E devices */

      struct ifreq ifr;             /* request structure for ioctl */
      IPA_CMD_REG* ipa_reg_mib;     /* structure for IPA REGISTER MIB command header */ 
      IF_LIST*     tmp_list;        /* temporary interfaces list */
      char*        buffer;          /* a data buffer */


      /* Retrieve ifNumber/ifIndex/ifDescr newly from IF-MIB for all interfaces */
      /* retrieve data in temporary list first */
      if_num = query_IF_MIB( &tmp_list );
      if ( if_num < 0 )
      {
            get_time( time_buf );        
            snmp_log( LOG_ERR, "%s update_mib_info(): "
                    "could not get interface info from IF-MIB\n"
                    "update_mib_info(): check previous messages for more details\n"
                    "update_mib_info(): keeping original interface lists\n",
                    time_buf );
            return; 
      }

      /* query OSA-E device driver for OSA-E devices 
       * and mark them in IF-MIB interface list 
       * */
      osaexp_num = query_OSA_EXP( &tmp_list, if_num );
      if ( osaexp_num < 0 )
      {
            get_time( time_buf );
            fprintf( stderr, "%s update_mib_info(): "
                   "OSA-E device driver query interface ioctl() "
                   "failed\nupdate_mib_info(): going to stop osasnmpd daemon\n"
                   "update_mib_info(): check subagent logfile for more details\n"
                   "update_mib_info(): sending termination signal to osasnmpd...\n",
                   time_buf );
            exit(-1);
      }
      else if ( osaexp_num == 0 )
      {
            get_time( time_buf );      
            snmp_log( LOG_ERR, "%s update_mib_info(): "
                    "no or bad OSA Express devices reported"
                    " - continue processing\n"
                    "update_mib_info(): "
                    "if available, see previous message for reason\n" 
                    "update_mib_info(): freeing interface lists\n",
                    time_buf );
            free( tmp_list );

            /* remove all index entries from Toplevel OID 
             * linked list and store ifNumber 
             * */
            clear_oid_list( mib_info );
            ifNumber = if_num;
      
            return;
      } /* end if */

    
    /* allocate area, that should contain retrieved MIB 
     * data for a single interface 
     * */
    buffer = (char*) malloc( MIB_AREA_LEN );
    if ( buffer == NULL )
      {
      get_time( time_buf );      
      snmp_log( LOG_ERR, "%s update_mib_info(): "
              "malloc() for REGISTER MIB data buffer "
              "failed\nupdate_mib_info(): requested %d bytes\n"
              "update_mib_info(): keeping original interface lists\n",
              time_buf, MIB_AREA_LEN );
      free( tmp_list );
      return;
      } /* end if */

    /* socket for query MIB information ioctl */
    sd = socket( AF_INET, SOCK_STREAM, 0 );
    if ( sd < 0 )
      {
      error_code = errno;
      get_time( time_buf );
      snmp_log(LOG_ERR, "%s update_mib_info(): "
             "error opening socket() - reason %s\n"
             "update_mib_info(): cannot update OSA-E MIB information\n"
             "update_mib_info(): keeping original interface lists\n",
             time_buf, strerror( error_code ) );
      free( tmp_list );
      free( buffer );
      return;
      } /* end if */

    /* free original interface list and assign the new one (global data) */
    if ( if_list != NULL )
      free( if_list );
    
    ifNumber = if_num;
    if_list = tmp_list;

    /* free entire MIB lists that we maintain so far */ 
    clear_oid_list( mib_info ); 

    /* walk through interface list and query MIB data 
     * for all OSA-E devices register MIB data with 
     * subagent driving code afterwards               
     * */  
    for ( i=0; i < ifNumber; i++ )
      {
      if ( if_list[i].is_OSAEXP == TRUE )
        {
          /* clear buffer */
          memset( buffer, 0, MIB_AREA_LEN ); 
          
          /* setup ioctl buffer with request and input parameters */
          /* map command structure */
          ipa_reg_mib = (IPA_CMD_REG*) buffer;
           
          /* size of IPA data area */
          ipa_reg_mib->ioctl_cmd.data_len  =                  
            MIB_AREA_LEN - offsetof( IOCTL_CMD_HDR, ipa_cmd_hdr );

          /* length of IPA subcommand */      
          ipa_reg_mib->ioctl_cmd.req_len =                  
            sizeof( ipa_reg_mib->ioctl_cmd.ipa_cmd_hdr );  
          
          /* set input parameters for IPA Register MIB command */
          ipa_reg_mib->ioctl_cmd.ipa_cmd_hdr.request  = IPA_REG_MIB;        
          ipa_reg_mib->ioctl_cmd.ipa_cmd_hdr.ifIndex  = if_list[i].ifIndex; 
          ipa_reg_mib->ioctl_cmd.ipa_cmd_hdr.ret_code = 0;
          ipa_reg_mib->ioctl_cmd.ipa_cmd_hdr.seq_num  = 0;                        
    
          /* do ioctl() */
          strcpy( ifr.ifr_name, if_list[i].if_Name );         /* add interface name */       
          ifr.ifr_ifru.ifru_data = (char*) buffer;            /* add data buffer    */ 
      
          if ( ioctl( sd,SIOC_QETH_ADP_SET_SNMP_CONTROL, &ifr ) < 0 )
            {
            error_code = errno;
            get_time( time_buf );

                /* see if we got a common I/O error */
                if ( error_code == -EIO )
                  {
                     snmp_log( LOG_ERR, "%s update_mib_info(): "
                         "ioctl() failed - reason %s for interface %s\n"
                               "update_mib_info(): "
                         "MIB information may be incomplete\n",
                               time_buf, strerror( error_code ),
                         if_list[i].if_Name );
                     continue;
                     break;
                  } /* end if */
            
            /* let's see, if we got a return code from IPAssists */
            /* or if MIB buffer is exhausted */
            switch ( ipa_reg_mib->ioctl_cmd.ipa_cmd_hdr.ret_code ) {
            case IPA_FAILED:
              snmp_log( LOG_ERR, "%s update_mib_info(): "
                      "ioctl() failed - IPA command failed\n"
                      "update_mib_info(): for interface %s\n"
                      "update_mib_info(): MIB information may be incomplete\n",
                      time_buf, if_list[i].if_Name );
              continue;
              break;
              
            case IPA_NOT_SUPP:
              snmp_log( LOG_ERR, "%s update_mib_info(): "
                      "ioctl() failed - IPA command not supported\n"
                      "update_mib_info(): for interface %s\n"
                      "update_mib_info(): MIB information may be incomplete\n", 
                      time_buf, if_list[i].if_Name );
              continue;
              break;
            
            case IPA_NO_DATA:
              snmp_log( LOG_ERR, "%s update_mib_info(): "
                      "ioctl() failed - valid IPA command, but no"
                      "SNMP data is available for interface %s\n"
                      "update_mib_info(): MIB information may be incomplete\n", 
                      time_buf, if_list[i].if_Name );
              continue;
              break;
              
            case -ENOMEM: /* should not happen in the near future ;-) */
              snmp_log( LOG_ERR, "%s update_mib_info(): "
                      "ioctl() failed - MIB data size > "
                      "constant MIB_AREA_LEN for interface %s\n"
                      "update_mib_info(): "
                      "Enlarge constant for MIB_AREA_LEN "
                      "within ibmOSAMibDefs.h and "
                      "recompile the subagent\n"
                      "update_mib_info(): MIB information may be incomplete\n",
                      time_buf, if_list[i].if_Name );
              continue;
              break;
              
            default:
              snmp_log( LOG_ERR, "%s update_mib_info(): "
                      "ioctl() failed - reason %s "
                      "for interface %s\n"
                      "update_mib_info(): MIB information may be incomplete\n",
                      time_buf, strerror( error_code ), if_list[i].if_Name );
              continue;
              break;
            } /* end switch */
            } 
          else if ( ipa_reg_mib->ioctl_cmd.ipa_cmd_hdr.ret_code != 0 )
            {
            get_time( time_buf );      
            
            /* now check IPA SNMP subcommand return code */
            switch ( ipa_reg_mib->ioctl_cmd.ipa_cmd_hdr.ret_code ) {
              
            case IPA_SNMP_INV_TOPOID: 
            case IPA_SNMP_INV_GROUP: 
            case IPA_SNMP_INV_SUFFIX:
            case IPA_SNMP_INV_INST:
            case IPA_SNMP_OID_NREAD:
            case IPA_SNMP_OID_NWRIT:
              snmp_log( LOG_ERR, "%s update_mib_info(): "
                      "IPA SNMP subcommand failed - "
                        "return code 0x%x for interface %s\n"
                      "update_mib_info(): MIB information may be incomplete\n",
                      time_buf, 
                      ipa_reg_mib->ioctl_cmd.ipa_cmd_hdr.ret_code, 
                      if_list[i].if_Name );
              continue;
              break;
              
            case IPA_SNMP_NOT_SUPP:
              snmp_log( LOG_ERR, "%s update_mib_info(): "
                      "IPA SNMP subcommand failed - "
                      "subcommand 0x%x for interface %s\n"
                      "update_mib_info(): MIB information may be incomplete\n",
                      time_buf, 
                      ipa_reg_mib->ioctl_cmd.ipa_cmd_hdr.request, 
                      if_list[i].if_Name );
              continue;
              break;
            
            case IPA_SNMP_NO_DATA:
              snmp_log( LOG_ERR, "%s update_mib_info(): "
                      "IPA SNMP subcommand failed - "
                      "no data available for interface %s\n"
                      "update_mib_info(): MIB information may be incomplete\n",
                      time_buf, if_list[i].if_Name );
              continue;
              break;
              
            default:
              snmp_log( LOG_ERR, "%s update_mib_info(): "
                      "IPA SNMP subcommand failed - "
                      "undefined return code 0x%x for interface %s\n"
                      "update_mib_info(): MIB information may be incomplete\n",
                      time_buf, 
                      ipa_reg_mib->ioctl_cmd.ipa_cmd_hdr.ret_code, 
                      if_list[i].if_Name );
              continue;
              break;
              
            } /* end switch */
            
            } /* end if */

          /* register MIB tables information, that we got from IPAssists */
          retc = register_tables ( buffer, mib_info );
          if ( retc != 0 )
            {
            get_time( time_buf );      
            snmp_log( LOG_ERR, "%s update_mib_info(): "
                    "register MIB data with subagent "
                    "driving code failed\nupdate_mib_info(): for interface %s\n"
                    "update_mib_info(): check previous messages for "
                    "more details\nupdate_mib_info(): MIB information may be "
                    "incomplete\n", time_buf, if_list[i].if_Name );
            continue;
            } /* end if */
          
        } /* end if */
          
      } /* end for */ 
 
    get_time( time_buf );
    snmp_log( LOG_INFO, "%s *** OSA-E interface change indicated ***\n"
                    "%s *** Reinitialized MIB information ***\n",
                  time_buf, time_buf );
    
    close( sd );
    free( buffer );
} /* end update_mib_info */


/**********************************************************************
 * query_IF_MIB():
 *  Retrieve ifIndex values for all OSA devices residing on this    
 *  system. Use SNMP to query the master agent for ifNumber and 
 *  ifIndex/ifDescr values from the standard IF-MIB.
 *  Then figure out which of these devices are OSA Express devices.
 *  parameters:
 *  INOUT IF_LIST** ifList: List of network interfaces on this system  
 *  returns: int if_Number - number of network interfaces on this system 
 *                          system  (>=0)
 *                          -1 -an error occured , no valid info avail             
 *********************************************************************/
int query_IF_MIB ( IF_LIST** ifList )
{
  
  char   time_buf[TIME_BUF_SIZE];  /* date/time buffer */
  
  /* data structures for SNMP API */ 
  struct snmp_session session, *ss;
  struct snmp_pdu *pdu;
  struct snmp_pdu *response;
  struct variable_list *vars;
  void   *sessp;
  int status, have_info, valid;
  
  /* define static OIDs for if_Number, ifIndex and ifDescr from IF-MIB */
  size_t ifNumber_OIDlen   = 9,
         ifIndex_OIDlen    = 11,
         ifDescr_OIDlen    = 11;
  oid    ifNumber_OID[9]   = { 1,3,6,1,2,1,2,1,0 },
         ifIndex_OID[11]   = { 1,3,6,1,2,1,2,2,1,1,0 },
       ifDescr_OID[11]   = { 1,3,6,1,2,1,2,2,1,2,0 };
       
  int i, if_Number, count;      

  /* Initialize the SNMP library */
  DEBUGMSGTL(("query_IF_MIB"," about to query IF-MIB information using SNMP\n"));    
  
  /* Initialize a "session" for localhost */
  have_info = TRUE;
  valid = TRUE;
  if_Number = 0;
  snmp_sess_init( &session );                                           
  session.peername  = NET_SNMP_PEERNAME;       
  session.version   = SNMP_VERSION_2c;      /* use SNMPv2c */
  /* SNMPv2c community name */
  session.community = (unsigned char*)NET_SNMP_COMMUNITY;
  session.community_len = strlen((const char*)session.community);
  session.timeout = 300 * 1000000L;
   
  /* Open the session */
  sessp = snmp_sess_open( &session );                               
  if ( sessp == NULL ) {
    get_time( time_buf );       
    snmp_log(LOG_ERR,
           "%s query_IF_MIB(): snmp_sess_open() failed\n", time_buf );
    return -1;                                                
  } /* end if */
 
  ss = snmp_sess_session( sessp );
  
  /* Create and send synchronous GET PDU for if_Number */
  pdu = snmp_pdu_create(SNMP_MSG_GET);
  snmp_add_null_var( pdu, ifNumber_OID, ifNumber_OIDlen );
  status = snmp_sess_synch_response( sessp, pdu, &response);
  
  /* Process the response and get ifIndex/ifDescr table entries */
  if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR) 
    {    
      /* get value for if_Number */
      if ( response->variables->val.integer == NULL )
        {
           get_time( time_buf );
         snmp_log(LOG_ERR, "%s query_IF_MIB(): Get(if_Number) Error in packet\n"
                           "Reason: response->variables->val.integer == NULL\n",
                       time_buf);
           snmp_free_pdu(response);
           return -1;      
        } /* end if */  
      
      count = (int) *(response->variables->val.integer);
      snmp_free_pdu(response);
      
      if ( count == 0 )
      {
        snmp_sess_close( sessp );
        return 0;
      } /* end if */

      /* allocate memory for interface list */
      *ifList = (IF_LIST*) malloc((sizeof(IF_LIST) * count));
      if (*ifList == NULL)
      {
        get_time( time_buf ); 
        snmp_log(LOG_ERR, 
               "%s query_IF_MIB(): malloc() for ifList structure failed!\n", 
               time_buf);
        snmp_sess_close( sessp );
        return -1;
      } /* end if */
      
      /* if have interfaces, issue GETNEXT PDUs for ifIndex/ifDescr table entries */
      for ( i=0; i < count; i++ )
      {
        pdu = snmp_pdu_create( SNMP_MSG_GETNEXT );
        snmp_add_null_var( pdu, ifIndex_OID, ifIndex_OIDlen  );
        snmp_add_null_var( pdu, ifDescr_OID, ifDescr_OIDlen  );
        status = snmp_sess_synch_response( sessp, pdu, &response );   
         
        if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR)
          {
            /* set device to default value false; 
             * device type is determined later 
             * */
            (*ifList)[i].is_OSAEXP = FALSE;
            (*ifList)[i].kerIndex = 0;
            (*ifList)[i].ifIndex = 0;

            /* get values for ifIndex/ifDescr from response PDU 
             *  FIXME: (workaround) compare ifDescr values 
             *  and omit double entries 
             *  */ 
            for(vars = response->variables; vars; vars = vars->next_variable)
            {
              if( vars->type == ASN_INTEGER ) 
                (*ifList)[if_Number].ifIndex = (int) *(vars->val.integer);
              else if( vars->type == ASN_OCTET_STR  
                     && vars->val_len <= IFNAME_MAXLEN ) 
                {
                if ( if_Number == 0 )
                  {        
                     strncpy((char*)((*ifList)[0]).if_Name,
                         (const char*)vars->val.string, vars->val_len);
                   (*ifList)[0].if_Name[vars->val_len] = '\0';
                  }
                else
                  {
                        if (strncmp((const char*)(*ifList)[if_Number-1].if_Name,
                            (const char*)vars->val.string,
                             vars->val_len) !=0)
                      {
                        strncpy((char*)(*ifList)[if_Number].if_Name,
                            (const char*)vars->val.string,
                             vars->val_len);
                          (*ifList)[if_Number].if_Name[vars->val_len] = '\0';
                      valid = TRUE;
                          }
                    else 
                    valid = FALSE;  
                      } /* end if */                  
              }
              else 
              {
                get_time( time_buf );       
                snmp_log(LOG_ERR, "%s query_IF_MIB(): GetNext(ifIndex;ifDescr)"
                       " response PDU has invalid data\n", time_buf );
                free( *ifList ); 
                snmp_free_pdu(response);
                snmp_sess_close( sessp );
                return -1;
              } /* end if */
            } /* end for */
            if ( valid == TRUE ) 
            if_Number++;      
          }
        else
          {
            /* FAILURE GETNEXT */
            if (status == STAT_SUCCESS)
            {  
            get_time( time_buf );      
            snmp_log(LOG_ERR, "%s query_IF_MIB(): GetNext(ifIndex,ifDescr) "
                   "Error in packet\n"
                   "Reason: %s\n",time_buf, snmp_errstring(response->errstat));
            }
            else
            snmp_sess_perror("query_IF_MIB(): GetNext(ifIndex;ifDescr)", ss);
            if (response)
            snmp_free_pdu(response);
            free( *ifList );
            
            have_info = FALSE;
            break;
          } /* end if */
        
        /* store current ifIndex in OIDs for next GetNext request */
        ifIndex_OID[ifIndex_OIDlen-1] = (*ifList)[i].ifIndex;
        ifDescr_OID[ifDescr_OIDlen-1] = (*ifList)[i].ifIndex;
        
        snmp_free_pdu( response );
        
      } /* end for */
    }
  else
    { 
      /* FAILURE GET if_Number */
      if (status == STAT_SUCCESS)
      {
      get_time( time_buf );      
      snmp_log(LOG_ERR, "%s query_IF_MIB(): Get(if_Number) Error in packet\n"
             "Reason: %s\n", time_buf, snmp_errstring(response->errstat));
      }     
      else
      snmp_sess_perror("query_IF_MIB(): Get(if_Number)", ss);
      
      if (response)
      snmp_free_pdu(response);
      have_info = FALSE;
    } /* end if */
  
  /* Cleanup */
  snmp_sess_close( sessp );
  if ( have_info )
    return ( if_Number );
  else
    return -1;

} /* end query_IF_MIB() */


/**********************************************************************
 * query_OSA_EXP():
 *  Retrieve device characteristics for OSA Express devices and mark
 *  OSA Express devices in the interface list from IF-MIB.    
 *  parameters:
 *  INOUT IF_LIST** ifList: List of network interfaces on this system 
 *  IN    int       if_Number: number of network interfaces
 *  returns: int num - number of OSA Express devices found on this 
 *                          system  (>=0)
 *                          -1 -an error occured , no valid info avail             
 *********************************************************************/
int query_OSA_EXP ( IF_LIST** ifList, int if_Number )
{
  int j, num = 0;  
  char            time_buf[TIME_BUF_SIZE];  /* date/time buffer */
  int sd;
  struct ifreq ifr;
  /*open socket to get information if device is an OSA device*/ 
  if ( (sd = socket(AF_INET,SOCK_STREAM,0)) < 0 ) {
      snmp_log( LOG_ERR,"%s query_OSA_EXP(): " 
                    "socket  failed\n"
                    "query_OSA_EXP(): cancel init or update "
                    "of MIB information\n",time_buf );
      return 0;
  }
  
  /* walk through IF-MIB interface list and mark OSA Express interfaces */
  for ( j=0; j < if_Number; j++ ) {
      int ret=0;

      memset(&ifr,0,sizeof(ifr));
      strncpy(ifr.ifr_name, (*ifList)[j].if_Name,IFNAME_MAXLEN);
        ret = ioctl(sd, SIOC_QETH_GET_CARD_TYPE, &ifr);
      if (ret>0) {
                  (*ifList)[j].is_OSAEXP = TRUE;
            (*ifList)[j].kerIndex  = (*ifList)[j].ifIndex;
                  num++;
        }
  } /* end for */
  close(sd);
  
  return num;
} /* end query_OSA_EXP() */ 


/********************************************************************** 
 * get_time():
 *  gets current time of day string and returns it as
 *  MONTH DAY HH:MM:SS
 *  returns: string with date and time 
 *********************************************************************/
int get_time( char* buffer )
{
  
  time_t curtime;
  struct tm *loctime;

  curtime = time(NULL);
  loctime = localtime( &curtime );
  
  strftime( buffer, TIME_BUF_SIZE, "%b %d %T", loctime );
  
  return 0;
  
} /* end get_time () */

static const char* usage_text[] = {
"Usage:  osasnmpd [-h] [-v] [-l LOGFILE] [-A] [-f] [-L] [-P PIDFILE]",
"                 [-x SOCKADDR]",
"",
"-h, --help              This usage message",
"-v, --version           Version information",
"-l, --logfile LOGFILE   Print warnings/messages to LOGFILE",
"-A, --append            Append to the logfile rather than truncating it",
"-L, --stderrlog         Print warnings/messages to stdout/err",
"-f, --nofork            Do not fork() from the calling shell",
"-P, --pidfile PIDFILE   Save the process ID of the subagent in PIDFILE",
"-x, --sockaddr SOCKADDR Bind AgentX port to this address",
""
};

/**********************************************************************
 * usage():
 *  prints help message with descriptions of available parameters    
 *  IN name of subagent                                                
 *  returns: none                                                    
 *********************************************************************/
void usage()
{
      unsigned int i;

      for (i=0; i < sizeof(usage_text) / sizeof(usage_text[0]); i++)
            printf("%s\n", usage_text[i]);
      exit(0);
  
} /* end usage() */

Generated by  Doxygen 1.6.0   Back to index