035c4945d43062ff4054fb3e90ed1ca6bd0aba52
[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_verb(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_verb(2, "Terminating %sAgent\n", res_snmp_agentx_subagent ? "Sub" : "");
172
173         return NULL;
174 }
175
176 static u_char *
177 ast_var_channels(struct variable *vp, oid *name, size_t *length,
178                                  int exact, size_t *var_len, WriteMethod **write_method)
179 {
180         static unsigned long long_ret;
181
182         if (header_generic(vp, name, length, exact, var_len, write_method))
183                 return NULL;
184
185         if (vp->magic != ASTCHANCOUNT)
186                 return NULL;
187
188         long_ret = ast_active_channels();
189
190         return (u_char *)&long_ret;
191 }
192
193 static u_char *ast_var_channels_table(struct variable *vp, oid *name, size_t *length,
194                                                                         int exact, size_t *var_len, WriteMethod **write_method)
195 {
196         static unsigned long long_ret;
197         static u_char bits_ret[2];
198         static char string_ret[256];
199         struct ast_channel *chan, *bridge;
200         struct timeval tval;
201         u_char *ret = NULL;
202         int i, bit;
203         struct ast_str *out = ast_str_alloca(2048);
204
205         if (header_simple_table(vp, name, length, exact, var_len, write_method, ast_active_channels()))
206                 return NULL;
207
208         i = name[*length - 1] - 1;
209         for (chan = ast_channel_walk_locked(NULL);
210                  chan && i;
211                  chan = ast_channel_walk_locked(chan), i--)
212                 ast_channel_unlock(chan);
213         if (chan == NULL)
214                 return NULL;
215         *var_len = sizeof(long_ret);
216
217         switch (vp->magic) {
218         case ASTCHANINDEX:
219                 long_ret = name[*length - 1];
220                 ret = (u_char *)&long_ret;
221                 break;
222         case ASTCHANNAME:
223                 if (!ast_strlen_zero(chan->name)) {
224                         strncpy(string_ret, chan->name, sizeof(string_ret));
225                         string_ret[sizeof(string_ret) - 1] = '\0';
226                         *var_len = strlen(string_ret);
227                         ret = (u_char *)string_ret;
228                 }
229                 break;
230         case ASTCHANLANGUAGE:
231                 if (!ast_strlen_zero(chan->language)) {
232                         strncpy(string_ret, chan->language, sizeof(string_ret));
233                         string_ret[sizeof(string_ret) - 1] = '\0';
234                         *var_len = strlen(string_ret);
235                         ret = (u_char *)string_ret;
236                 }
237                 break;
238         case ASTCHANTYPE:
239                 strncpy(string_ret, chan->tech->type, sizeof(string_ret));
240                 string_ret[sizeof(string_ret) - 1] = '\0';
241                 *var_len = strlen(string_ret);
242                 ret = (u_char *)string_ret;
243                 break;
244         case ASTCHANMUSICCLASS:
245                 if (!ast_strlen_zero(chan->musicclass)) {
246                         strncpy(string_ret, chan->musicclass, sizeof(string_ret));
247                         string_ret[sizeof(string_ret) - 1] = '\0';
248                         *var_len = strlen(string_ret);
249                         ret = (u_char *)string_ret;
250                 }
251                 break;
252         case ASTCHANBRIDGE:
253                 if ((bridge = ast_bridged_channel(chan)) != NULL) {
254                         strncpy(string_ret, bridge->name, sizeof(string_ret));
255                         string_ret[sizeof(string_ret) - 1] = '\0';
256                         *var_len = strlen(string_ret);
257                         ret = (u_char *)string_ret;
258                 }
259                 break;
260         case ASTCHANMASQ:
261                 if (chan->masq && !ast_strlen_zero(chan->masq->name)) {
262                         strncpy(string_ret, chan->masq->name, sizeof(string_ret));
263                         string_ret[sizeof(string_ret) - 1] = '\0';
264                         *var_len = strlen(string_ret);
265                         ret = (u_char *)string_ret;
266                 }
267                 break;
268         case ASTCHANMASQR:
269                 if (chan->masqr && !ast_strlen_zero(chan->masqr->name)) {
270                         strncpy(string_ret, chan->masqr->name, sizeof(string_ret));
271                         string_ret[sizeof(string_ret) - 1] = '\0';
272                         *var_len = strlen(string_ret);
273                         ret = (u_char *)string_ret;
274                 }
275                 break;
276         case ASTCHANWHENHANGUP:
277                 if (chan->whentohangup) {
278                         gettimeofday(&tval, NULL);
279                         long_ret = difftime(chan->whentohangup, tval.tv_sec) * 100 - tval.tv_usec / 10000;
280                         ret= (u_char *)&long_ret;
281                 }
282                 break;
283         case ASTCHANAPP:
284                 if (chan->appl) {
285                         strncpy(string_ret, chan->appl, sizeof(string_ret));
286                         string_ret[sizeof(string_ret) - 1] = '\0';
287                         *var_len = strlen(string_ret);
288                         ret = (u_char *)string_ret;
289                 }
290                 break;
291         case ASTCHANDATA:
292                 if (chan->data) {
293                         strncpy(string_ret, chan->data, sizeof(string_ret));
294                         string_ret[sizeof(string_ret) - 1] = '\0';
295                         *var_len = strlen(string_ret);
296                         ret = (u_char *)string_ret;
297                 }
298                 break;
299         case ASTCHANCONTEXT:
300                 strncpy(string_ret, chan->context, sizeof(string_ret));
301                 string_ret[sizeof(string_ret) - 1] = '\0';
302                 *var_len = strlen(string_ret);
303                 ret = (u_char *)string_ret;
304                 break;
305         case ASTCHANMACROCONTEXT:
306                 strncpy(string_ret, chan->macrocontext, sizeof(string_ret));
307                 string_ret[sizeof(string_ret) - 1] = '\0';
308                 *var_len = strlen(string_ret);
309                 ret = (u_char *)string_ret;
310                 break;
311         case ASTCHANMACROEXTEN:
312                 strncpy(string_ret, chan->macroexten, sizeof(string_ret));
313                 string_ret[sizeof(string_ret) - 1] = '\0';
314                 *var_len = strlen(string_ret);
315                 ret = (u_char *)string_ret;
316                 break;
317         case ASTCHANMACROPRI:
318                 long_ret = chan->macropriority;
319                 ret = (u_char *)&long_ret;
320                 break;
321         case ASTCHANEXTEN:
322                 strncpy(string_ret, chan->exten, sizeof(string_ret));
323                 string_ret[sizeof(string_ret) - 1] = '\0';
324                 *var_len = strlen(string_ret);
325                 ret = (u_char *)string_ret;
326                 break;
327         case ASTCHANPRI:
328                 long_ret = chan->priority;
329                 ret = (u_char *)&long_ret;
330                 break;
331         case ASTCHANACCOUNTCODE:
332                 if (!ast_strlen_zero(chan->accountcode)) {
333                         strncpy(string_ret, chan->accountcode, sizeof(string_ret));
334                         string_ret[sizeof(string_ret) - 1] = '\0';
335                         *var_len = strlen(string_ret);
336                         ret = (u_char *)string_ret;
337                 }
338                 break;
339         case ASTCHANFORWARDTO:
340                 if (!ast_strlen_zero(chan->call_forward)) {
341                         strncpy(string_ret, chan->call_forward, sizeof(string_ret));
342                         string_ret[sizeof(string_ret) - 1] = '\0';
343                         *var_len = strlen(string_ret);
344                         ret = (u_char *)string_ret;
345                 }
346                 break;
347         case ASTCHANUNIQUEID:
348                 strncpy(string_ret, chan->uniqueid, sizeof(string_ret));
349                 string_ret[sizeof(string_ret) - 1] = '\0';
350                 *var_len = strlen(string_ret);
351                 ret = (u_char *)string_ret;
352                 break;
353         case ASTCHANCALLGROUP:
354                 long_ret = chan->callgroup;
355                 ret = (u_char *)&long_ret;
356                 break;
357         case ASTCHANPICKUPGROUP:
358                 long_ret = chan->pickupgroup;
359                 ret = (u_char *)&long_ret;
360                 break;
361         case ASTCHANSTATE:
362                 long_ret = chan->_state & 0xffff;
363                 ret = (u_char *)&long_ret;
364                 break;
365         case ASTCHANMUTED:
366                 long_ret = chan->_state & AST_STATE_MUTE ? 1 : 2;
367                 ret = (u_char *)&long_ret;
368                 break;
369         case ASTCHANRINGS:
370                 long_ret = chan->rings;
371                 ret = (u_char *)&long_ret;
372                 break;
373         case ASTCHANCIDDNID:
374                 if (chan->cid.cid_dnid) {
375                         strncpy(string_ret, chan->cid.cid_dnid, sizeof(string_ret));
376                         string_ret[sizeof(string_ret) - 1] = '\0';
377                         *var_len = strlen(string_ret);
378                         ret = (u_char *)string_ret;
379                 }
380                 break;
381         case ASTCHANCIDNUM:
382                 if (chan->cid.cid_num) {
383                         strncpy(string_ret, chan->cid.cid_num, sizeof(string_ret));
384                         string_ret[sizeof(string_ret) - 1] = '\0';
385                         *var_len = strlen(string_ret);
386                         ret = (u_char *)string_ret;
387                 }
388                 break;
389         case ASTCHANCIDNAME:
390                 if (chan->cid.cid_name) {
391                         strncpy(string_ret, chan->cid.cid_name, sizeof(string_ret));
392                         string_ret[sizeof(string_ret) - 1] = '\0';
393                         *var_len = strlen(string_ret);
394                         ret = (u_char *)string_ret;
395                 }
396                 break;
397         case ASTCHANCIDANI:
398                 if (chan->cid.cid_ani) {
399                         strncpy(string_ret, chan->cid.cid_ani, sizeof(string_ret));
400                         string_ret[sizeof(string_ret) - 1] = '\0';
401                         *var_len = strlen(string_ret);
402                         ret = (u_char *)string_ret;
403                 }
404                 break;
405         case ASTCHANCIDRDNIS:
406                 if (chan->cid.cid_rdnis) {
407                         strncpy(string_ret, chan->cid.cid_rdnis, sizeof(string_ret));
408                         string_ret[sizeof(string_ret) - 1] = '\0';
409                         *var_len = strlen(string_ret);
410                         ret = (u_char *)string_ret;
411                 }
412                 break;
413         case ASTCHANCIDPRES:
414                 long_ret = chan->cid.cid_pres;
415                 ret = (u_char *)&long_ret;
416                 break;
417         case ASTCHANCIDANI2:
418                 long_ret = chan->cid.cid_ani2;
419                 ret = (u_char *)&long_ret;
420                 break;
421         case ASTCHANCIDTON:
422                 long_ret = chan->cid.cid_ton;
423                 ret = (u_char *)&long_ret;
424                 break;
425         case ASTCHANCIDTNS:
426                 long_ret = chan->cid.cid_tns;
427                 ret = (u_char *)&long_ret;
428                 break;
429         case ASTCHANAMAFLAGS:
430                 long_ret = chan->amaflags;
431                 ret = (u_char *)&long_ret;
432                 break;
433         case ASTCHANADSI:
434                 long_ret = chan->adsicpe;
435                 ret = (u_char *)&long_ret;
436                 break;
437         case ASTCHANTONEZONE:
438                 if (chan->zone) {
439                         strncpy(string_ret, chan->zone->country, sizeof(string_ret));
440                         string_ret[sizeof(string_ret) - 1] = '\0';
441                         *var_len = strlen(string_ret);
442                         ret = (u_char *)string_ret;
443                 }
444                 break;
445         case ASTCHANHANGUPCAUSE:
446                 long_ret = chan->hangupcause;
447                 ret = (u_char *)&long_ret;
448                 break;
449         case ASTCHANVARIABLES:
450                 if (pbx_builtin_serialize_variables(chan, &out)) {
451                         *var_len = strlen(out->str);
452                         ret = (u_char *)out->str;
453                 }
454                 break;
455         case ASTCHANFLAGS:
456                 bits_ret[0] = 0;
457                 for (bit = 0; bit < 8; bit++)
458                         bits_ret[0] |= ((chan->flags & (1 << bit)) >> bit) << (7 - bit);
459                 bits_ret[1] = 0;
460                 for (bit = 0; bit < 8; bit++)
461                         bits_ret[1] |= (((chan->flags >> 8) & (1 << bit)) >> bit) << (7 - bit);
462                 *var_len = 2;
463                 ret = bits_ret;
464                 break;
465         case ASTCHANTRANSFERCAP:
466                 long_ret = chan->transfercapability;
467                 ret = (u_char *)&long_ret;
468         default:
469                 break;
470         }
471         ast_channel_unlock(chan);
472         return ret;
473 }
474
475 static u_char *ast_var_channel_types(struct variable *vp, oid *name, size_t *length,
476                                                                    int exact, size_t *var_len, WriteMethod **write_method)
477 {
478         static unsigned long long_ret;
479         struct ast_variable *channel_types, *next;
480
481         if (header_generic(vp, name, length, exact, var_len, write_method))
482                 return NULL;
483
484         if (vp->magic != ASTCHANTYPECOUNT)
485                 return NULL;
486
487         for (long_ret = 0, channel_types = next = ast_channeltype_list(); next; next = next->next)
488                 long_ret++;
489         ast_variables_destroy(channel_types);
490
491         return (u_char *)&long_ret;
492 }
493
494 static u_char *ast_var_channel_types_table(struct variable *vp, oid *name, size_t *length,
495                                                                                 int exact, size_t *var_len, WriteMethod **write_method)
496 {
497         const struct ast_channel_tech *tech = NULL;
498         struct ast_variable *channel_types, *next;
499         static unsigned long long_ret;
500         struct ast_channel *chan;
501         u_long i;
502
503         if (header_simple_table(vp, name, length, exact, var_len, write_method, -1))
504                 return NULL;
505
506         channel_types = ast_channeltype_list();
507         for (i = 1, next = channel_types; next && i != name[*length - 1]; next = next->next, i++)
508                 ;
509         if (next != NULL)
510                 tech = ast_get_channel_tech(next->name);
511         ast_variables_destroy(channel_types);
512         if (next == NULL || tech == NULL)
513                 return NULL;
514         
515         switch (vp->magic) {
516         case ASTCHANTYPEINDEX:
517                 long_ret = name[*length - 1];
518                 return (u_char *)&long_ret;
519         case ASTCHANTYPENAME:
520                 *var_len = strlen(tech->type);
521                 return (u_char *)tech->type;
522         case ASTCHANTYPEDESC:
523                 *var_len = strlen(tech->description);
524                 return (u_char *)tech->description;
525         case ASTCHANTYPEDEVSTATE:
526                 long_ret = tech->devicestate ? 1 : 2;
527                 return (u_char *)&long_ret;
528         case ASTCHANTYPEINDICATIONS:
529                 long_ret = tech->indicate ? 1 : 2;
530                 return (u_char *)&long_ret;
531         case ASTCHANTYPETRANSFER:
532                 long_ret = tech->transfer ? 1 : 2;
533                 return (u_char *)&long_ret;
534         case ASTCHANTYPECHANNELS:
535                 long_ret = 0;
536                 for (chan = ast_channel_walk_locked(NULL); chan; chan = ast_channel_walk_locked(chan)) {
537                         ast_channel_unlock(chan);
538                         if (chan->tech == tech)
539                                 long_ret++;
540                 }
541                 return (u_char *)&long_ret;
542         default:
543                 break;
544         }
545         return NULL;
546 }
547
548 static u_char *ast_var_channel_bridge(struct variable *vp, oid *name, size_t *length,
549         int exact, size_t *var_len, WriteMethod **write_method)
550 {
551         static unsigned long long_ret;
552         struct ast_channel *chan = NULL;
553
554         long_ret = 0;
555         if (header_generic(vp, name, length, exact, var_len, write_method))
556                 return NULL;
557
558         while ((chan = ast_channel_walk_locked(chan))) {
559                 if (ast_bridged_channel(chan))
560                         long_ret++;
561                 ast_channel_unlock(chan);
562         }
563
564         *var_len = sizeof(long_ret);
565
566         return (vp->magic == ASTCHANBRIDGECOUNT) ? (u_char *) &long_ret : NULL;
567 }
568
569 static u_char *ast_var_Config(struct variable *vp, oid *name, size_t *length,
570                                                          int exact, size_t *var_len, WriteMethod **write_method)
571 {
572         static unsigned long long_ret;
573         struct timeval tval;
574
575         if (header_generic(vp, name, length, exact, var_len, write_method))
576                 return NULL;
577
578         switch (vp->magic) {
579         case ASTCONFUPTIME:
580                 gettimeofday(&tval, NULL);
581                 long_ret = difftime(tval.tv_sec, ast_startuptime.tv_sec) * 100 + tval.tv_usec / 10000 - ast_startuptime.tv_usec / 10000;
582                 return (u_char *)&long_ret;
583         case ASTCONFRELOADTIME:
584                 gettimeofday(&tval, NULL);
585                 if (ast_lastreloadtime.tv_sec)
586                         long_ret = difftime(tval.tv_sec, ast_lastreloadtime.tv_sec) * 100 + tval.tv_usec / 10000 - ast_lastreloadtime.tv_usec / 10000;
587                 else
588                         long_ret = difftime(tval.tv_sec, ast_startuptime.tv_sec) * 100 + tval.tv_usec / 10000 - ast_startuptime.tv_usec / 10000;
589                 return (u_char *)&long_ret;
590         case ASTCONFPID:
591                 long_ret = getpid();
592                 return (u_char *)&long_ret;
593         case ASTCONFSOCKET:
594                 *var_len = strlen(ast_config_AST_SOCKET);
595                 return (u_char *)ast_config_AST_SOCKET;
596         case ASTCONFACTIVECALLS:
597                 long_ret = ast_active_calls();
598                 return (u_char *)&long_ret;
599         case ASTCONFPROCESSEDCALLS:
600                 long_ret = ast_processed_calls();
601                 return (u_char *)&long_ret;
602         default:
603                 break;
604         }
605         return NULL;
606 }
607
608 static u_char *ast_var_indications(struct variable *vp, oid *name, size_t *length,
609                                                                   int exact, size_t *var_len, WriteMethod **write_method)
610 {
611         static unsigned long long_ret;
612         struct ind_tone_zone *tz = NULL;
613
614         if (header_generic(vp, name, length, exact, var_len, write_method))
615                 return NULL;
616
617         switch (vp->magic) {
618         case ASTINDCOUNT:
619                 long_ret = 0;
620                 while ( (tz = ast_walk_indications(tz)) )
621                         long_ret++;
622
623                 return (u_char *)&long_ret;
624         case ASTINDCURRENT:
625                 tz = ast_get_indication_zone(NULL);
626                 if (tz) {
627                         *var_len = strlen(tz->country);
628                         return (u_char *)tz->country;
629                 }
630                 *var_len = 0;
631                 return NULL;
632         default:
633                 break;
634         }
635         return NULL;
636 }
637
638 static u_char *ast_var_indications_table(struct variable *vp, oid *name, size_t *length,
639                                                                            int exact, size_t *var_len, WriteMethod **write_method)
640 {
641         static unsigned long long_ret;
642         struct ind_tone_zone *tz = NULL;
643         int i;
644
645         if (header_simple_table(vp, name, length, exact, var_len, write_method, -1))
646                 return NULL;
647
648         i = name[*length - 1] - 1;
649         while ( (tz = ast_walk_indications(tz)) && i )
650         i--;
651         if (tz == NULL)
652                 return NULL;
653
654         switch (vp->magic) {
655         case ASTINDINDEX:
656                 long_ret = name[*length - 1];
657                 return (u_char *)&long_ret;
658         case ASTINDCOUNTRY:
659                 *var_len = strlen(tz->country);
660                 return (u_char *)tz->country;
661         case ASTINDALIAS:
662                 if (tz->alias) {
663                         *var_len = strlen(tz->alias);
664                         return (u_char *)tz->alias;
665                 }
666                 return NULL;
667         case ASTINDDESCRIPTION:
668                 *var_len = strlen(tz->description);
669                 return (u_char *)tz->description;
670         default:
671                 break;
672         }
673         return NULL;
674 }
675
676 static int countmodule(const char *mod, const char *desc, int use, const char *like)
677 {
678         return 1;
679 }
680
681 static u_char *ast_var_Modules(struct variable *vp, oid *name, size_t *length,
682                                                           int exact, size_t *var_len, WriteMethod **write_method)
683 {
684         static unsigned long long_ret;
685
686         if (header_generic(vp, name, length, exact, var_len, write_method))
687                 return NULL;
688
689         if (vp->magic != ASTMODCOUNT)
690                 return NULL;
691
692         long_ret = ast_update_module_list(countmodule, NULL);
693
694         return (u_char *)&long_ret;
695 }
696
697 static u_char *ast_var_Version(struct variable *vp, oid *name, size_t *length,
698                                                           int exact, size_t *var_len, WriteMethod **write_method)
699 {
700         static unsigned long long_ret;
701
702         if (header_generic(vp, name, length, exact, var_len, write_method))
703                 return NULL;
704
705         switch (vp->magic) {
706         case ASTVERSTRING:
707                 *var_len = strlen(ASTERISK_VERSION);
708                 return (u_char *)ASTERISK_VERSION;
709         case ASTVERTAG:
710                 long_ret = ASTERISK_VERSION_NUM;
711                 return (u_char *)&long_ret;
712         default:
713                 break;
714         }
715         return NULL;
716 }
717
718 static int term_asterisk_mib(int majorID, int minorID, void *serverarg, void *clientarg)
719 {
720         unregister_sysORTable(asterisk_oid, OID_LENGTH(asterisk_oid));
721         return 0;
722 }
723
724 static void init_asterisk_mib(void)
725 {
726         static struct variable4 asterisk_vars[] = {
727                 {ASTVERSTRING,           ASN_OCTET_STR, RONLY, ast_var_Version,             2, {ASTVERSION, ASTVERSTRING}},
728                 {ASTVERTAG,              ASN_UNSIGNED,  RONLY, ast_var_Version,             2, {ASTVERSION, ASTVERTAG}},
729                 {ASTCONFUPTIME,          ASN_TIMETICKS, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFUPTIME}},
730                 {ASTCONFRELOADTIME,      ASN_TIMETICKS, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFRELOADTIME}},
731                 {ASTCONFPID,             ASN_INTEGER,   RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFPID}},
732                 {ASTCONFSOCKET,          ASN_OCTET_STR, RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFSOCKET}},
733                 {ASTCONFACTIVECALLS,     ASN_GAUGE,     RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFACTIVECALLS}},
734                 {ASTCONFPROCESSEDCALLS,  ASN_INTEGER,   RONLY, ast_var_Config,              2, {ASTCONFIGURATION, ASTCONFPROCESSEDCALLS}},
735                 {ASTMODCOUNT,            ASN_INTEGER,   RONLY, ast_var_Modules ,            2, {ASTMODULES, ASTMODCOUNT}},
736                 {ASTINDCOUNT,            ASN_INTEGER,   RONLY, ast_var_indications,         2, {ASTINDICATIONS, ASTINDCOUNT}},
737                 {ASTINDCURRENT,          ASN_OCTET_STR, RONLY, ast_var_indications,         2, {ASTINDICATIONS, ASTINDCURRENT}},
738                 {ASTINDINDEX,            ASN_INTEGER,   RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDINDEX}},
739                 {ASTINDCOUNTRY,          ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDCOUNTRY}},
740                 {ASTINDALIAS,            ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDALIAS}},
741                 {ASTINDDESCRIPTION,      ASN_OCTET_STR, RONLY, ast_var_indications_table,   4, {ASTINDICATIONS, ASTINDTABLE, 1, ASTINDDESCRIPTION}},
742                 {ASTCHANCOUNT,           ASN_INTEGER,   RONLY, ast_var_channels,            2, {ASTCHANNELS, ASTCHANCOUNT}},
743                 {ASTCHANINDEX,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANINDEX}},
744                 {ASTCHANNAME,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANNAME}},
745                 {ASTCHANLANGUAGE,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANLANGUAGE}},
746                 {ASTCHANTYPE,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTYPE}},
747                 {ASTCHANMUSICCLASS,      ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMUSICCLASS}},
748                 {ASTCHANBRIDGE,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANBRIDGE}},
749                 {ASTCHANMASQ,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMASQ}},
750                 {ASTCHANMASQR,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMASQR}},
751                 {ASTCHANWHENHANGUP,      ASN_TIMETICKS, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANWHENHANGUP}},
752                 {ASTCHANAPP,             ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANAPP}},
753                 {ASTCHANDATA,            ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANDATA}},
754                 {ASTCHANCONTEXT,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCONTEXT}},
755                 {ASTCHANMACROCONTEXT,    ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROCONTEXT}},
756                 {ASTCHANMACROEXTEN,      ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROEXTEN}},
757                 {ASTCHANMACROPRI,        ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMACROPRI}},
758                 {ASTCHANEXTEN,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANEXTEN}},
759                 {ASTCHANPRI,             ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANPRI}},
760                 {ASTCHANACCOUNTCODE,     ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANACCOUNTCODE}},
761                 {ASTCHANFORWARDTO,       ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANFORWARDTO}},
762                 {ASTCHANUNIQUEID,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANUNIQUEID}},
763                 {ASTCHANCALLGROUP,       ASN_UNSIGNED,  RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCALLGROUP}},
764                 {ASTCHANPICKUPGROUP,     ASN_UNSIGNED,  RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANPICKUPGROUP}},
765                 {ASTCHANSTATE,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANSTATE}},
766                 {ASTCHANMUTED,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANMUTED}},
767                 {ASTCHANRINGS,           ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANRINGS}},
768                 {ASTCHANCIDDNID,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDDNID}},
769                 {ASTCHANCIDNUM,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDNUM}},
770                 {ASTCHANCIDNAME,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDNAME}},
771                 {ASTCHANCIDANI,          ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDANI}},
772                 {ASTCHANCIDRDNIS,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDRDNIS}},
773                 {ASTCHANCIDPRES,         ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDPRES}},
774                 {ASTCHANCIDANI2,         ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDANI2}},
775                 {ASTCHANCIDTON,          ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDTON}},
776                 {ASTCHANCIDTNS,          ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANCIDTNS}},
777                 {ASTCHANAMAFLAGS,        ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANAMAFLAGS}},
778                 {ASTCHANADSI,            ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANADSI}},
779                 {ASTCHANTONEZONE,        ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTONEZONE}},
780                 {ASTCHANHANGUPCAUSE,     ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANHANGUPCAUSE}},
781                 {ASTCHANVARIABLES,       ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANVARIABLES}},
782                 {ASTCHANFLAGS,           ASN_OCTET_STR, RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANFLAGS}},
783                 {ASTCHANTRANSFERCAP,     ASN_INTEGER,   RONLY, ast_var_channels_table,      4, {ASTCHANNELS, ASTCHANTABLE, 1, ASTCHANTRANSFERCAP}},
784                 {ASTCHANTYPECOUNT,       ASN_INTEGER,   RONLY, ast_var_channel_types,       2, {ASTCHANNELS, ASTCHANTYPECOUNT}},
785                 {ASTCHANTYPEINDEX,       ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEINDEX}},
786                 {ASTCHANTYPENAME,        ASN_OCTET_STR, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPENAME}},
787                 {ASTCHANTYPEDESC,        ASN_OCTET_STR, RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEDESC}},
788                 {ASTCHANTYPEDEVSTATE,    ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEDEVSTATE}},
789                 {ASTCHANTYPEINDICATIONS, ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPEINDICATIONS}},
790                 {ASTCHANTYPETRANSFER,    ASN_INTEGER,   RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPETRANSFER}},
791                 {ASTCHANTYPECHANNELS,    ASN_GAUGE,     RONLY, ast_var_channel_types_table, 4, {ASTCHANNELS, ASTCHANTYPETABLE, 1, ASTCHANTYPECHANNELS}},
792                 {ASTCHANBRIDGECOUNT,     ASN_GAUGE,     RONLY, ast_var_channel_bridge,      3, {ASTCHANNELS, ASTCHANSCALARS, ASTCHANBRIDGECOUNT}},
793         };
794
795         register_sysORTable(asterisk_oid, OID_LENGTH(asterisk_oid),
796                         "ASTERISK-MIB implementation for Asterisk.");
797
798         REGISTER_MIB("res_snmp", asterisk_vars, variable4, asterisk_oid);
799
800         snmp_register_callback(SNMP_CALLBACK_LIBRARY,
801                            SNMP_CALLBACK_SHUTDOWN,
802                            term_asterisk_mib, NULL);
803 }
804
805 /*
806  * Local Variables:
807  * c-basic-offset: 4
808  * c-file-offsets: ((case-label . 0))
809  * tab-width: 4
810  * indent-tabs-mode: t
811  * End:
812  */