added files
[bcm963xx.git] / userapps / opensource / net-snmp / agent / mibgroup / agentx / subagent.c
1 /*
2  *  AgentX sub-agent
3  */
4 #include <net-snmp/net-snmp-config.h>
5
6 #include <sys/types.h>
7 #ifdef HAVE_STDLIB_H
8 #include <stdlib.h>
9 #endif
10 #if TIME_WITH_SYS_TIME
11 # ifdef WIN32
12 #  include <sys/timeb.h>
13 # else
14 #  include <sys/time.h>
15 # endif
16 # include <time.h>
17 #else
18 # if HAVE_SYS_TIME_H
19 #  include <sys/time.h>
20 # else
21 #  include <time.h>
22 # endif
23 #endif
24 #if HAVE_WINSOCK_H
25 #include <winsock.h>
26 #endif
27 #if HAVE_SYS_SOCKET_H
28 #include <sys/socket.h>
29 #endif
30 #if HAVE_STRING_H
31 #include <string.h>
32 #else
33 #include <strings.h>
34 #endif
35 #if HAVE_NETINET_IN_H
36 #include <netinet/in.h>
37 #endif
38
39 #if HAVE_DMALLOC_H
40 #include <dmalloc.h>
41 #endif
42
43 #include <net-snmp/net-snmp-includes.h>
44 #include <net-snmp/agent/net-snmp-agent-includes.h>
45 #include <net-snmp/library/snmp_assert.h>
46
47 #include "snmpd.h"
48 #include "agentx/protocol.h"
49 #include "agentx/client.h"
50 #include <net-snmp/agent/agent_callbacks.h>
51 #include <net-snmp/agent/agent_trap.h>
52 #ifdef USING_MIBII_SYSORTABLE_MODULE
53 #include "mibII/sysORTable.h"
54 #endif
55
56 #include "subagent.h"
57
58 static SNMPCallback subagent_register_ping_alarm;
59 static SNMPAlarmCallback agentx_reopen_session;
60 void            agentx_register_callbacks(netsnmp_session * s);
61 void            agentx_unregister_callbacks(netsnmp_session * ss);
62 int             handle_subagent_response(int op, netsnmp_session * session,
63                                          int reqid, netsnmp_pdu *pdu,
64                                          void *magic);
65 int             handle_subagent_set_response(int op,
66                                              netsnmp_session * session,
67                                              int reqid, netsnmp_pdu *pdu,
68                                              void *magic);
69
70 typedef struct _net_snmpsubagent_magic_s {
71     int             original_command;
72     netsnmp_session *session;
73     netsnmp_variable_list *ovars;
74 } ns_subagent_magic;
75
76 struct agent_netsnmp_set_info {
77     int             transID;
78     int             mode;
79     int             errstat;
80     time_t          uptime;
81     netsnmp_session *sess;
82     netsnmp_variable_list *var_list;
83
84     struct agent_netsnmp_set_info *next;
85 };
86
87 static struct agent_netsnmp_set_info *Sets = NULL;
88
89 netsnmp_session *agentx_callback_sess = NULL;
90 extern int      callback_master_num;
91
92 void
93 init_subagent(void)
94 {
95     if (agentx_callback_sess == NULL) {
96         agentx_callback_sess = netsnmp_callback_open(callback_master_num,
97                                                      handle_subagent_response,
98                                                      NULL, NULL);
99         DEBUGMSGTL(("agentx/subagent", "init_subagent sess %08x\n",
100                     agentx_callback_sess));
101     }
102 }
103
104
105 struct agent_netsnmp_set_info *
106 save_set_vars(netsnmp_session * ss, netsnmp_pdu *pdu)
107 {
108     struct agent_netsnmp_set_info *ptr;
109     struct timeval  now;
110     extern struct timeval starttime;
111
112     ptr = (struct agent_netsnmp_set_info *)
113         malloc(sizeof(struct agent_netsnmp_set_info));
114     if (ptr == NULL)
115         return NULL;
116
117     /*
118      * Save the important information
119      */
120     ptr->transID = pdu->transid;
121     ptr->sess = ss;
122     ptr->mode = SNMP_MSG_INTERNAL_SET_RESERVE1;
123     gettimeofday(&now, NULL);
124     ptr->uptime = calculate_time_diff(&now, &starttime);
125
126     ptr->var_list = snmp_clone_varbind(pdu->variables);
127     if (ptr->var_list == NULL) {
128         free(ptr);
129         return NULL;
130     }
131
132     ptr->next = Sets;
133     Sets = ptr;
134
135     return ptr;
136 }
137
138 struct agent_netsnmp_set_info *
139 restore_set_vars(netsnmp_session * sess, netsnmp_pdu *pdu)
140 {
141     struct agent_netsnmp_set_info *ptr;
142
143     for (ptr = Sets; ptr != NULL; ptr = ptr->next)
144         if (ptr->sess == sess && ptr->transID == pdu->transid)
145             break;
146
147     if (ptr == NULL || ptr->var_list == NULL)
148         return NULL;
149
150     pdu->variables = snmp_clone_varbind(ptr->var_list);
151     if (pdu->variables == NULL)
152         return NULL;
153
154     return ptr;
155 }
156
157
158 void
159 free_set_vars(netsnmp_session * ss, netsnmp_pdu *pdu)
160 {
161     struct agent_netsnmp_set_info *ptr, *prev = NULL;
162
163     for (ptr = Sets; ptr != NULL; ptr = ptr->next) {
164         if (ptr->sess == ss && ptr->transID == pdu->transid) {
165             if (prev)
166                 prev->next = ptr->next;
167             else
168                 Sets = ptr->next;
169             snmp_free_varbind(ptr->var_list);
170             free(ptr);
171             return;
172         }
173         prev = ptr;
174     }
175 }
176
177 extern netsnmp_session *main_session;   /* from snmp_agent.c */
178
179 int
180 handle_agentx_packet(int operation, netsnmp_session * session, int reqid,
181                      netsnmp_pdu *pdu, void *magic)
182 {
183     struct agent_netsnmp_set_info *asi = NULL;
184     snmp_callback   mycallback;
185     netsnmp_pdu    *internal_pdu = NULL;
186     void           *retmagic = NULL;
187     ns_subagent_magic *smagic = NULL;
188
189     if (operation == NETSNMP_CALLBACK_OP_DISCONNECT) {
190         int             period =
191             netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL);
192         DEBUGMSGTL(("agentx/subagent",
193                     "transport disconnect indication\n"));
194         /*
195          * Deregister the ping alarm, if any, and invalidate all other
196          * references to this session.  
197          */
198         if (session->securityModel != SNMP_DEFAULT_SECMODEL) {
199             snmp_alarm_unregister(session->securityModel);
200         }
201         snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
202                             SNMPD_CALLBACK_INDEX_STOP, (void *) session);
203         agentx_unregister_callbacks(session);
204         remove_trap_session(session);
205         register_mib_detach();
206         main_session = NULL;
207         if (period != 0) {
208             /*
209              * Pings are enabled, so periodically attempt to re-establish contact 
210              * with the master agent.  Don't worry about the handle,
211              * agentx_reopen_session unregisters itself if it succeeds in talking 
212              * to the master agent.  
213              */
214             snmp_alarm_register(period, SA_REPEAT, agentx_reopen_session,
215                                 NULL);
216         }
217         return 0;
218     } else if (operation != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
219         DEBUGMSGTL(("agentx/subagent", "unexpected callback op %d\n",
220                     operation));
221         return 1;
222     }
223
224     /*
225      * ok, we have a pdu from the net. Modify as needed 
226      */
227
228     DEBUGMSGTL(("agentx/subagent", "handling agentx request (req=0x%x,trans="
229                 "0x%x,sess=0x%x)\n", pdu->reqid,pdu->transid, pdu->sessid));
230     pdu->version = AGENTX_VERSION_1;
231     pdu->flags |= UCD_MSG_FLAG_ALWAYS_IN_VIEW;
232
233     if (pdu->command == AGENTX_MSG_GET
234         || pdu->command == AGENTX_MSG_GETNEXT
235         || pdu->command == AGENTX_MSG_GETBULK) {
236         smagic =
237             (ns_subagent_magic *) calloc(1, sizeof(ns_subagent_magic));
238         if (smagic == NULL) {
239             DEBUGMSGTL(("agentx/subagent", "couldn't malloc() smagic\n"));
240             return 1;
241         }
242         smagic->original_command = pdu->command;
243         smagic->session = session;
244         smagic->ovars = NULL;
245         retmagic = (void *) smagic;
246     }
247
248     switch (pdu->command) {
249     case AGENTX_MSG_GET:
250         DEBUGMSGTL(("agentx/subagent", "  -> get\n"));
251         pdu->command = SNMP_MSG_GET;
252         mycallback = handle_subagent_response;
253         break;
254
255     case AGENTX_MSG_GETNEXT:
256         DEBUGMSGTL(("agentx/subagent", "  -> getnext\n"));
257         pdu->command = SNMP_MSG_GETNEXT;
258
259         /*
260          * We have to save a copy of the original variable list here because
261          * if the master agent has requested scoping for some of the varbinds
262          * that information is stored there.  
263          */
264
265         smagic->ovars = snmp_clone_varbind(pdu->variables);
266         DEBUGMSGTL(("agentx/subagent", "saved variables\n"));
267         mycallback = handle_subagent_response;
268         break;
269
270     case AGENTX_MSG_GETBULK:
271         /*
272          * WWWXXX 
273          */
274         DEBUGMSGTL(("agentx/subagent", "  -> getbulk\n"));
275         pdu->command = SNMP_MSG_GETBULK;
276
277         /*
278          * We have to save a copy of the original variable list here because
279          * if the master agent has requested scoping for some of the varbinds
280          * that information is stored there.  
281          */
282
283         smagic->ovars = snmp_clone_varbind(pdu->variables);
284         DEBUGMSGTL(("agentx/subagent", "saved variables at %p\n",
285                     smagic->ovars));
286         mycallback = handle_subagent_response;
287         break;
288
289     case AGENTX_MSG_RESPONSE:
290         DEBUGMSGTL(("agentx/subagent", "  -> response\n"));
291         return 1;
292
293     case AGENTX_MSG_TESTSET:
294         /*
295          * XXXWWW we have to map this twice to both RESERVE1 and RESERVE2 
296          */
297         DEBUGMSGTL(("agentx/subagent", "  -> testset\n"));
298         asi = save_set_vars(session, pdu);
299         if (asi == NULL) {
300             snmp_log(LOG_WARNING, "save_set_vars() failed\n");
301             return 1;
302         }
303         asi->mode = pdu->command = SNMP_MSG_INTERNAL_SET_RESERVE1;
304         mycallback = handle_subagent_set_response;
305         retmagic = asi;
306         break;
307
308     case AGENTX_MSG_COMMITSET:
309         DEBUGMSGTL(("agentx/subagent", "  -> commitset\n"));
310         asi = restore_set_vars(session, pdu);
311         if (asi == NULL) {
312             snmp_log(LOG_WARNING, "restore_set_vars() failed\n");
313             return 1;
314         }
315         if (asi->mode != SNMP_MSG_INTERNAL_SET_RESERVE2) {
316             snmp_log(LOG_WARNING,
317                      "dropping bad AgentX request (wrong mode %d)\n",
318                      asi->mode);
319             return 1;
320         }
321         asi->mode = pdu->command = SNMP_MSG_INTERNAL_SET_ACTION;
322         mycallback = handle_subagent_set_response;
323         retmagic = asi;
324         break;
325
326     case AGENTX_MSG_CLEANUPSET:
327         DEBUGMSGTL(("agentx/subagent", "  -> cleanupset\n"));
328         asi = restore_set_vars(session, pdu);
329         if (asi == NULL) {
330             snmp_log(LOG_WARNING, "restore_set_vars() failed\n");
331             return 1;
332         }
333         if (asi->mode == SNMP_MSG_INTERNAL_SET_RESERVE1 ||
334             asi->mode == SNMP_MSG_INTERNAL_SET_RESERVE2) {
335             asi->mode = pdu->command = SNMP_MSG_INTERNAL_SET_FREE;
336         } else if (asi->mode == SNMP_MSG_INTERNAL_SET_ACTION) {
337             asi->mode = pdu->command = SNMP_MSG_INTERNAL_SET_COMMIT;
338         } else {
339             snmp_log(LOG_WARNING,
340                      "dropping bad AgentX request (wrong mode %d)\n",
341                      asi->mode);
342             return 1;
343         }
344         mycallback = handle_subagent_set_response;
345         retmagic = asi;
346         break;
347
348     case AGENTX_MSG_UNDOSET:
349         DEBUGMSGTL(("agentx/subagent", "  -> undoset\n"));
350         asi = restore_set_vars(session, pdu);
351         if (asi == NULL) {
352             snmp_log(LOG_WARNING, "restore_set_vars() failed\n");
353             return 1;
354         }
355         asi->mode = pdu->command = SNMP_MSG_INTERNAL_SET_UNDO;
356         mycallback = handle_subagent_set_response;
357         retmagic = asi;
358         break;
359
360     default:
361         DEBUGMSGTL(("agentx/subagent", "  -> unknown command %d (%02x)\n",
362                     pdu->command, pdu->command));
363         return 0;
364     }
365
366     /*
367      * submit the pdu to the internal handler 
368      */
369
370     /*
371      * We have to clone the PDU here, because when we return from this
372      * callback, sess_process_packet will free(pdu), but this call also
373      * free()s its argument PDU.  
374      */
375
376     internal_pdu = snmp_clone_pdu(pdu);
377     snmp_async_send(agentx_callback_sess, internal_pdu, mycallback,
378                     retmagic);
379     return 1;
380 }
381
382 int
383 handle_subagent_response(int op, netsnmp_session * session, int reqid,
384                          netsnmp_pdu *pdu, void *magic)
385 {
386     ns_subagent_magic *smagic = (ns_subagent_magic *) magic;
387     netsnmp_variable_list *u = NULL, *v = NULL;
388     int             rc = 0;
389
390     if (op != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE || magic == NULL) {
391         return 1;
392     }
393
394     pdu = snmp_clone_pdu(pdu);
395     DEBUGMSGTL(("agentx/subagent",
396                 "handling AgentX response (cmd 0x%02x orig_cmd 0x%02x)\n",
397                 pdu->command, smagic->original_command));
398
399     if (pdu->command == SNMP_MSG_INTERNAL_SET_FREE ||
400         pdu->command == SNMP_MSG_INTERNAL_SET_UNDO ||
401         pdu->command == SNMP_MSG_INTERNAL_SET_COMMIT) {
402         free_set_vars(smagic->session, pdu);
403     }
404
405     if (smagic->original_command == AGENTX_MSG_GETNEXT) {
406         DEBUGMSGTL(("agentx/subgaent",
407                     "do getNext scope processing %p %p\n", smagic->ovars,
408                     pdu->variables));
409         for (u = smagic->ovars, v = pdu->variables; u != NULL && v != NULL;
410              u = u->next_variable, v = v->next_variable) {
411             if (snmp_oid_compare
412                 (u->val.objid, u->val_len / sizeof(oid), nullOid,
413                  nullOidLen) != 0) {
414                 /*
415                  * The master agent requested scoping for this variable.  
416                  */
417                 rc = snmp_oid_compare(v->name, v->name_length,
418                                       u->val.objid,
419                                       u->val_len / sizeof(oid));
420                 DEBUGMSGTL(("agentx/subagent", "result "));
421                 DEBUGMSGOID(("agentx/subagent", v->name, v->name_length));
422                 DEBUGMSG(("agentx/subagent", " scope to "));
423                 DEBUGMSGOID(("agentx/subagent",
424                              u->val.objid, u->val_len / sizeof(oid)));
425                 DEBUGMSG(("agentx/subagent", " result %d\n", rc));
426
427                 if (rc >= 0) {
428                     /*
429                      * The varbind is out of scope.  From RFC2741, p. 66: "If
430                      * the subagent cannot locate an appropriate variable,
431                      * v.name is set to the starting OID, and the VarBind is
432                      * set to `endOfMibView'".  
433                      */
434                     snmp_set_var_objid(v, u->name, u->name_length);
435                     snmp_set_var_typed_value(v, SNMP_ENDOFMIBVIEW, 0, 0);
436                     DEBUGMSGTL(("agentx/subagent",
437                                 "scope violation -- return endOfMibView\n"));
438                 }
439             } else {
440                 DEBUGMSGTL(("agentx/subagent", "unscoped var\n"));
441             }
442         }
443     }
444
445     /*
446      * XXXJBPN: similar for GETBULK but the varbinds can get re-ordered I
447      * think which makes it er more difficult.  
448      */
449
450     if (smagic->ovars != NULL) {
451         snmp_free_varbind(smagic->ovars);
452     }
453
454     pdu->command = AGENTX_MSG_RESPONSE;
455     pdu->version = smagic->session->version;
456
457     if (!snmp_send(smagic->session, pdu)) {
458         snmp_free_pdu(pdu);
459     }
460     DEBUGMSGTL(("agentx/subagent", "  FINISHED\n"));
461     free(smagic);
462     return 1;
463 }
464
465 int
466 handle_subagent_set_response(int op, netsnmp_session * session, int reqid,
467                              netsnmp_pdu *pdu, void *magic)
468 {
469     netsnmp_session *retsess;
470     struct agent_netsnmp_set_info *asi;
471
472     if (op != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE || magic == NULL) {
473         return 1;
474     }
475
476     DEBUGMSGTL(("agentx/subagent",
477                 "handling agentx subagent set response (mode=%d,req=0x%x,"
478                 "trans=0x%x,sess=0x%x)\n",
479                 pdu->command, pdu->reqid,pdu->transid, pdu->sessid));
480     pdu = snmp_clone_pdu(pdu);
481
482     asi = (struct agent_netsnmp_set_info *) magic;
483     retsess = asi->sess;
484     asi->errstat = pdu->errstat;
485
486     if (asi->mode == SNMP_MSG_INTERNAL_SET_RESERVE1) {
487         /*
488          * reloop for RESERVE2 mode, an internal only agent mode 
489          */
490         /*
491          * XXX: check exception statuses of reserve1 first 
492          */
493         if (!pdu->errstat) {
494             asi->mode = pdu->command = SNMP_MSG_INTERNAL_SET_RESERVE2;
495             snmp_async_send(agentx_callback_sess, pdu,
496                             handle_subagent_set_response, asi);
497             DEBUGMSGTL(("agentx/subagent",
498                         "  going from RESERVE1 -> RESERVE2\n"));
499             return 1;
500         }
501     } else {
502         if (asi->mode == SNMP_MSG_INTERNAL_SET_FREE ||
503             asi->mode == SNMP_MSG_INTERNAL_SET_UNDO ||
504             asi->mode == SNMP_MSG_INTERNAL_SET_COMMIT) {
505             free_set_vars(retsess, pdu);
506         }
507         pdu->variables = NULL;  /* the variables were added by us */
508     }
509
510     netsnmp_assert(retsess != NULL);
511     pdu->command = AGENTX_MSG_RESPONSE;
512     pdu->version = retsess->version;
513
514     if (!snmp_send(retsess, pdu)) {
515         snmp_free_pdu(pdu);
516     }
517     DEBUGMSGTL(("agentx/subagent", "  FINISHED\n"));
518     return 1;
519 }
520
521
522
523 int
524 agentx_registration_callback(int majorID, int minorID, void *serverarg,
525                              void *clientarg)
526 {
527     struct register_parameters *reg_parms =
528         (struct register_parameters *) serverarg;
529     netsnmp_session *agentx_ss = (netsnmp_session *) clientarg;
530
531     if (minorID == SNMPD_CALLBACK_REGISTER_OID)
532         return agentx_register(agentx_ss,
533                                reg_parms->name, reg_parms->namelen,
534                                reg_parms->priority,
535                                reg_parms->range_subid,
536                                reg_parms->range_ubound, reg_parms->timeout,
537                                reg_parms->flags);
538     else
539         return agentx_unregister(agentx_ss,
540                                  reg_parms->name, reg_parms->namelen,
541                                  reg_parms->priority,
542                                  reg_parms->range_subid,
543                                  reg_parms->range_ubound);
544 }
545
546
547 #ifdef USING_MIBII_SYSORTABLE_MODULE
548 int
549 agentx_sysOR_callback(int majorID, int minorID, void *serverarg,
550                       void *clientarg)
551 {
552     struct register_sysOR_parameters *reg_parms =
553         (struct register_sysOR_parameters *) serverarg;
554     netsnmp_session *agentx_ss = (netsnmp_session *) clientarg;
555
556     if (minorID == SNMPD_CALLBACK_REG_SYSOR)
557         return agentx_add_agentcaps(agentx_ss,
558                                     reg_parms->name, reg_parms->namelen,
559                                     reg_parms->descr);
560     else
561         return agentx_remove_agentcaps(agentx_ss,
562                                        reg_parms->name,
563                                        reg_parms->namelen);
564 }
565 #endif
566
567
568 static int
569 subagent_shutdown(int majorID, int minorID, void *serverarg, void *clientarg)
570 {
571     netsnmp_session *thesession = (netsnmp_session *)clientarg;
572     DEBUGMSGTL(("agentx/subagent", "shutting down session....\n"));
573     if (thesession == NULL) {
574         DEBUGMSGTL(("agentx/subagent", "Empty session to shutdown\n"));
575         main_session = NULL;
576         return 0;
577     }
578     agentx_close_session(thesession, AGENTX_CLOSE_SHUTDOWN);
579     snmp_close(thesession);
580     main_session = NULL;
581     DEBUGMSGTL(("agentx/subagent", "shut down finished.\n"));
582     return 1;
583 }
584
585
586
587 /*
588  * Register all the "standard" AgentX callbacks for the given session.  
589  */
590
591 void
592 agentx_register_callbacks(netsnmp_session * s)
593 {
594     DEBUGMSGTL(("agentx/subagent",
595                 "registering callbacks for session %p\n", s));
596     snmp_register_callback(SNMP_CALLBACK_LIBRARY,
597                            SNMP_CALLBACK_POST_READ_CONFIG,
598                            subagent_register_ping_alarm, s);
599     snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN,
600                            subagent_shutdown, s);
601     snmp_register_callback(SNMP_CALLBACK_APPLICATION,
602                            SNMPD_CALLBACK_REGISTER_OID,
603                            agentx_registration_callback, s);
604     snmp_register_callback(SNMP_CALLBACK_APPLICATION,
605                            SNMPD_CALLBACK_UNREGISTER_OID,
606                            agentx_registration_callback, s);
607 #ifdef USING_MIBII_SYSORTABLE_MODULE
608     snmp_register_callback(SNMP_CALLBACK_APPLICATION,
609                            SNMPD_CALLBACK_REG_SYSOR,
610                            agentx_sysOR_callback, s);
611     snmp_register_callback(SNMP_CALLBACK_APPLICATION,
612                            SNMPD_CALLBACK_UNREG_SYSOR,
613                            agentx_sysOR_callback, s);
614 #endif
615 }
616
617 /*
618  * Unregister all the callbacks associated with this session.  
619  */
620
621 void
622 agentx_unregister_callbacks(netsnmp_session * ss)
623 {
624     DEBUGMSGTL(("agentx/subagent",
625                 "unregistering callbacks for session %p\n", ss));
626     snmp_unregister_callback(SNMP_CALLBACK_LIBRARY,
627                              SNMP_CALLBACK_POST_READ_CONFIG,
628                              subagent_register_ping_alarm, ss, 1);
629     snmp_unregister_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_SHUTDOWN,
630                              subagent_shutdown, ss, 1);
631     snmp_unregister_callback(SNMP_CALLBACK_APPLICATION,
632                              SNMPD_CALLBACK_REGISTER_OID,
633                              agentx_registration_callback, ss, 1);
634     snmp_unregister_callback(SNMP_CALLBACK_APPLICATION,
635                              SNMPD_CALLBACK_UNREGISTER_OID,
636                              agentx_registration_callback, ss, 1);
637 #ifdef USING_MIBII_SYSORTABLE_MODULE
638     snmp_unregister_callback(SNMP_CALLBACK_APPLICATION,
639                              SNMPD_CALLBACK_REG_SYSOR,
640                              agentx_sysOR_callback, ss, 1);
641     snmp_unregister_callback(SNMP_CALLBACK_APPLICATION,
642                              SNMPD_CALLBACK_UNREG_SYSOR,
643                              agentx_sysOR_callback, ss, 1);
644 #endif
645
646 }
647
648 /*
649  * Open a session to the master agent.  
650  */
651 int
652 subagent_open_master_session(void)
653 {
654     netsnmp_session sess;
655
656     DEBUGMSGTL(("agentx/subagent", "opening session...\n"));
657
658     if (main_session) {
659         snmp_log(LOG_WARNING,
660                  "AgentX session to master agent attempted to be re-opened.");
661         return -1;
662     }
663
664     snmp_sess_init(&sess);
665     sess.version = AGENTX_VERSION_1;
666     sess.retries = SNMP_DEFAULT_RETRIES;
667     sess.timeout = SNMP_DEFAULT_TIMEOUT;
668     sess.flags |= SNMP_FLAGS_STREAM_SOCKET;
669     if (netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET)) {
670         sess.peername =
671             netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET);
672     } else {
673         sess.peername = strdup(AGENTX_SOCKET);
674     }
675
676     sess.local_port = 0;        /* client */
677     sess.remote_port = AGENTX_PORT;     /* default port */
678     sess.callback = handle_agentx_packet;
679     sess.authenticator = NULL;
680     main_session = snmp_open_ex(&sess, NULL, agentx_parse, NULL, NULL,
681                                 agentx_realloc_build, agentx_check_packet);
682
683     if (main_session == NULL) {
684         /*
685          * Diagnose snmp_open errors with the input
686          * netsnmp_session pointer.  
687          */
688         if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_CONNECTION_WARNINGS)) {
689             if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) {
690                 netsnmp_sess_log_error(LOG_WARNING,
691                                        "Error: Failed to connect to the agentx master agent",
692                                        &sess);
693             } else {
694                 snmp_sess_perror
695                     ("Error: Failed to connect to the agentx master agent",
696                      &sess);
697             }
698         }
699         return -1;
700     }
701
702     if (agentx_open_session(main_session) < 0) {
703         snmp_close(main_session);
704         main_session = NULL;
705         return -1;
706     }
707
708     if (add_trap_session(main_session, AGENTX_MSG_NOTIFY, 1,
709                          AGENTX_VERSION_1)) {
710         DEBUGMSGTL(("agentx/subagent", " trap session registered OK\n"));
711     } else {
712         DEBUGMSGTL(("agentx/subagent",
713                     "trap session registration failed\n"));
714         snmp_close(main_session);
715         main_session = NULL;
716         return -1;
717     }
718
719     agentx_register_callbacks(main_session);
720
721     snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
722                         SNMPD_CALLBACK_INDEX_START, (void *) main_session);
723
724     DEBUGMSGTL(("agentx/subagent", "opening session...  DONE (%p)\n",
725                 main_session));
726
727     return 0;
728 }
729
730 /*
731  * returns non-zero on error 
732  */
733 int
734 subagent_pre_init(void)
735 {
736     DEBUGMSGTL(("agentx/subagent", "initializing....\n"));
737
738     /*
739      * set up callbacks to initiate master agent pings for this session 
740      */
741     netsnmp_ds_register_config(ASN_INTEGER,
742                        netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE),
743                        "agentxPingInterval",
744                        NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL);
745
746
747     if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE) != SUB_AGENT) {
748         return 0;
749     }
750
751     /*
752      * if a valid ping interval has been defined, call agentx_reopen_session
753      * * to try to connect to master or setup a ping alarm if it couldn't
754      * * succeed 
755      */
756     if (netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL) > 0)
757         agentx_reopen_session(0, NULL);
758     else                        /* if no ping interval was set up, just try to connect once */
759         subagent_open_master_session();
760     if (!main_session)
761         return -1;
762
763     DEBUGMSGTL(("agentx/subagent", "initializing....  DONE\n"));
764
765     return 0;
766 }
767
768
769 /*
770  * Alarm callback function to open a session to the master agent.  If a
771  * transport disconnection callback occurs, indicating that the master agent
772  * has died (or there has been some strange communication problem), this
773  * alarm is called repeatedly to try to re-open the connection.  
774  */
775
776 void
777 agentx_reopen_session(unsigned int clientreg, void *clientarg)
778 {
779     DEBUGMSGTL(("agentx/subagent", "agentx_reopen_session(%d) called\n",
780                 clientreg));
781
782     if (subagent_open_master_session() == 0) {
783         /*
784          * Successful.  Delete the alarm handle if one exists.  
785          */
786         if (clientreg != 0) {
787             snmp_alarm_unregister(clientreg);
788         }
789
790         /*
791          * Reregister all our nodes.  
792          */
793         register_mib_reattach();
794
795         /*
796          * Register a ping alarm (if need be).  
797          */
798         subagent_register_ping_alarm(0, 0, 0, main_session);
799     } else {
800         if (clientreg == 0) {
801             /*
802              * Register a reattach alarm for later 
803              */
804             subagent_register_ping_alarm(0, 0, 0, main_session);
805         }
806     }
807 }
808
809 /*
810  * If a valid session is passed in (through clientarg), register a
811  * ping handler to ping it frequently, else register an attempt to try
812  * and open it again later. 
813  */
814
815 static int
816 subagent_register_ping_alarm(int majorID, int minorID,
817                              void *serverarg, void *clientarg)
818 {
819
820     netsnmp_session *ss = (netsnmp_session *) clientarg;
821     int             ping_interval =
822         netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_PING_INTERVAL);
823
824     if (!ping_interval)         /* don't do anything if not setup properly */
825         return 0;
826
827     /*
828      * register a ping alarm, if desired 
829      */
830     if (ss) {
831         if (ss->securityModel != SNMP_DEFAULT_SECMODEL) {
832             DEBUGMSGTL(("agentx/subagent",
833                         "unregister existing alarm %d\n",
834                         ss->securityModel));
835             snmp_alarm_unregister(ss->securityModel);
836         }
837
838         DEBUGMSGTL(("agentx/subagent",
839                     "register ping alarm every %d seconds\n",
840                     ping_interval));
841         /*
842          * we re-use the securityModel parameter for an alarm stash,
843          * since agentx doesn't need it 
844          */
845         ss->securityModel = snmp_alarm_register(ping_interval, SA_REPEAT,
846                                                 agentx_check_session, ss);
847     } else {
848         /*
849          * attempt to open it later instead 
850          */
851         DEBUGMSGTL(("agentx/subagent",
852                     "subagent not properly attached, postponing registration till later....\n"));
853         snmp_alarm_register(ping_interval, SA_REPEAT,
854                             agentx_reopen_session, NULL);
855     }
856     return 0;
857 }
858
859 /*
860  * check a session validity for connectivity to the master agent.  If
861  * not functioning, close and start attempts to reopen the session 
862  */
863 void
864 agentx_check_session(unsigned int clientreg, void *clientarg)
865 {
866     netsnmp_session *ss = (netsnmp_session *) clientarg;
867     if (!ss) {
868         if (clientreg)
869             snmp_alarm_unregister(clientreg);
870         return;
871     }
872     DEBUGMSGTL(("agentx/subagent", "checking status of session %p\n", ss));
873
874     if (!agentx_send_ping(ss)) {
875         snmp_log(LOG_WARNING,
876                  "AgentX master agent failed to respond to ping.  Attempting to re-register.\n");
877         /*
878          * master agent disappeared?  Try and re-register.
879          * close first, just to be sure .
880          */
881         agentx_unregister_callbacks(ss);
882         agentx_close_session(ss, AGENTX_CLOSE_TIMEOUT);
883         snmp_alarm_unregister(clientreg);       /* delete ping alarm timer */
884         snmp_call_callbacks(SNMP_CALLBACK_APPLICATION,
885                             SNMPD_CALLBACK_INDEX_STOP, (void *) ss);
886         snmp_close(main_session);
887         main_session = NULL;
888         agentx_reopen_session(0, NULL);
889     } else {
890         DEBUGMSGTL(("agentx/subagent", "session %p responded to ping\n",
891                     ss));
892     }
893 }