0a47879cf77ff9365d3031de0f12702efd75c59c
[asterisk/asterisk.git] / res / snmp / agent.c
1 /*
2  * Copyright (C) 2006 Voop as
3  * Thorsten Lockert <tholo@voop.as>
4  *
5  * This program is free software, distributed under the terms of
6  * the GNU General Public License Version 2. See the LICENSE file
7  * at the top of the source tree.
8  */
9
10 /*! \file
11  *
12  * \brief SNMP Agent / SubAgent support for Asterisk
13  *
14  * \author Thorsten Lockert <tholo@voop.as>
15  */
16
17 #include "asterisk.h"
18
19 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
20
21 /*
22  * There is some collision collision between netsmp and asterisk names,
23  * causing build under AST_DEVMODE to fail.
24  *
25  * The following PACKAGE_* macros are one place.
26  * Also netsnmp has an improper check for HAVE_DMALLOC_H, using
27  *    #if HAVE_DMALLOC_H   instead of #ifdef HAVE_DMALLOC_H
28  * As a countermeasure we define it to 0, however this will fail
29  * when the proper check is implemented.
30  */
31 #ifdef PACKAGE_NAME
32 #undef PACKAGE_NAME
33 #endif
34 #ifdef PACKAGE_BUGREPORT
35 #undef PACKAGE_BUGREPORT
36 #endif
37 #ifdef PACKAGE_STRING
38 #undef PACKAGE_STRING
39 #endif
40 #ifdef PACKAGE_TARNAME
41 #undef PACKAGE_TARNAME
42 #endif
43 #ifdef PACKAGE_VERSION
44 #undef PACKAGE_VERSION
45 #endif
46 #ifndef HAVE_DMALLOC_H
47 #define HAVE_DMALLOC_H 0        /* XXX we shouldn't do this */
48 #endif
49
50 #if defined(__OpenBSD__)
51 /*
52  * OpenBSD uses old "legacy" cc which has a rather pedantic builtin preprocessor.
53  * Using a macro which is not #defined throws an error.
54  */
55 #define __NetBSD_Version__ 0
56 #endif
57
58 #include <net-snmp/net-snmp-config.h>
59 #include <net-snmp/net-snmp-includes.h>
60 #include <net-snmp/agent/net-snmp-agent-includes.h>
61
62 #include "asterisk/paths.h"     /* need ast_config_AST_SOCKET */
63 #include "asterisk/channel.h"
64 #include "asterisk/logger.h"
65 #include "asterisk/options.h"
66 #include "asterisk/indications.h"
67 #include "asterisk/ast_version.h"
68 #include "asterisk/pbx.h"
69
70 /* Colission between Net-SNMP and Asterisk */
71 #define unload_module ast_unload_module
72 #include "asterisk/module.h"
73 #undef unload_module
74
75 #include "agent.h"
76
77 /* Helper functions in Net-SNMP, header file not installed by default */
78 int header_generic(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **);
79 int header_simple_table(struct variable *, oid *, size_t *, int, size_t *, WriteMethod **, int);
80 int register_sysORTable(oid *, size_t, const char *);
81 int unregister_sysORTable(oid *, size_t);
82
83 /* Forward declaration */
84 static void init_asterisk_mib(void);
85
86 /*
87  * Anchor for all the Asterisk MIB values
88  */
89 static oid asterisk_oid[] = { 1, 3, 6, 1, 4, 1, 22736, 1 };
90
91 /*
92  * MIB values -- these correspond to values in the Asterisk MIB,
93  * and MUST be kept in sync with the MIB for things to work as
94  * expected.
95  */
96 #define ASTVERSION                              1
97 #define         ASTVERSTRING                    1
98 #define         ASTVERTAG                               2
99
100 #define ASTCONFIGURATION                2
101 #define         ASTCONFUPTIME                   1
102 #define         ASTCONFRELOADTIME               2
103 #define         ASTCONFPID                              3
104 #define         ASTCONFSOCKET                   4
105 #define         ASTCONFACTIVECALLS      5
106 #define         ASTCONFPROCESSEDCALLS   6
107
108 #define ASTMODULES                              3
109 #define         ASTMODCOUNT                             1
110
111 #define ASTINDICATIONS                  4
112 #define         ASTINDCOUNT                             1
113 #define         ASTINDCURRENT                   2
114
115 #define         ASTINDTABLE                             3
116 #define                 ASTINDINDEX                             1
117 #define                 ASTINDCOUNTRY                   2
118 #define                 ASTINDALIAS                             3
119 #define                 ASTINDDESCRIPTION               4
120
121 #define ASTCHANNELS                             5
122 #define         ASTCHANCOUNT                    1
123
124 #define         ASTCHANTABLE                    2
125 #define                 ASTCHANINDEX                    1
126 #define                 ASTCHANNAME                             2
127 #define                 ASTCHANLANGUAGE                 3
128 #define                 ASTCHANTYPE                             4
129 #define                 ASTCHANMUSICCLASS               5
130 #define                 ASTCHANBRIDGE                   6
131 #define                 ASTCHANMASQ                             7
132 #define                 ASTCHANMASQR                    8
133 #define                 ASTCHANWHENHANGUP               9
134 #define                 ASTCHANAPP                              10
135 #define                 ASTCHANDATA                             11
136 #define                 ASTCHANCONTEXT                  12
137 #define                 ASTCHANMACROCONTEXT             13
138 #define                 ASTCHANMACROEXTEN               14
139 #define                 ASTCHANMACROPRI                 15
140 #define                 ASTCHANEXTEN                    16
141 #define                 ASTCHANPRI                              17
142 #define                 ASTCHANACCOUNTCODE              18
143 #define                 ASTCHANFORWARDTO                19
144 #define                 ASTCHANUNIQUEID                 20
145 #define                 ASTCHANCALLGROUP                21
146 #define                 ASTCHANPICKUPGROUP              22
147 #define                 ASTCHANSTATE                    23
148 #define                 ASTCHANMUTED                    24
149 #define                 ASTCHANRINGS                    25
150 #define                 ASTCHANCIDDNID                  26
151 #define                 ASTCHANCIDNUM                   27
152 #define                 ASTCHANCIDNAME                  28
153 #define                 ASTCHANCIDANI                   29
154 #define                 ASTCHANCIDRDNIS                 30
155 #define                 ASTCHANCIDPRES                  31
156 #define                 ASTCHANCIDANI2                  32
157 #define                 ASTCHANCIDTON                   33
158 #define                 ASTCHANCIDTNS                   34
159 #define                 ASTCHANAMAFLAGS                 35
160 #define                 ASTCHANADSI                             36
161 #define                 ASTCHANTONEZONE                 37
162 #define                 ASTCHANHANGUPCAUSE              38
163 #define                 ASTCHANVARIABLES                39
164 #define                 ASTCHANFLAGS                    40
165 #define                 ASTCHANTRANSFERCAP              41
166
167 #define         ASTCHANTYPECOUNT                3
168
169 #define         ASTCHANTYPETABLE                4
170 #define                 ASTCHANTYPEINDEX                1
171 #define                 ASTCHANTYPENAME                 2
172 #define                 ASTCHANTYPEDESC                 3
173 #define                 ASTCHANTYPEDEVSTATE             4
174 #define                 ASTCHANTYPEINDICATIONS  5
175 #define                 ASTCHANTYPETRANSFER             6
176 #define                 ASTCHANTYPECHANNELS             7
177
178 #define         ASTCHANSCALARS                  5
179 #define                 ASTCHANBRIDGECOUNT              1
180
181 void *agent_thread(void *arg)
182 {
183         ast_verb(2, "Starting %sAgent\n", res_snmp_agentx_subagent ? "Sub" : "");
184
185         snmp_enable_stderrlog();
186
187         if (res_snmp_agentx_subagent)
188                 netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,
189                                                            NETSNMP_DS_AGENT_ROLE,
190                                                            1);
191
192         init_agent("asterisk");
193
194         init_asterisk_mib();
195
196         init_snmp("asterisk");
197
198         if (!res_snmp_agentx_subagent)
199                 init_master_agent();
200
201         while (res_snmp_dont_stop)
202                 agent_check_and_process(1);
203
204         snmp_shutdown("asterisk");
205
206         ast_verb(2, "Terminating %sAgent\n", res_snmp_agentx_subagent ? "Sub" : "");
207
208         return NULL;
209 }
210
211 static u_char *
212 ast_var_channels(struct variable *vp, oid *name, size_t *length,
213                                  int exact, size_t *var_len, WriteMethod **write_method)
214 {
215         static unsigned long long_ret;
216
217         if (header_generic(vp, name, length, exact, var_len, write_method))
218                 return NULL;
219
220         if (vp->magic != ASTCHANCOUNT)
221                 return NULL;
222
223         long_ret = ast_active_channels();
224
225         return (u_char *)&long_ret;
226 }
227
228 static u_char *ast_var_channels_table(struct variable *vp, oid *name, size_t *length,
229                                                                         int exact, size_t *var_len, WriteMethod **write_method)
230 {
231         static unsigned long long_ret;
232         static u_char bits_ret[2];
233         static char string_ret[256];
234         struct ast_channel *chan, *bridge;
235         struct timeval tval;
236         u_char *ret = NULL;
237         int i, bit;
238         struct ast_str *out = ast_str_alloca(2048);
239
240         if (header_simple_table(vp, name, length, exact, var_len, write_method, ast_active_channels()))
241                 return NULL;
242
243         i = name[*length - 1] - 1;
244         for (chan = ast_channel_walk_locked(NULL);
245                  chan && i;
246                  chan = ast_channel_walk_locked(chan), i--)
247                 ast_channel_unlock(chan);
248         if (chan == NULL)
249                 return NULL;
250         *var_len = sizeof(long_ret);
251
252         switch (vp->magic) {
253         case ASTCHANINDEX:
254                 long_ret = name[*length - 1];
255                 ret = (u_char *)&long_ret;
256                 break;
257         case ASTCHANNAME:
258                 if (!ast_strlen_zero(chan->name)) {
259                         strncpy(string_ret, chan->name, sizeof(string_ret));
260                         string_ret[sizeof(string_ret) - 1] = '\0';
261                         *var_len = strlen(string_ret);
262                         ret = (u_char *)string_ret;
263                 }
264                 break;
265         case ASTCHANLANGUAGE:
266                 if (!ast_strlen_zero(chan->language)) {
267                         strncpy(string_ret, chan->language, sizeof(string_ret));
268                         string_ret[sizeof(string_ret) - 1] = '\0';
269                         *var_len = strlen(string_ret);
270                         ret = (u_char *)string_ret;
271                 }
272                 break;
273         case ASTCHANTYPE:
274                 strncpy(string_ret, chan->tech->type, sizeof(string_ret));
275                 string_ret[sizeof(string_ret) - 1] = '\0';
276                 *var_len = strlen(string_ret);
277                 ret = (u_char *)string_ret;
278                 break;
279         case ASTCHANMUSICCLASS:
280                 if (!ast_strlen_zero(chan->musicclass)) {
281                         strncpy(string_ret, chan->musicclass, sizeof(string_ret));
282                         string_ret[sizeof(string_ret) - 1] = '\0';
283                         *var_len = strlen(string_ret);
284                         ret = (u_char *)string_ret;
285                 }
286                 break;
287         case ASTCHANBRIDGE:
288                 if ((bridge = ast_bridged_channel(chan)) != NULL) {
289                         strncpy(string_ret, bridge->name, sizeof(string_ret));
290                         string_ret[sizeof(string_ret) - 1] = '\0';
291                         *var_len = strlen(string_ret);
292                         ret = (u_char *)string_ret;
293                 }
294                 break;
295         case ASTCHANMASQ:
296                 if (chan->masq && !ast_strlen_zero(chan->masq->name)) {
297                         strncpy(string_ret, chan->masq->name, sizeof(string_ret));
298                         string_ret[sizeof(string_ret) - 1] = '\0';
299                         *var_len = strlen(string_ret);
300                         ret = (u_char *)string_ret;
301                 }
302                 break;
303         case ASTCHANMASQR:
304                 if (chan->masqr && !ast_strlen_zero(chan->masqr->name)) {
305                         strncpy(string_ret, chan->masqr->name, sizeof(string_ret));
306                         string_ret[sizeof(string_ret) - 1] = '\0';
307                         *var_len = strlen(string_ret);
308                         ret = (u_char *)string_ret;
309                 }
310                 break;
311         case ASTCHANWHENHANGUP:
312                 if (!ast_tvzero(chan->whentohangup)) {
313                         gettimeofday(&tval, NULL);
314                         long_ret = difftime(chan->whentohangup.tv_sec, tval.tv_sec) * 100 - tval.tv_usec / 10000;
315                         ret= (u_char *)&long_ret;
316                 }
317                 break;
318         case ASTCHANAPP:
319                 if (chan->appl) {
320                         strncpy(string_ret, chan->appl, sizeof(string_ret));
321                         string_ret[sizeof(string_ret) - 1] = '\0';
322                         *var_len = strlen(string_ret);
323                         ret = (u_char *)string_ret;
324                 }
325                 break;
326         case ASTCHANDATA:
327                 if (chan->data) {
328                         strncpy(string_ret, chan->data, sizeof(string_ret));
329                         string_ret[sizeof(string_ret) - 1] = '\0';
330                         *var_len = strlen(string_ret);
331                         ret = (u_char *)string_ret;
332                 }
333                 break;
334         case ASTCHANCONTEXT:
335                 strncpy(string_ret, chan->context, sizeof(string_ret));
336                 string_ret[sizeof(string_ret) - 1] = '\0';
337                 *var_len = strlen(string_ret);
338                 ret = (u_char *)string_ret;
339                 break;
340         case ASTCHANMACROCONTEXT:
341                 strncpy(string_ret, chan->macrocontext, sizeof(string_ret));
342                 string_ret[sizeof(string_ret) - 1] = '\0';
343                 *var_len = strlen(string_ret);
344                 ret = (u_char *)string_ret;
345                 break;
346         case ASTCHANMACROEXTEN:
347                 strncpy(string_ret, chan->macroexten, sizeof(string_ret));
348                 string_ret[sizeof(string_ret) - 1] = '\0';
349                 *var_len = strlen(string_ret);
350                 ret = (u_char *)string_ret;
351                 break;
352         case ASTCHANMACROPRI:
353                 long_ret = chan->macropriority;
354                 ret = (u_char *)&long_ret;
355                 break;
356         case ASTCHANEXTEN:
357                 strncpy(string_ret, chan->exten, sizeof(string_ret));
358                 string_ret[sizeof(string_ret) - 1] = '\0';
359                 *var_len = strlen(string_ret);
360                 ret = (u_char *)string_ret;
361                 break;
362         case ASTCHANPRI:
363                 long_ret = chan->priority;
364                 ret = (u_char *)&long_ret;
365                 break;
366         case ASTCHANACCOUNTCODE:
367                 if (!ast_strlen_zero(chan->accountcode)) {
368                         strncpy(string_ret, chan->accountcode, sizeof(string_ret));
369                         string_ret[sizeof(string_ret) - 1] = '\0';
370                         *var_len = strlen(string_ret);
371                         ret = (u_char *)string_ret;
372                 }
373                 break;
374         case ASTCHANFORWARDTO:
375                 if (!ast_strlen_zero(chan->call_forward)) {
376                         strncpy(string_ret, chan->call_forward, sizeof(string_ret));
377                         string_ret[sizeof(string_ret) - 1] = '\0';
378                         *var_len = strlen(string_ret);
379                         ret = (u_char *)string_ret;
380                 }
381                 break;
382         case ASTCHANUNIQUEID:
383                 strncpy(string_ret, chan->uniqueid, sizeof(string_ret));
384                 string_ret[sizeof(string_ret) - 1] = '\0';
385                 *var_len = strlen(string_ret);
386                 ret = (u_char *)string_ret;
387                 break;
388         case ASTCHANCALLGROUP:
389                 long_ret = chan->callgroup;
390                 ret = (u_char *)&long_ret;
391                 break;
392         case ASTCHANPICKUPGROUP:
393                 long_ret = chan->pickupgroup;
394                 ret = (u_char *)&long_ret;
395                 break;
396         case ASTCHANSTATE:
397                 long_ret = chan->_state & 0xffff;
398                 ret = (u_char *)&long_ret;
399                 break;
400         case ASTCHANMUTED:
401                 long_ret = chan->_state & AST_STATE_MUTE ? 1 : 2;
402                 ret = (u_char *)&long_ret;
403                 break;
404         case ASTCHANRINGS:
405                 long_ret = chan->rings;
406                 ret = (u_char *)&long_ret;
407                 break;
408         case ASTCHANCIDDNID:
409                 if (chan->cid.cid_dnid) {
410                         strncpy(string_ret, chan->cid.cid_dnid, sizeof(string_ret));
411                         string_ret[sizeof(string_ret) - 1] = '\0';
412                         *var_len = strlen(string_ret);
413                         ret = (u_char *)string_ret;
414                 }
415                 break;
416         case ASTCHANCIDNUM:
417                 if (chan->cid.cid_num) {
418                         strncpy(string_ret, chan->cid.cid_num, sizeof(string_ret));
419                         string_ret[sizeof(string_ret) - 1] = '\0';
420                         *var_len = strlen(string_ret);
421                         ret = (u_char *)string_ret;
422                 }
423                 break;
424         case ASTCHANCIDNAME:
425                 if (chan->cid.cid_name) {
426                         strncpy(string_ret, chan->cid.cid_name, sizeof(string_ret));
427                         string_ret[sizeof(string_ret) - 1] = '\0';
428                         *var_len = strlen(string_ret);
429                         ret = (u_char *)string_ret;
430                 }
431                 break;
432         case ASTCHANCIDANI:
433                 if (chan->cid.cid_ani) {
434                         strncpy(string_ret, chan->cid.cid_ani, sizeof(string_ret));
435                         string_ret[sizeof(string_ret) - 1] = '\0';
436                         *var_len = strlen(string_ret);
437                         ret = (u_char *)string_ret;
438                 }
439                 break;
440         case ASTCHANCIDRDNIS:
441                 if (chan->cid.cid_rdnis) {
442                         strncpy(string_ret, chan->cid.cid_rdnis, sizeof(string_ret));
443                         string_ret[sizeof(string_ret) - 1] = '\0';
444                         *var_len = strlen(string_ret);
445                         ret = (u_char *)string_ret;
446                 }
447                 break;
448         case ASTCHANCIDPRES:
449                 long_ret = chan->cid.cid_pres;
450                 ret = (u_char *)&long_ret;
451                 break;
452         case ASTCHANCIDANI2:
453                 long_ret = chan->cid.cid_ani2;
454                 ret = (u_char *)&long_ret;
455                 break;
456         case ASTCHANCIDTON:
457                 long_ret = chan->cid.cid_ton;
458                 ret = (u_char *)&long_ret;
459                 break;
460         case ASTCHANCIDTNS:
461                 long_ret = chan->cid.cid_tns;
462                 ret = (u_char *)&long_ret;
463                 break;
464         case ASTCHANAMAFLAGS:
465                 long_ret = chan->amaflags;
466                 ret = (u_char *)&long_ret;
467                 break;
468         case ASTCHANADSI:
469                 long_ret = chan->adsicpe;
470                 ret = (u_char *)&long_ret;
471                 break;
472         case ASTCHANTONEZONE:
473                 if (chan->zone) {
474                         strncpy(string_ret, chan->zone->country, sizeof(string_ret));
475                         string_ret[sizeof(string_ret) - 1] = '\0';
476                         *var_len = strlen(string_ret);
477                         ret = (u_char *)string_ret;
478                 }
479                 break;
480         case ASTCHANHANGUPCAUSE:
481                 long_ret = chan->hangupcause;
482                 ret = (u_char *)&long_ret;
483                 break;
484         case ASTCHANVARIABLES:
485                 if (pbx_builtin_serialize_variables(chan, &out)) {
486                         *var_len = ast_str_strlen(out);
487                         ret = (u_char *)ast_str_buffer(out);
488                 }
489                 break;
490         case ASTCHANFLAGS:
491                 bits_ret[0] = 0;
492                 for (bit = 0; bit < 8; bit++)
493                         bits_ret[0] |= ((chan->flags & (1 << bit)) >> bit) << (7 - bit);
494                 bits_ret[1] = 0;
495                 for (bit = 0; bit < 8; bit++)
496                         bits_ret[1] |= (((chan->flags >> 8) & (1 << bit)) >> bit) << (7 - bit);
497                 *var_len = 2;
498                 ret = bits_ret;
499                 break;
500         case ASTCHANTRANSFERCAP:
501                 long_ret = chan->transfercapability;
502                 ret = (u_char *)&long_ret;
503         default:
504                 break;
505         }
506         ast_channel_unlock(chan);
507         return ret;
508 }
509
510 static u_char *ast_var_channel_types(struct variable *vp, oid *name, size_t *length,
511                                                                    int exact, size_t *var_len, WriteMethod **write_method)
512 {
513         static unsigned long long_ret;
514         struct ast_variable *channel_types, *next;
515
516         if (header_generic(vp, name, length, exact, var_len, write_method))
517                 return NULL;
518
519         if (vp->magic != ASTCHANTYPECOUNT)
520                 return NULL;
521
522         for (long_ret = 0, channel_types = next = ast_channeltype_list(); next; next = next->next)
523                 long_ret++;
524         ast_variables_destroy(channel_types);
525
526         return (u_char *)&long_ret;
527 }
528
529 static u_char *ast_var_channel_types_table(struct variable *vp, oid *name, size_t *length,
530                                                                                 int exact, size_t *var_len, WriteMethod **write_method)
531 {
532         const struct ast_channel_tech *tech = NULL;
533         struct ast_variable *channel_types, *next;
534         static unsigned long long_ret;
535         struct ast_channel *chan;
536         u_long i;
537
538         if (header_simple_table(vp, name, length, exact, var_len, write_method, -1))
539                 return NULL;
540
541         channel_types = ast_channeltype_list();
542         for (i = 1, next = channel_types; next && i != name[*length - 1]; next = next->next, i++)
543                 ;
544         if (next != NULL)
545                 tech = ast_get_channel_tech(next->name);
546         ast_variables_destroy(channel_types);
547         if (next == NULL || tech == NULL)
548                 return NULL;
549         
550         switch (vp->magic) {
551         case ASTCHANTYPEINDEX:
552                 long_ret = name[*length - 1];
553                 return (u_char *)&long_ret;
554         case ASTCHANTYPENAME:
555                 *var_len = strlen(tech->type);
556                 return (u_char *)tech->type;
557         case ASTCHANTYPEDESC:
558                 *var_len = strlen(tech->description);
559                 return (u_char *)tech->description;
560         case ASTCHANTYPEDEVSTATE:
561                 long_ret = tech->devicestate ? 1 : 2;
562                 return (u_char *)&long_ret;
563         case ASTCHANTYPEINDICATIONS:
564                 long_ret = tech->indicate ? 1 : 2;
565                 return (u_char *)&long_ret;
566         case ASTCHANTYPETRANSFER:
567                 long_ret = tech->transfer ? 1 : 2;
568                 return (u_char *)&long_ret;
569         case ASTCHANTYPECHANNELS:
570                 long_ret = 0;
571                 for (chan = ast_channel_walk_locked(NULL); chan; chan = ast_channel_walk_locked(chan)) {
572                         if (chan->tech == tech)
573                                 long_ret++;
574                         ast_channel_unlock(chan);
575                 }
576                 return (u_char *)&long_ret;
577         default:
578                 break;
579         }
580         return NULL;
581 }
582
583 static u_char *ast_var_channel_bridge(struct variable *vp, oid *name, size_t *length,
584         int exact, size_t *var_len, WriteMethod **write_method)
585 {
586         static unsigned long long_ret;
587         struct ast_channel *chan = NULL;
588
589         long_ret = 0;
590         if (header_generic(vp, name, length, exact, var_len, write_method))
591                 return NULL;
592
593         while ((chan = ast_channel_walk_locked(chan))) {
594                 if (ast_bridged_channel(chan))
595                         long_ret++;
596                 ast_channel_unlock(chan);
597         }
598
599         *var_len = sizeof(long_ret);
600
601         return (vp->magic == ASTCHANBRIDGECOUNT) ? (u_char *) &long_ret : NULL;
602 }
603
604 static u_char *ast_var_Config(struct variable *vp, oid *name, size_t *length,
605                                                          int exact, size_t *var_len, WriteMethod **write_method)
606 {
607         static unsigned long long_ret;
608         struct timeval tval;
609
610         if (header_generic(vp, name, length, exact, var_len, write_method))
611                 return NULL;
612
613         switch (vp->magic) {
614         case ASTCONFUPTIME:
615                 gettimeofday(&tval, NULL);
616                 long_ret = difftime(tval.tv_sec, ast_startuptime.tv_sec) * 100 + tval.tv_usec / 10000 - ast_startuptime.tv_usec / 10000;
617                 return (u_char *)&long_ret;
618         case ASTCONFRELOADTIME:
619                 gettimeofday(&tval, NULL);
620                 if (ast_lastreloadtime.tv_sec)
621                         long_ret = difftime(tval.tv_sec, ast_lastreloadtime.tv_sec) * 100 + tval.tv_usec / 10000 - ast_lastreloadtime.tv_usec / 10000;
622                 else
623                         long_ret = difftime(tval.tv_sec, ast_startuptime.tv_sec) * 100 + tval.tv_usec / 10000 - ast_startuptime.tv_usec / 10000;
624                 return (u_char *)&long_ret;
625         case ASTCONFPID:
626                 long_ret = getpid();
627                 return (u_char *)&long_ret;
628         case ASTCONFSOCKET:
629                 *var_len = strlen(ast_config_AST_SOCKET);
630                 return (u_char *)ast_config_AST_SOCKET;
631         case ASTCONFACTIVECALLS:
632                 long_ret = ast_active_calls();
633                 return (u_char *)&long_ret;
634         case ASTCONFPROCESSEDCALLS:
635                 long_ret = ast_processed_calls();
636                 return (u_char *)&long_ret;
637         default:
638                 break;
639         }
640         return NULL;
641 }
642
643 static u_char *ast_var_indications(struct variable *vp, oid *name, size_t *length,
644                                                                   int exact, size_t *var_len, WriteMethod **write_method)
645 {
646         static unsigned long long_ret;
647         struct tone_zone *tz = NULL;
648
649         if (header_generic(vp, name, length, exact, var_len, write_method))
650                 return NULL;
651
652         switch (vp->magic) {
653         case ASTINDCOUNT:
654                 long_ret = 0;
655                 while ( (tz = ast_walk_indications(tz)) )
656                         long_ret++;
657
658                 return (u_char *)&long_ret;
659         case ASTINDCURRENT:
660                 tz = ast_get_indication_zone(NULL);
661                 if (tz) {
662                         *var_len = strlen(tz->country);
663                         return (u_char *)tz->country;
664                 }
665                 *var_len = 0;
666                 return NULL;
667         default:
668                 break;
669         }
670         return NULL;
671 }
672
673 static u_char *ast_var_indications_table(struct variable *vp, oid *name, size_t *length,
674                                                                            int exact, size_t *var_len, WriteMethod **write_method)
675 {
676         static unsigned long long_ret;
677         struct tone_zone *tz = NULL;
678         int i;
679
680         if (header_simple_table(vp, name, length, exact, var_len, write_method, -1))
681                 return NULL;
682
683         i = name[*length - 1] - 1;
684         while ( (tz = ast_walk_indications(tz)) && i )
685         i--;
686         if (tz == NULL)
687                 return NULL;
688
689         switch (vp->magic) {
690         case ASTINDINDEX:
691                 long_ret = name[*length - 1];
692                 return (u_char *)&long_ret;
693         case ASTINDCOUNTRY:
694                 *var_len = strlen(tz->country);
695                 return (u_char *)tz->country;
696         case ASTINDALIAS:
697                 if (tz->alias) {
698                         *var_len = strlen(tz->alias);
699                         return (u_char *)tz->alias;
700                 }
701                 return NULL;
702         case ASTINDDESCRIPTION:
703                 *var_len = strlen(tz->description);
704                 return (u_char *)tz->description;
705         default:
706                 break;
707         }
708         return NULL;
709 }
710
711 static int countmodule(const char *mod, const char *desc, int use, const char *like)
712 {
713         return 1;
714 }
715
716 static u_char *ast_var_Modules(struct variable *vp, oid *name, size_t *length,
717                                                           int exact, size_t *var_len, WriteMethod **write_method)
718 {
719         static unsigned long long_ret;
720
721         if (header_generic(vp, name, length, exact, var_len, write_method))
722                 return NULL;
723
724         if (vp->magic != ASTMODCOUNT)
725                 return NULL;
726
727         long_ret = ast_update_module_list(countmodule, NULL);
728
729         return (u_char *)&long_ret;
730 }
731
732 static u_char *ast_var_Version(struct variable *vp, oid *name, size_t *length,
733                                                           int exact, size_t *var_len, WriteMethod **write_method)
734 {
735         static unsigned long long_ret;
736
737         if (header_generic(vp, name, length, exact, var_len, write_method))
738                 return NULL;
739
740         switch (vp->magic) {
741         case ASTVERSTRING:
742         {
743                 const char *version = ast_get_version();
744                 *var_len = strlen(version);
745                 return (u_char *)version;
746         }
747         case ASTVERTAG:
748                 sscanf(ast_get_version_num(), "%lu", &long_ret);
749                 return (u_char *)&long_ret;
750         default:
751                 break;
752         }
753         return NULL;
754 }
755
756 static int term_asterisk_mib(int majorID, int minorID, void *serverarg, void *clientarg)
757 {
758         unregister_sysORTable(asterisk_oid, OID_LENGTH(asterisk_oid));
759         return 0;
760 }
761
762 static void init_asterisk_mib(void)
763 {
764         static struct variable4 asterisk_vars[] = {
765                 {ASTVERSTRING,           ASN_OCTET_STR, RONLY, ast_var_Version,             2, {ASTVERSION, ASTVERSTRING}},
766                 {ASTVERTAG,              ASN_UNSIGNED,  RONLY, ast_var_Version,             2, {ASTVERSION, ASTVERTAG}},
767                 {ASTCONFUPTIME,          ASN_TIMETICKS, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFUPTIME}},
768                 {ASTCONFRELOADTIME,      ASN_TIMETICKS, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFRELOADTIME}},
769                 {ASTCONFPID,             ASN_INTEGER,   RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFPID}},
770                 {ASTCONFSOCKET,          ASN_OCTET_STR, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFSOCKET}},
771                 {ASTCONFACTIVECALLS,     ASN_GAUGE,     RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFACTIVECALLS}},
772                 {ASTCONFPROCESSEDCALLS,  ASN_COUNTER,   RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFPROCESSEDCALLS}},
773                 {ASTMODCOUNT,            ASN_INTEGER,   RONLY, ast_var_Modules ,            2, {ASTMODULES, ASTMODCOUNT}},
774                 {ASTINDCOUNT,            ASN_INTEGER,   RONLY, ast_var_indications,         2, {ASTINDICATIONS, ASTINDCOUNT}},
775                 {ASTINDCURRENT,          ASN_OCTET_STR, RONLY, ast_var_indications,         2, {ASTINDICATIONS, ASTINDCURRENT}},
776                 {ASTINDINDEX,            ASN_INTEGER,   RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDINDEX}},
777                 {ASTINDCOUNTRY,          ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDCOUNTRY}},
778                 {ASTINDALIAS,            ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDALIAS}},
779                 {ASTINDDESCRIPTION,      ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDDESCRIPTION}},
780                 {ASTCHANCOUNT,           ASN_GAUGE,     RONLY, ast_var_channels,            2, {ASTCHANNELS, ASTCHANCOUNT}},
781                 {ASTCHANINDEX,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANINDEX}},
782                 {ASTCHANNAME,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANNAME}},
783                 {ASTCHANLANGUAGE,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANLANGUAGE}},
784                 {ASTCHANTYPE,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTYPE}},
785                 {ASTCHANMUSICCLASS,      ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMUSICCLASS}},
786                 {ASTCHANBRIDGE,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANBRIDGE}},
787                 {ASTCHANMASQ,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMASQ}},
788                 {ASTCHANMASQR,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMASQR}},
789                 {ASTCHANWHENHANGUP,      ASN_TIMETICKS, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANWHENHANGUP}},
790                 {ASTCHANAPP,             ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANAPP}},
791                 {ASTCHANDATA,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANDATA}},
792                 {ASTCHANCONTEXT,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCONTEXT}},
793                 {ASTCHANMACROCONTEXT,    ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROCONTEXT}},
794                 {ASTCHANMACROEXTEN,      ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROEXTEN}},
795                 {ASTCHANMACROPRI,        ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROPRI}},
796                 {ASTCHANEXTEN,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANEXTEN}},
797                 {ASTCHANPRI,             ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANPRI}},
798                 {ASTCHANACCOUNTCODE,     ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANACCOUNTCODE}},
799                 {ASTCHANFORWARDTO,       ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANFORWARDTO}},
800                 {ASTCHANUNIQUEID,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANUNIQUEID}},
801                 {ASTCHANCALLGROUP,       ASN_UNSIGNED,  RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCALLGROUP}},
802                 {ASTCHANPICKUPGROUP,     ASN_UNSIGNED,  RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANPICKUPGROUP}},
803                 {ASTCHANSTATE,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANSTATE}},
804                 {ASTCHANMUTED,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMUTED}},
805                 {ASTCHANRINGS,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANRINGS}},
806                 {ASTCHANCIDDNID,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDDNID}},
807                 {ASTCHANCIDNUM,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDNUM}},
808                 {ASTCHANCIDNAME,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDNAME}},
809                 {ASTCHANCIDANI,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDANI}},
810                 {ASTCHANCIDRDNIS,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDRDNIS}},
811                 {ASTCHANCIDPRES,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDPRES}},
812                 {ASTCHANCIDANI2,         ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDANI2}},
813                 {ASTCHANCIDTON,          ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDTON}},
814                 {ASTCHANCIDTNS,          ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDTNS}},
815                 {ASTCHANAMAFLAGS,        ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANAMAFLAGS}},
816                 {ASTCHANADSI,            ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANADSI}},
817                 {ASTCHANTONEZONE,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTONEZONE}},
818                 {ASTCHANHANGUPCAUSE,     ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANHANGUPCAUSE}},
819                 {ASTCHANVARIABLES,       ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANVARIABLES}},
820                 {ASTCHANFLAGS,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANFLAGS}},
821                 {ASTCHANTRANSFERCAP,     ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTRANSFERCAP}},
822                 {ASTCHANTYPECOUNT,       ASN_INTEGER,   RONLY, ast_var_channel_types,       2, {ASTCHANNELS, ASTCHANTYPECOUNT}},
823                 {ASTCHANTYPEINDEX,       ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEINDEX}},
824                 {ASTCHANTYPENAME,        ASN_OCTET_STR, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPENAME}},
825                 {ASTCHANTYPEDESC,        ASN_OCTET_STR, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEDESC}},
826                 {ASTCHANTYPEDEVSTATE,    ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEDEVSTATE}},
827                 {ASTCHANTYPEINDICATIONS, ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEINDICATIONS}},
828                 {ASTCHANTYPETRANSFER,    ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPETRANSFER}},
829                 {ASTCHANTYPECHANNELS,    ASN_GAUGE,     RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPECHANNELS}},
830                 {ASTCHANBRIDGECOUNT,     ASN_GAUGE,     RONLY, ast_var_channel_bridge,      3, {ASTCHANNELS, ASTCHANSCALARS, ASTCHANBRIDGECOUNT}},
831         };
832
833         register_sysORTable(asterisk_oid, OID_LENGTH(asterisk_oid),
834                         "ASTERISK-MIB implementation for Asterisk.");
835
836         REGISTER_MIB("res_snmp", asterisk_vars, variable4, asterisk_oid);
837
838         snmp_register_callback(SNMP_CALLBACK_LIBRARY,
839                            SNMP_CALLBACK_SHUTDOWN,
840                            term_asterisk_mib, NULL);
841 }
842
843 /*
844  * Local Variables:
845  * c-basic-offset: 4
846  * c-file-offsets: ((case-label . 0))
847  * tab-width: 4
848  * indent-tabs-mode: t
849  * End:
850  */