xref: /onnv-gate/usr/src/cmd/hal/addons/network-devices/snmp.c (revision 10863:48c7568390ec)
15307Sjacobs /*
2*10863SLin.Guo@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
35307Sjacobs  * Use is subject to license terms.
45307Sjacobs  *
55307Sjacobs  * Licensed under the Academic Free License version 2.1
65307Sjacobs  */
75307Sjacobs 
85307Sjacobs #include <sys/types.h>
95307Sjacobs #include <sys/socket.h>
105307Sjacobs #include <netinet/in.h>
115307Sjacobs #include <arpa/inet.h>
125307Sjacobs 
135307Sjacobs #include <glib.h>
145307Sjacobs 
155307Sjacobs #include <libhal.h>
165307Sjacobs #include <logger.h>
175307Sjacobs 
185307Sjacobs #undef PACKAGE_STRING
195307Sjacobs #undef PACKAGE_VERSION
205307Sjacobs 
215307Sjacobs #include <net-snmp/net-snmp-config.h>
225307Sjacobs #include <net-snmp/net-snmp-includes.h>
235307Sjacobs 
245307Sjacobs #include "network-discovery.h"
255307Sjacobs #include "printer.h"
265307Sjacobs 
27*10863SLin.Guo@Sun.COM #define	NP(x)	(x?x:"NULL")
285307Sjacobs 
295307Sjacobs static GList *new_addrs = NULL;
305307Sjacobs 
315307Sjacobs static void
add_snmp_device(LibHalContext * ctx,char * parent,char * name,char * community)325307Sjacobs add_snmp_device(LibHalContext *ctx, char *parent, char *name, char *community)
335307Sjacobs {
345307Sjacobs 	/* most printers listen on the appsocket port (9100) */
355307Sjacobs 	if (is_listening(name, 9100) == 0) {
365307Sjacobs 		char device[128];
375307Sjacobs 
385307Sjacobs 		snprintf(device, sizeof (device), "socket://%s:9100", name);
395307Sjacobs 
405307Sjacobs 		add_network_printer(ctx, parent, name, device, community);
415307Sjacobs 	}
425307Sjacobs 
435307Sjacobs 	/*
445307Sjacobs 	 * This would be a good place to detect other types of devices or other
455307Sjacobs 	 * device capabilities.  scanners, removable media, storage, ...
465307Sjacobs 	 */
475307Sjacobs }
485307Sjacobs 
495307Sjacobs static int
snmp_response_cb(int operation,struct snmp_session * sp,int reqid,struct snmp_pdu * pdu,void * data)505307Sjacobs snmp_response_cb(int operation, struct snmp_session *sp, int reqid,
515307Sjacobs 		struct snmp_pdu *pdu, void *data)
525307Sjacobs {
535307Sjacobs 	struct sockaddr_in *addr = pdu->transport_data;
545307Sjacobs 	char *name;
555307Sjacobs 
565307Sjacobs 	name = inet_ntoa(addr->sin_addr);
575307Sjacobs 
585307Sjacobs 	/* have we already seen this network device */
595307Sjacobs 	if (device_seen(name) == FALSE)
605307Sjacobs 		new_addrs = g_list_append(new_addrs, strdup(name));
615307Sjacobs 
625307Sjacobs 	return (0);
635307Sjacobs }
645307Sjacobs 
655307Sjacobs gboolean
scan_for_devices_using_snmp(LibHalContext * ctx,char * parent,char * community,char * network)665307Sjacobs scan_for_devices_using_snmp(LibHalContext *ctx, char *parent, char *community,
675307Sjacobs 		char *network)
685307Sjacobs {
695307Sjacobs 	struct snmp_session session, *ss;
705307Sjacobs 	struct snmp_pdu *request = NULL, *response = NULL;
715307Sjacobs 	oid Oid[MAX_OID_LEN];
725307Sjacobs 	unsigned int oid_len = MAX_OID_LEN;
735307Sjacobs 	GList *elem;
745307Sjacobs 
755307Sjacobs 	HAL_DEBUG(("scan_for_devices_using_snmp(0x%8.8x, %s, %s, %s)",
76*10863SLin.Guo@Sun.COM 	    ctx, NP(parent), NP(community), NP(network)));
775307Sjacobs 
785307Sjacobs 	init_snmp("snmp-scan");
795307Sjacobs 	init_mib();
805307Sjacobs 
815307Sjacobs 	/* initialize the SNMP session */
825307Sjacobs 	snmp_sess_init(&session);
835307Sjacobs 	session.peername = network;
845307Sjacobs 	session.community = (uchar_t *)community;
855307Sjacobs 	session.community_len = strlen((const char *)session.community);
865307Sjacobs 	session.version = SNMP_VERSION_1;
875307Sjacobs 
885307Sjacobs 	if ((ss = snmp_open(&session)) == NULL)
895307Sjacobs 		return (FALSE);
905307Sjacobs 
915307Sjacobs 	/* initialize the request PDU */
925307Sjacobs 	request = snmp_pdu_create(SNMP_MSG_GET);
935307Sjacobs 
945307Sjacobs 	/* add the requested data (everyone should have a sysDescr.0) */
955307Sjacobs 	if (!read_objid("SNMPv2-MIB::sysDescr.0", Oid, &oid_len))
965307Sjacobs 		snmp_perror("sysDescr.0");
975307Sjacobs 	snmp_add_null_var(request, Oid, oid_len);
985307Sjacobs 
995307Sjacobs 	snmp_async_send(ss, request, snmp_response_cb, NULL);
1005307Sjacobs 
1015307Sjacobs 	/* detect any new devices */
1025307Sjacobs 	while (1) {
1035307Sjacobs 		int fds = 0, block = 0;
1045307Sjacobs 		fd_set fdset;
1055307Sjacobs 		struct timeval timeout;
1065307Sjacobs 
1075307Sjacobs 		FD_ZERO(&fdset);
1085307Sjacobs 		snmp_select_info(&fds, &fdset, &timeout, &block);
1095307Sjacobs 		fds = select(fds, &fdset, NULL, NULL, block ? NULL : &timeout);
1105307Sjacobs 		if (fds < 0) {
1115307Sjacobs 			perror("select failed");
112*10863SLin.Guo@Sun.COM 			break;
1135307Sjacobs 		} if (fds == 0) {
1145307Sjacobs 			break;
1155307Sjacobs 		} else {
1165307Sjacobs 			snmp_read(&fdset);
1175307Sjacobs 		}
1185307Sjacobs 	}
1195307Sjacobs 
1205307Sjacobs 	snmp_close(ss);
1215307Sjacobs 
1225307Sjacobs 	/* add the newly detected devices */
1235307Sjacobs 	for (elem = new_addrs; elem != NULL; elem = g_list_next(elem)) {
1245307Sjacobs 		add_snmp_device(ctx, parent, (char *)elem->data, community);
1255307Sjacobs 		free(elem->data);
1265307Sjacobs 	}
1275307Sjacobs 	g_list_free(new_addrs);
1285307Sjacobs 	new_addrs = NULL;
1295307Sjacobs 
1305307Sjacobs 	return (TRUE);
1315307Sjacobs }
132