/*
- * "$Id: snmp.c 6649 2007-07-11 21:46:42Z mike $"
+ * "$Id: snmp.c 7506 2008-04-29 04:38:47Z mike $"
*
* SNMP discovery backend for the Common UNIX Printing System (CUPS).
*
#include "backend-private.h"
#include <cups/array.h>
#include <cups/file.h>
-#include <cups/snmp.h>
#include <cups/http-private.h>
#include <regex.h>
/*
* This backend implements SNMP printer discovery. It uses a broadcast-
* based approach to get SNMP response packets from potential printers,
- * tries a mDNS lookup (Mac OS X only at present), a URI lookup based on
- * the device description string, and finally a probe of port 9100
- * (AppSocket) and 515 (LPD).
+ * requesting OIDs from the Host and Port Monitor MIBs, does a URI
+ * lookup based on the device description string, and finally a probe of
+ * port 9100 (AppSocket) and 515 (LPD).
*
* The current focus is on printers with internal network cards, although
- * the code also works with many external print servers as well. Future
- * versions will support scanning for vendor-specific SNMP OIDs and the
- * new PWG Port Monitor MIB and not just the Host MIB OIDs.
+ * the code also works with many external print servers as well.
*
* The backend reads the snmp.conf file from the CUPS_SERVERROOT directory
* which can contain comments, blank lines, or any number of the following
* print servers:
*
* Axis OfficeBasic, 5400, 5600
+ * Brother
* EPSON
* Genicom
* HP JetDirect
* Types...
*/
+enum /**** Request IDs for each field ****/
+{
+ DEVICE_TYPE = 1,
+ DEVICE_DESCRIPTION,
+ DEVICE_LOCATION,
+ DEVICE_ID,
+ DEVICE_URI,
+ DEVICE_PRODUCT
+};
+
typedef struct device_uri_s /**** DeviceURI values ****/
{
regex_t re; /* Regular expression to match */
char *addrname, /* Name of device */
*uri, /* device-uri */
*id, /* device-id */
+ *info, /* device-info */
+ *location, /* device-location */
*make_and_model; /* device-make-and-model */
+ int sent; /* Has this device been listed? */
} snmp_cache_t;
* Private CUPS API to set the last error...
*/
-extern void _cupsSetError(ipp_status_t status, const char *message);
+extern void _cupsSetError(ipp_status_t status, const char *message);
/*
static cups_array_t *Communities = NULL;
static cups_array_t *Devices = NULL;
static int DebugLevel = 0;
-static int DeviceDescOID[] = { CUPS_OID_hrDeviceDescr, 1, -1 };
-static unsigned DeviceDescRequest;
-static int DeviceTypeOID[] = { CUPS_OID_hrDeviceType, 1, -1 };
-static unsigned DeviceTypeRequest;
+static const int DescriptionOID[] = { CUPS_OID_hrDeviceDescr, 1, -1 };
+static const int LocationOID[] = { CUPS_OID_sysLocation, 0, -1 };
+static const int DeviceTypeOID[] = { CUPS_OID_hrDeviceType, 1, -1 };
+static const int DeviceIdOID[] = { CUPS_OID_ppmPrinterIEEE1284DeviceId, 1, -1 };
+static const int UriOID[] = { CUPS_OID_ppmPortServiceNameOrURI, 1, 1, -1 };
+static const int LexmarkProductOID[] = { 1,3,6,1,4,1,641,2,1,2,1,2,1,-1 };
+static const int LexmarkProductOID2[] = { 1,3,6,1,4,1,674,10898,100,2,1,2,1,2,1,-1 };
+static const int LexmarkDeviceIdOID[] = { 1,3,6,1,4,1,641,2,1,2,1,3,1,-1 };
+static const int XeroxProductOID[] = { 1,3,6,1,4,1,128,2,1,3,1,2,0,-1 };
static cups_array_t *DeviceURIs = NULL;
static int HostNameLookups = 0;
static int MaxRunTime = 120;
* Open the SNMP socket...
*/
- if ((fd = cupsSNMPOpen(AF_INET)) < 0)
+ if ((fd = _cupsSNMPOpen(AF_INET)) < 0)
return (1);
/*
read_snmp_conf(argv[1]);
- cupsSNMPSetDebug(DebugLevel);
+ _cupsSNMPSetDebug(DebugLevel);
Devices = cupsArrayNew((cups_array_func_t)compare_cache, NULL);
* Close, free, and return with no errors...
*/
- cupsSNMPClose(fd);
+ _cupsSNMPClose(fd);
free_array(Addresses);
free_array(Communities);
list_device(snmp_cache_t *cache) /* I - Cached device */
{
if (cache->uri)
- {
- printf("network %s \"%s\" \"%s %s\" \"%s\"\n",
- cache->uri,
- cache->make_and_model ? cache->make_and_model : "Unknown",
- cache->make_and_model ? cache->make_and_model : "Unknown",
- cache->addrname, cache->id ? cache->id : "");
- fflush(stdout);
- }
+ cupsBackendReport("network", cache->uri, cache->make_and_model,
+ cache->info, cache->id, cache->location);
}
* Read the response data...
*/
- if (!cupsSNMPRead(fd, &packet, -1.0))
+ if (!_cupsSNMPRead(fd, &packet, -1.0))
{
fprintf(stderr, "ERROR: Unable to read data from socket: %s\n",
strerror(errno));
* Process the message...
*/
- if (packet.request_id == DeviceTypeRequest)
+ switch (packet.request_id)
{
- /*
- * Got the device type response...
- */
+ case DEVICE_TYPE :
+ /*
+ * Got the device type response...
+ */
+
+ if (device)
+ {
+ debug_printf("DEBUG: Discarding duplicate device type for \"%s\"...\n",
+ addrname);
+ return;
+ }
+
+ /*
+ * Add the device and request the device data...
+ */
+
+ add_cache(&(packet.address), addrname, NULL, NULL, NULL);
+
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_DESCRIPTION, DescriptionOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_ID, DeviceIdOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_URI, UriOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_LOCATION, LocationOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_PRODUCT, LexmarkProductOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_PRODUCT, LexmarkProductOID2);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_URI, LexmarkDeviceIdOID);
+ _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+ packet.community, CUPS_ASN1_GET_REQUEST,
+ DEVICE_PRODUCT, XeroxProductOID);
+ break;
+
+ case DEVICE_DESCRIPTION :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING)
+ {
+ /*
+ * Update an existing cache entry...
+ */
+
+ char make_model[256]; /* Make and model */
+
+
+ if (strchr(packet.object_value.string, ':') &&
+ strchr(packet.object_value.string, ';'))
+ {
+ /*
+ * Description is the IEEE-1284 device ID...
+ */
- if (device)
- {
- debug_printf("DEBUG: Discarding duplicate device type for \"%s\"...\n",
- addrname);
- return;
- }
+ if (!device->id)
+ device->id = strdup(packet.object_value.string);
- /*
- * Add the device and request the device description...
- */
+ backendGetMakeModel(packet.object_value.string, make_model,
+ sizeof(make_model));
- add_cache(&(packet.address), addrname, NULL, NULL, NULL);
+ if (device->info)
+ free(device->info);
- cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community,
- CUPS_ASN1_GET_REQUEST, DeviceDescRequest, DeviceDescOID);
- }
- else if (packet.request_id == DeviceDescRequest &&
- packet.object_type == CUPS_ASN1_OCTET_STRING)
- {
- /*
- * Update an existing cache entry...
- */
+ device->info = strdup(make_model);
+ }
+ else
+ {
+ /*
+ * Description is plain text...
+ */
- char make_model[256]; /* Make and model */
+ fix_make_model(make_model, packet.object_value.string,
+ sizeof(make_model));
+ if (device->info)
+ free(device->info);
- if (!device)
- {
- debug_printf("DEBUG: Discarding device description for \"%s\"...\n",
- addrname);
- return;
- }
+ device->info = strdup(packet.object_value.string);
+ }
- /*
- * Convert the description to a make and model string...
- */
+ if (!device->make_and_model)
+ device->make_and_model = strdup(make_model);
+ }
+ break;
- if (strchr(packet.object_value.string, ':') &&
- strchr(packet.object_value.string, ';'))
- {
- /*
- * Description is the IEEE-1284 device ID...
- */
+ case DEVICE_ID :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING)
+ {
+ /*
+ * Update an existing cache entry...
+ */
- backendGetMakeModel(packet.object_value.string, make_model,
- sizeof(make_model));
- }
- else
- {
- /*
- * Description is plain text...
- */
+ char make_model[256]; /* Make and model */
- fix_make_model(make_model, packet.object_value.string,
- sizeof(make_model));
- }
- if (device->make_and_model)
- free(device->make_and_model);
+ if (device->id)
+ free(device->id);
- device->make_and_model = strdup(make_model);
+ device->id = strdup(packet.object_value.string);
+
+ /*
+ * Convert the ID to a make and model string...
+ */
+
+ backendGetMakeModel(packet.object_value.string, make_model,
+ sizeof(make_model));
+ if (device->make_and_model)
+ free(device->make_and_model);
+
+ device->make_and_model = strdup(make_model);
+ }
+ break;
+
+ case DEVICE_LOCATION :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+ !device->location)
+ device->location = strdup(packet.object_value.string);
+ break;
+
+ case DEVICE_PRODUCT :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+ !device->id)
+ {
+ /*
+ * Update an existing cache entry...
+ */
+
+ if (!device->info)
+ device->info = strdup(packet.object_value.string);
+
+ if (device->make_and_model)
+ free(device->make_and_model);
+
+ device->make_and_model = strdup(packet.object_value.string);
+ }
+ break;
+
+ case DEVICE_URI :
+ if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+ !device->uri)
+ {
+ /*
+ * Update an existing cache entry...
+ */
+
+ if (!strncmp(packet.object_value.string, "lpr:", 4))
+ {
+ /*
+ * We want "lpd://..." for the URI...
+ */
+
+ packet.object_value.string[2] = 'd';
+ }
- probe_device(device);
+ device->uri = strdup(packet.object_value.string);
+ }
+ break;
}
}
snmp_cache_t *device; /* Current device */
- /*
- * Setup the request IDs...
- */
-
gettimeofday(&StartTime, NULL);
- DeviceTypeRequest = StartTime.tv_sec;
- DeviceDescRequest = StartTime.tv_sec + 1;
-
/*
* First send all of the broadcast queries...
*/
community, address);
for (addr = addrs; addr; addr = addr->next)
- cupsSNMPWrite(fd, &(addr->addr), CUPS_SNMP_VERSION_1, community,
- CUPS_ASN1_GET_REQUEST, DeviceTypeRequest, DeviceTypeOID);
+ _cupsSNMPWrite(fd, &(addr->addr), CUPS_SNMP_VERSION_1, community,
+ CUPS_ASN1_GET_REQUEST, DEVICE_TYPE, DeviceTypeOID);
}
httpAddrFreeList(addrs);
if (FD_ISSET(fd, &input))
read_snmp_response(fd);
else
- break;
- }
+ {
+ /*
+ * List devices with complete information...
+ */
- /*
- * Finally, probe all of the printers we discovered to see how they are
- * connected...
- */
+ int sent_something = 0;
- for (device = (snmp_cache_t *)cupsArrayFirst(Devices);
- device;
- device = (snmp_cache_t *)cupsArrayNext(Devices))
- if (MaxRunTime > 0 && run_time() >= MaxRunTime)
- break;
- else if (!device->uri)
- probe_device(device);
+ for (device = (snmp_cache_t *)cupsArrayFirst(Devices);
+ device;
+ device = (snmp_cache_t *)cupsArrayNext(Devices))
+ if (!device->sent && device->info && device->make_and_model)
+ {
+ if (device->uri)
+ list_device(device);
+ else
+ probe_device(device);
+
+ device->sent = sent_something = 1;
+ }
+
+ if (!sent_something)
+ break;
+ }
+ }
debug_printf("DEBUG: %.3f Scan complete!\n", run_time());
}
/*
- * End of "$Id: snmp.c 6649 2007-07-11 21:46:42Z mike $".
+ * End of "$Id: snmp.c 7506 2008-04-29 04:38:47Z mike $".
*/