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