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