xref: /illumos-gate/usr/src/cmd/hal/addons/network-devices/snmp.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 
31 static GList *new_addrs = NULL;
32 
33 static void
34 add_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 
51 static int
52 snmp_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 
67 gboolean
68 scan_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