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