/*
 * Copyright (c) 1993 Thomas Pusateri
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that: (1) source code distributions
 * retain the above copyright notice and this paragraph in its entirety, (2)
 * redistribution for commercial purposes be limited to those that obtain
 * prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Portions of this code may have been derived from code distributed
 * with the cmu-snmp1.2u.tar.Z distribution containing the following
 * copyright.
 *	Copyright 1988, 1989 by Carnegie Mellon University
 */

/**********************************************************************
 *
 * Name:        $RCSfile: ospfquery.c,v $
 *
 * Dated:       $Date: 93/05/14 11:36:47 $
 *
 * Author:      $Author: pusateri $
 *
 * Revision:    $Revision: 1.4 $
 *
 * Description:
 *		collect information from an ospf router running SNMP
 *
 *
 ***********************************************************************/

#ifndef lint
static char RCSid[]=
"$Id: ospfquery.c,v 1.4 93/05/14 11:36:47 pusateri Exp $";
#endif

#include <sys/types.h>
#include <netinet/in.h>
#include <stdio.h>

#include "snmp.h"
#include "snmp_impl.h"
#include "asn1.h"
#include "snmp_client.h"
#include "snmp_api.h"
#include "mib.h"
#include "ospf.h"

struct ospfIf *ifp;
struct ospfNbr *nbrp;
struct ospfLsdb *lsdbp;
struct ospf_advlist *ap;
struct ospfRT *rtp;
struct ospfFT *ftp;

int	snmp_dump_packet = 0;

oid objid_sysDescr[] = {1, 3, 6, 1, 2, 1, 1, 1, 0};
int length_sysDescr = sizeof(objid_sysDescr)/sizeof(oid);
oid objid_ospfRouterId[] = {1, 3, 6, 1, 2, 1, 14, 1, 1, 0};
int length_ospfRouterId = sizeof(objid_ospfRouterId)/sizeof(oid);
oid objid_ospfAdminStat[] = {1, 3, 6, 1, 2, 1, 14, 1, 2, 0};
int length_ospfAdminStat = sizeof(objid_ospfAdminStat)/sizeof(oid);


main(argc, argv)
    int	    argc;
    char    *argv[];
{
    void collect_ospf_interfaces(),
	 collect_ospf_neighbors(),
	 collect_ospf_lsdb(),
	 collect_ospf_lsa(),
	 collect_route_table(),
	 collect_forward_table(),
	 print_ospf_interfaces(),
	 print_ospf_neighbors(),
	 print_ospf_lsdb(),
	 print_ospf_lsa(),
	 print_route_table(),
	 print_forward_table();

    struct snmp_session session, *ss;
    struct snmp_pdu *pdu, *response;
    struct variable_list *vars;
    int	arg;
    char *router = NULL;
    char *community = NULL;
    char    name[256];
    int	    status, count;
    int     command = NEIGHBORS;
    u_long  routerid = 0,
	    adminstat = 0;

    /*
     * usage: ospfquery [-d] -a | -f | -g | -i | -l | -m | -n | -r router [community-name]
     */
    for(arg = 1; arg < argc; arg++){
	if (argv[arg][0] == '-'){
	    switch(argv[arg][1]){
		case 'd':
		    snmp_dump_packet++;
		    break;
		case 'i':
		    command = INTERFACES;
		    break;
		case 'n':		/* default */
		    command = NEIGHBORS;
		    break;
		case 'a':
		    command = ADVERTISEMENTS;
		    break;
		case 'g':
		    command = GENERAL;
		    break;
		case 'l':
		    command = LSDB;
		    break;
		case 'r':
		    command = ROUTE_TABLE;
		    break;
		case 'f':
		    command = FORWARD_TABLE;
		    break;
		case 'm':
		    command = MISMATCH;
		    break;
		default:
		    printf("invalid option: -%c\n", argv[arg][1]);
		    printf("usage: %s [-d] -a | -f | -g | -i | -l | -m | -n | -r router [community-name]\n", argv[0]);
		    exit(1);
		    break;
	    }
	    continue;
	}
	if (router == NULL){
	    router = argv[arg];
	} else if (community == NULL){
	    community = argv[arg]; 
	} else {
	    printf("usage: %s [-d] -a | -f | -g | -i | -l | -m | -n | -r router [community-name]\n", argv[0]);
	    exit(1);
	}
    }
    if (!(router)){
	printf("usage: %s [-d] -a | -f | -g | -i | -l | -m | -n | -r router [community-name]\n", argv[0]);
	exit(1);
    }

    bzero((char *)&session, sizeof(struct snmp_session));
    session.peername = router;
    session.community = (u_char *)community;
    if (community == NULL){
	session.community_len = SNMP_DEFAULT_COMMUNITY_LEN;
    } else {
	session.community_len = strlen(community);
    }
    session.retries = 4;
    session.timeout = 500000;
    session.authenticator = NULL;
    snmp_synch_setup(&session);
    ss = snmp_open(&session);
    if (ss == NULL){
	printf("Couldn't open snmp\n");
	exit(-1);
    }

    strcpy(name, "No System Description Available");
    pdu = snmp_pdu_create(GET_REQ_MSG);

    snmp_add_null_var(pdu, objid_sysDescr, length_sysDescr);
    snmp_add_null_var(pdu, objid_ospfRouterId, length_ospfRouterId);
    snmp_add_null_var(pdu, objid_ospfAdminStat, length_ospfAdminStat);

retry:
    status = snmp_synch_response(ss, pdu, &response);
    if (status == STAT_SUCCESS){
	if (response->errstat == SNMP_ERR_NOERROR){
	    for(vars = response->variables; vars; vars = vars->next_variable){
		if (vars->name_length == length_sysDescr &&
		    !bcmp((char *)objid_sysDescr, (char*)vars->name, sizeof(objid_sysDescr))){
			bcopy((char *)vars->val.string, name, vars->val_len);
			name[vars->val_len] = '\0';
		}
		if (vars->name_length == length_ospfRouterId &&
		    !bcmp((char *)objid_ospfRouterId, (char*)vars->name, sizeof(objid_ospfRouterId))){
			routerid = *vars->val.integer;
		}
		if (vars->name_length == length_ospfAdminStat &&
		    !bcmp((char *)objid_ospfAdminStat, (char*)vars->name, sizeof(objid_ospfAdminStat))){
			adminstat = *vars->val.integer;
		}
	    }
	} else {
	    printf("Error in packet.\nReason: %s\n", snmp_errstring(response->errstat));
	    if (response->errstat == SNMP_ERR_NOSUCHNAME){
		printf("This name doesn't exist: ");
		for(count = 1, vars = response->variables; vars && count != response->errindex;
		    vars = vars->next_variable, count++)
			;
		if (vars)
		    print_objid(vars->name, vars->name_length);
		printf("\n");
	    }
	    if ((pdu = snmp_fix_pdu(response, GET_REQ_MSG)) != NULL)
		goto retry;
	}

    } else if (status == STAT_TIMEOUT){
	printf("No Response from %s\n", router);
	exit(1);
    } else {    /* status == STAT_ERROR */
	printf("An error occurred, Quitting\n");
	exit(2);
    }

    if (adminstat != ENABLED) {
	printf("OSPF disabled.\n");
	exit(1);
    }

    if (response)
	snmp_free_pdu(response);

    switch (command) {
    case ADVERTISEMENTS:
			ap = (struct ospf_advlist *) 0;
			collect_ospf_lsa(ss);
			print_ospf_lsa();
			break;
    case GENERAL:
			printf("Not yet implemented\n");
			break;
    case LSDB:
			lsdbp = (struct ospfLsdb *) 0;
			collect_ospf_lsdb(ss);
			print_ospf_lsdb();
			break;
    case MISMATCH:
			printf("Not yet implemented\n");
			break;
    case NEIGHBORS:
			nbrp = (struct ospfNbr *) 0;
			collect_ospf_neighbors(ss);
			print_ospf_neighbors();
			break;
    case INTERFACES:
			ifp = (struct ospfIf *) 0;
			collect_ospf_interfaces(ss);
			print_ospf_interfaces();
			break;
    case ROUTE_TABLE:
			rtp = (struct ospfRT *) 0;
			collect_route_table(ss);
			print_route_table();
			break;
    case FORWARD_TABLE:
			ftp = (struct ospfFT *) 0;
			collect_forward_table(ss);
			print_forward_table();
			break;
    }
}
