2
* UDP MIB group Table implementation - udpTable.c
6
/* Portions of this file are subject to the following copyright(s). See
7
* the Net-SNMP's COPYING file for more details and other copyrights
11
* Portions of this file are copyrighted by:
12
* Copyright ļæ½ 2003 Sun Microsystems, Inc. All rights reserved.
13
* Use is subject to license terms specified in the COPYING file
14
* distributed with the Net-SNMP package.
17
#include <net-snmp/net-snmp-config.h>
18
#include "mibII_common.h"
20
#if HAVE_NETINET_UDP_H
21
#include <netinet/udp.h>
23
#if HAVE_NETINET_UDP_VAR_H
24
#include <netinet/udp_var.h>
27
#include <net-snmp/net-snmp-includes.h>
28
#include <net-snmp/agent/net-snmp-agent-includes.h>
29
#include <net-snmp/agent/auto_nlist.h>
36
#include "sysORTable.h"
39
#define UDPTABLE_ENTRY_TYPE mib_udpLsnEnt
40
#define UDPTABLE_LOCALADDRESS LocalAddress
41
#define UDPTABLE_LOCALPORT LocalPort
42
#define UDPTABLE_IS_TABLE
46
typedef struct netsnmp_udpEntry_s netsnmp_udpEntry;
47
struct netsnmp_udpEntry_s {
48
mib2_udpEntry_t entry;
49
netsnmp_udpEntry *inp_next;
51
#define UDPTABLE_ENTRY_TYPE netsnmp_udpEntry
52
#define UDPTABLE_LOCALADDRESS entry.udpLocalAddress
53
#define UDPTABLE_LOCALPORT entry.udpLocalPort
54
#define UDPTABLE_IS_LINKED_LIST
59
#define UDPTABLE_ENTRY_TYPE MIB_UDPROW /* ??? */
60
#define UDPTABLE_LOCALADDRESS dwLocalAddr
61
#define UDPTABLE_LOCALPORT dwLocalPort
62
#define UDPTABLE_IS_TABLE
63
#else /* everything else */
66
#define INP_NEXT_SYMBOL inp_next
68
#define UDPTABLE_ENTRY_TYPE struct inpcb
69
#define UDPTABLE_LOCALADDRESS inp_laddr.s_addr
70
#define UDPTABLE_LOCALPORT inp_lport
71
#define UDPTABLE_IS_LINKED_LIST
77
/* Head of linked list, or root of table */
78
UDPTABLE_ENTRY_TYPE *udp_head = NULL;
79
int udp_size = 0; /* Only used for table-based systems */
84
* Initialization and handler routines are common to all architectures
87
#ifndef MIB_STATS_CACHE_TIMEOUT
88
#define MIB_STATS_CACHE_TIMEOUT 5
90
#ifndef UDP_STATS_CACHE_TIMEOUT
91
#define UDP_STATS_CACHE_TIMEOUT MIB_STATS_CACHE_TIMEOUT
94
oid udpTable_oid[] = { SNMP_OID_MIB2, 7, 5 };
99
netsnmp_table_registration_info *table_info;
100
netsnmp_iterator_info *iinfo;
101
netsnmp_handler_registration *reginfo;
103
DEBUGMSGTL(("mibII/udpTable", "Initialising UDP Table\n"));
105
* Create the table data structure, and define the indexing....
107
table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
111
netsnmp_table_helper_add_indexes(table_info, ASN_IPADDRESS,
113
table_info->min_column = UDPLOCALADDRESS;
114
table_info->max_column = UDPLOCALPORT;
118
* .... and iteration information ....
120
iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);
124
iinfo->get_first_data_point = udpTable_first_entry;
125
iinfo->get_next_data_point = udpTable_next_entry;
126
iinfo->table_reginfo = table_info;
127
#if defined(WIN32) || defined(solaris2)
128
iinfo->flags |= NETSNMP_ITERATOR_FLAG_SORTED;
129
#endif /* WIN32 || solaris2 */
133
* .... and register the table with the agent.
135
reginfo = netsnmp_create_handler_registration("udpTable",
137
udpTable_oid, OID_LENGTH(udpTable_oid),
139
netsnmp_register_table_iterator(reginfo, iinfo);
142
* .... with a local cache
144
netsnmp_inject_handler( reginfo,
145
netsnmp_get_cache_handler(UDP_STATS_CACHE_TIMEOUT,
146
udpTable_load, udpTable_free,
147
udpTable_oid, OID_LENGTH(udpTable_oid)));
153
udpTable_handler(netsnmp_mib_handler *handler,
154
netsnmp_handler_registration *reginfo,
155
netsnmp_agent_request_info *reqinfo,
156
netsnmp_request_info *requests)
158
netsnmp_request_info *request;
159
netsnmp_variable_list *requestvb;
160
netsnmp_table_request_info *table_info;
161
UDPTABLE_ENTRY_TYPE *entry;
165
DEBUGMSGTL(("mibII/udpTable", "Handler - mode %s\n",
166
se_find_label_in_slist("agent_mode", reqinfo->mode)));
167
switch (reqinfo->mode) {
169
for (request=requests; request; request=request->next) {
170
requestvb = request->requestvb;
171
DEBUGMSGTL(( "mibII/udpTable", "oid: "));
172
DEBUGMSGOID(("mibII/udpTable", requestvb->name,
173
requestvb->name_length));
174
DEBUGMSG(( "mibII/udpTable", "\n"));
176
entry = (UDPTABLE_ENTRY_TYPE *)netsnmp_extract_iterator_context(request);
179
table_info = netsnmp_extract_table_info(request);
180
subid = table_info->colnum;
183
case UDPLOCALADDRESS:
184
#if defined(osf5) && defined(IN6_EXTRACT_V4ADDR)
185
snmp_set_var_typed_value(requestvb, ASN_IPADDRESS,
186
(u_char*)IN6_EXTRACT_V4ADDR(pcb->inp_laddr),
187
sizeof(IN6_EXTRACT_V4ADDR(pcb->inp_laddr)));
189
snmp_set_var_typed_value(requestvb, ASN_IPADDRESS,
190
(u_char *)&entry->UDPTABLE_LOCALADDRESS,
191
sizeof(entry->UDPTABLE_LOCALADDRESS));
195
port = ntohs((u_short)entry->UDPTABLE_LOCALPORT);
196
snmp_set_var_typed_value(requestvb, ASN_INTEGER,
197
(u_char *)&port, sizeof(port));
205
case MODE_SET_RESERVE1:
206
case MODE_SET_RESERVE2:
207
case MODE_SET_ACTION:
208
case MODE_SET_COMMIT:
211
snmp_log(LOG_WARNING, "mibII/udpTable: Unsupported mode (%d)\n",
215
snmp_log(LOG_WARNING, "mibII/udpTable: Unrecognised mode (%d)\n",
220
return SNMP_ERR_NOERROR;
224
* Two forms of iteration hook routines:
225
* One for when the UDP table is stored as a table
226
* One for when the UDP table is stored as a linked list
228
* Also applies to the cache-handler free routine
231
#ifdef UDPTABLE_IS_TABLE
232
netsnmp_variable_list *
233
udpTable_first_entry(void **loop_context,
235
netsnmp_variable_list *index,
236
netsnmp_iterator_info *data)
239
* XXX - How can we tell if the cache is valid?
240
* No access to 'reqinfo'
246
* Point to the first entry, and use the
247
* 'next_entry' hook to retrieve this row
250
return udpTable_next_entry( loop_context, data_context, index, data );
253
netsnmp_variable_list *
254
udpTable_next_entry( void **loop_context,
256
netsnmp_variable_list *index,
257
netsnmp_iterator_info *data)
259
int i = (int)*loop_context;
266
* Set up the indexing for the specified row...
268
snmp_set_var_value(index, (u_char *)&udp_head[i].UDPTABLE_LOCALADDRESS,
269
sizeof(udp_head[i].UDPTABLE_LOCALADDRESS));
270
port = ntohs((u_short)udp_head[i].UDPTABLE_LOCALPORT);
271
snmp_set_var_value(index->next_variable,
272
(u_char*)&port, sizeof(port));
274
* ... return the data structure for this row,
275
* and update the loop context ready for the next one.
277
*data_context = (void*)&udp_head[i];
278
*loop_context = (void*)++i;
283
udpTable_free(netsnmp_cache *cache, void *magic)
287
/* the allocated structure is a count followed by table entries */
288
free((char *)(udp_head) - sizeof(DWORD));
298
#ifdef UDPTABLE_IS_LINKED_LIST
299
netsnmp_variable_list *
300
udpTable_first_entry(void **loop_context,
302
netsnmp_variable_list *index,
303
netsnmp_iterator_info *data)
306
* XXX - How can we tell if the cache is valid?
307
* No access to 'reqinfo'
313
* Point to the first entry, and use the
314
* 'next_entry' hook to retrieve this row
316
*loop_context = (void*)udp_head;
317
return udpTable_next_entry( loop_context, data_context, index, data );
320
netsnmp_variable_list *
321
udpTable_next_entry( void **loop_context,
323
netsnmp_variable_list *index,
324
netsnmp_iterator_info *data)
326
UDPTABLE_ENTRY_TYPE *entry = (UDPTABLE_ENTRY_TYPE *)*loop_context;
333
* Set up the indexing for the specified row...
335
#if defined(osf5) && defined(IN6_EXTRACT_V4ADDR)
336
snmp_set_var_value(index,
337
(u_char*)&IN6_EXTRACT_V4ADDR(entry->inp_laddr),
338
sizeof(IN6_EXTRACT_V4ADDR(entry->inp_laddr)));
340
snmp_set_var_value(index, (u_char*)&entry->UDPTABLE_LOCALADDRESS,
341
sizeof(entry->UDPTABLE_LOCALADDRESS));
343
port = ntohs(entry->UDPTABLE_LOCALPORT);
344
snmp_set_var_value(index->next_variable,
345
(u_char*)&port, sizeof(port));
348
* ... return the data structure for this row,
349
* and update the loop context ready for the next one.
351
*data_context = (void*)entry;
352
*loop_context = (void*)entry->INP_NEXT_SYMBOL;
357
udpTable_free(netsnmp_cache *cache, void *magic)
359
UDPTABLE_ENTRY_TYPE *p;
362
udp_head = udp_head->INP_NEXT_SYMBOL;
368
#endif /* UDPTABLE_IS_LINKED_LIST */
369
#endif /* UDPTABLE_IS_TABLE */
374
* The cache-handler loading routine is the main
375
* place for architecture-specific code
377
* Load into either a table structure, or a linked list
378
* depending on the system architecture
384
udpTable_load(netsnmp_cache *cache, void *vmagic)
392
udpTable_free(NULL, NULL);
394
if ((fd = open_mib("/dev/ip", O_RDONLY, 0, NM_ASYNC_OFF)) >= 0) {
395
p.objid = ID_udpLsnNumEnt;
396
p.buffer = (void *) &val;
399
if ((ret = get_mib_info(fd, &p)) == 0)
403
ulen = (unsigned) udp_size *sizeof(mib_udpLsnEnt);
404
udp_head = (mib_udpLsnEnt *) malloc(ulen);
405
p.objid = ID_udpLsnTable;
406
p.buffer = (void *) udp_head;
408
if ((ret = get_mib_info(fd, &p)) < 0) {
417
DEBUGMSGTL(("mibII/udpTable", "Loaded UDP Table\n"));
420
DEBUGMSGTL(("mibII/udpTable", "Failed to load UDP Table (hpux11)\n"));
427
udpTable_load(netsnmp_cache *cache, void *vmagic)
432
udpTable_free(cache, NULL);
434
if (!(in = fopen("/proc/net/udp", "r"))) {
435
DEBUGMSGTL(("mibII/udpTable", "Failed to load UDP Table (linux1)\n"));
436
snmp_log(LOG_ERR, "snmpd: cannot open /proc/net/udp ...\n");
441
* scan proc-file and build up a linked list
442
* This will actually be built up in reverse,
443
* but since the entries are unsorted, that doesn't matter.
445
while (line == fgets(line, sizeof(line), in)) {
446
struct inpcb pcb, *nnew;
447
unsigned int state, lport;
449
if (3 != sscanf(line, "%*d: %x:%x %*x:%*x %x",
450
&pcb.inp_laddr.s_addr, &lport, &state))
453
if (state != 7) /* fix me: UDP_LISTEN ??? */
456
pcb.inp_lport = htons((unsigned short) (lport));
457
pcb.inp_fport = htons(pcb.inp_fport);
459
nnew = SNMP_MALLOC_TYPEDEF(struct inpcb);
462
memcpy(nnew, &pcb, sizeof(struct inpcb));
463
nnew->inp_next = udp_head;
469
DEBUGMSGTL(("mibII/udpTable", "Loaded UDP Table\n"));
476
UDP_Cmp(void *addr, void *ep)
478
if (memcmp((mib2_udpEntry_t *) ep, (mib2_udpEntry_t *) addr,
479
sizeof(mib2_udpEntry_t)) == 0)
487
udpTable_load(netsnmp_cache *cache, void *vmagic)
489
mib2_udpEntry_t entry;
490
netsnmp_udpEntry *nnew;
491
netsnmp_udpEntry *prev_entry = NULL;
494
udpTable_free(NULL, NULL);
496
if (getMibstat(MIB_UDP_LISTEN, &entry, sizeof(mib2_udpEntry_t),
497
GET_FIRST, &UDP_Cmp, &entry) != 0) {
498
DEBUGMSGTL(("mibII/udpTable", "Failed to load UDP Table (solaris)\n"));
504
* Not interested in 'idle' entries, apparently....
506
if (entry.udpEntryInfo.ue_state != MIB2_UDP_idle) {
508
* Build up a linked list copy of the getMibstat results
509
* Note that since getMibstat returns rows in sorted order,
510
* we need to retain this order while building the list
511
* so new entries are added onto the end of the list.
513
nnew = SNMP_MALLOC_TYPEDEF(netsnmp_udpEntry);
516
memcpy(&(nnew->entry), &entry, sizeof(mib2_udpEntry_t));
520
prev_entry->inp_next = nnew;
524
if (getMibstat(MIB_UDP_LISTEN, &entry, sizeof(mib2_udpEntry_t),
525
GET_NEXT, &UDP_Cmp, &entry) != 0)
530
DEBUGMSGTL(("mibII/udpTable", "Loaded UDP Table\n"));
533
DEBUGMSGTL(("mibII/udpTable", "Failed to load UDP Table (solaris)\n"));
540
udpTable_load(netsnmp_cache *cache, void *vmagic)
542
PMIB_UDPTABLE pUdpTable = NULL;
543
DWORD dwActualSize = 0;
544
DWORD status = NO_ERROR;
547
* query for the buffer size needed
549
status = GetUdpTable(pUdpTable, &dwActualSize, TRUE);
550
if (status == ERROR_INSUFFICIENT_BUFFER) {
551
pUdpTable = (PMIB_UDPTABLE) malloc(dwActualSize);
552
if (pUdpTable != NULL) {
554
* Get the sorted UDP table
556
status = GetUdpTable(pUdpTable, &dwActualSize, TRUE);
559
if (status == NO_ERROR) {
560
DEBUGMSGTL(("mibII/udpTable", "Loaded UDP Table\n"));
561
udp_size = pUdpTable->dwNumEntries -1; /* entries are counted starting with 0 */
562
udp_head = pUdpTable->table;
565
DEBUGMSGTL(("mibII/udpTable", "Failed to load UDP Table (win32)\n"));
572
#if (defined(CAN_USE_SYSCTL) && defined(UDPCTL_PCBLIST))
574
udpTable_load(netsnmp_cache *cache, void *vmagic)
577
int sname[] = { CTL_NET, PF_INET, IPPROTO_UDP, UDPCTL_PCBLIST };
578
char *udpcb_buf = NULL;
579
struct xinpgen *xig = NULL;
582
udpTable_free(NULL, NULL);
585
* Read in the buffer containing the UDP table data
588
if (sysctl(sname, 4, 0, &len, 0, 0) < 0 ||
589
(udpcb_buf = malloc(len)) == NULL)
591
if (sysctl(sname, 4, udpcb_buf, &len, 0, 0) < 0) {
597
* Unpick this into the constituent 'xinpgen' structures, and extract
598
* the 'inpcb' elements into a linked list (built in reverse)
600
xig = (struct xinpgen *) udpcb_buf;
601
xig = (struct xinpgen *) ((char *) xig + xig->xig_len);
603
while (xig && (xig->xig_len > sizeof(struct xinpgen))) {
604
nnew = SNMP_MALLOC_TYPEDEF(struct inpcb);
607
memcpy(nnew, ((struct xinpcb *) xig)->xi_inp, sizeof(struct inpcb));
609
nnew->next = udp_head; /* XXX - ?? Check 'next' pointer */
611
xig = (struct xinpgen *) ((char *) xig + xig->xig_len);
616
DEBUGMSGTL(("mibII/udpTable", "Loaded UDP Table\n"));
619
DEBUGMSGTL(("mibII/udpTable", "Failed to load UDP Table (sysctl)\n"));
622
#else /* (defined(CAN_USE_SYSCTL) && defined(UDPCTL_PCBLIST)) */
625
udpTable_load(netsnmp_cache *cache, void *vmagic)
627
struct inpcbtable table;
628
struct inpcb *nnew, *entry;
630
udpTable_free(NULL, NULL);
632
if (!auto_nlist(UDB_SYMBOL, (char *) &table, sizeof(table))) {
633
DEBUGMSGTL(("mibII/udpTable", "Failed to read inpcbtable\n"));
638
* Set up a linked list
640
entry = table.inpt_queue.cqh_first;
643
nnew = SNMP_MALLOC_TYPEDEF(struct inpcb);
646
klookup((unsigned long) entry, (char *) nnew, sizeof(struct inpcb));
648
entry = nnew->inp_queue.cqe_next; /* Next kernel entry */
649
nnew->inp_queue.cqe_next = udp_head;
652
if (entry == table.inpt_queue.cqh_first)
657
DEBUGMSGTL(("mibII/udpTable", "Loaded UDP Table\n"));
660
DEBUGMSGTL(("mibII/udpTable", "Failed to load UDP Table (pcb_table)\n"));
664
#else /* PCB_TABLE */
667
udpTable_load(netsnmp_cache *cache, void *vmagic)
669
struct inpcb udp_inpcb;
670
struct inpcb *nnew, *entry;
672
udpTable_free(NULL, NULL);
674
if (!auto_nlist(UDB_SYMBOL, (char *) &udp_inpcb, sizeof(udp_inpcb))) {
675
DEBUGMSGTL(("mibII/udpTable", "Failed to read udb_symbol\n"));
680
* Set up a linked list
682
entry = udp_inpcb.INP_NEXT_SYMBOL;
685
nnew = SNMP_MALLOC_TYPEDEF(struct inpcb);
688
klookup((unsigned long) entry, (char *) nnew, sizeof(struct inpcb));
690
entry = nnew->INP_NEXT_SYMBOL; /* Next kernel entry */
691
nnew->INP_NEXT_SYMBOL = udp_head;
694
if (entry == udp_inpcb.INP_NEXT_SYMBOL)
699
DEBUGMSGTL(("mibII/udpTable", "Loaded UDP Table\n"));
702
DEBUGMSGTL(("mibII/udpTable", "Failed to load UDP Table (udb_symbol)\n"));
706
#else /* UDB_SYMBOL */
708
udpTable_load(netsnmp_cache *cache, void *vmagic)
710
DEBUGMSGTL(("mibII/udpTable", "Loading UDP Table not implemented\n"));
713
#endif /* UDB_SYMBOL */
714
#endif /* PCB_TABLE */
715
#endif /* (defined(CAN_USE_SYSCTL) && defined(UDPCTL_PCBLIST)) */
718
#endif /* solaris2 */