snmp.c revision 5307:ea4512a0e608
1/*
2 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 *
5 * Licensed under the Academic Free License version 2.1
6 */
7
8#pragma ident	"%Z%%M%	%I%	%E% SMI"
9
10#include <sys/types.h>
11#include <sys/socket.h>
12#include <netinet/in.h>
13#include <arpa/inet.h>
14
15#include <glib.h>
16
17#include <libhal.h>
18#include <logger.h>
19
20#undef PACKAGE_STRING
21#undef PACKAGE_VERSION
22
23#include <net-snmp/net-snmp-config.h>
24#include <net-snmp/net-snmp-includes.h>
25
26#include "network-discovery.h"
27#include "printer.h"
28
29#define NP(x)   (x?x:"NULL")
30
31static GList *new_addrs = NULL;
32
33static void
34add_snmp_device(LibHalContext *ctx, char *parent, char *name, char *community)
35{
36	/* most printers listen on the appsocket port (9100) */
37	if (is_listening(name, 9100) == 0) {
38		char device[128];
39
40		snprintf(device, sizeof (device), "socket://%s:9100", name);
41
42		add_network_printer(ctx, parent, name, device, community);
43	}
44
45	/*
46	 * This would be a good place to detect other types of devices or other
47	 * device capabilities.  scanners, removable media, storage, ...
48	 */
49}
50
51static int
52snmp_response_cb(int operation, struct snmp_session *sp, int reqid,
53		struct snmp_pdu *pdu, void *data)
54{
55	struct sockaddr_in *addr = pdu->transport_data;
56	char *name;
57
58	name = inet_ntoa(addr->sin_addr);
59
60	/* have we already seen this network device */
61	if (device_seen(name) == FALSE)
62		new_addrs = g_list_append(new_addrs, strdup(name));
63
64	return (0);
65}
66
67gboolean
68scan_for_devices_using_snmp(LibHalContext *ctx, char *parent, char *community,
69		char *network)
70{
71	struct snmp_session session, *ss;
72	struct snmp_pdu *request = NULL, *response = NULL;
73	oid Oid[MAX_OID_LEN];
74	unsigned int oid_len = MAX_OID_LEN;
75	GList *elem;
76
77	HAL_DEBUG(("scan_for_devices_using_snmp(0x%8.8x, %s, %s, %s)",
78			ctx, NP(parent), NP(community), NP(network)));
79
80	init_snmp("snmp-scan");
81	init_mib();
82
83	/* initialize the SNMP session */
84	snmp_sess_init(&session);
85	session.peername = network;
86	session.community = (uchar_t *)community;
87	session.community_len = strlen((const char *)session.community);
88	session.version = SNMP_VERSION_1;
89
90	if ((ss = snmp_open(&session)) == NULL)
91		return (FALSE);
92
93	/* initialize the request PDU */
94	request = snmp_pdu_create(SNMP_MSG_GET);
95
96	/* add the requested data (everyone should have a sysDescr.0) */
97	if (!read_objid("SNMPv2-MIB::sysDescr.0", Oid, &oid_len))
98		snmp_perror("sysDescr.0");
99	snmp_add_null_var(request, Oid, oid_len);
100
101	snmp_async_send(ss, request, snmp_response_cb, NULL);
102
103	/* detect any new devices */
104	while (1) {
105		int fds = 0, block = 0;
106		fd_set fdset;
107		struct timeval timeout;
108
109		FD_ZERO(&fdset);
110		snmp_select_info(&fds, &fdset, &timeout, &block);
111		fds = select(fds, &fdset, NULL, NULL, block ? NULL : &timeout);
112		if (fds < 0) {
113			perror("select failed");
114			continue;
115		} if (fds == 0) {
116			break;
117		} else {
118			snmp_read(&fdset);
119		}
120	}
121
122	snmp_close(ss);
123
124	/* add the newly detected devices */
125	for (elem = new_addrs; elem != NULL; elem = g_list_next(elem)) {
126		add_snmp_device(ctx, parent, (char *)elem->data, community);
127		free(elem->data);
128	}
129	g_list_free(new_addrs);
130	new_addrs = NULL;
131
132	return (TRUE);
133}
134