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