1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 *
22 * Copyright 1997 Sun Microsystems, Inc. All Rights Reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34
35 #include "impl.h"
36 #include "error.h"
37 #include "trace.h"
38 #include "pdu.h"
39
40 #include "access.h"
41 #include "agent.h"
42 #include "subtree.h"
43 #include "session.h"
44 #include "sh_table.h"
45
46
47 /***** STATIC VARIABLES *****/
48
49 int sap_agent_id = 1;
50
51 /* the agent list */
52 Agent *first_agent = NULL;
53
54
55 /****************************************************************/
56
trace_agents()57 void trace_agents()
58 {
59 Agent *ap;
60
61
62 trace("AGENTS:\n");
63 for(ap = first_agent; ap; ap = ap->next_agent)
64 {
65
66 trace("\t%X %-30s %-30s %8d %8d %8d %8d %X\n",
67 ap,
68 ap->name?ap->name:"NO NAME",
69 address_string(&(ap->address)),
70 ap->timeout,ap->agentID,ap->agentStatus,
71 ap->agentProcessID,
72 ap->first_manager);
73
74 }
75 trace("\n");
76 }
77
78
79 /****************************************************************/
80
81 /* We must invoke subtree_list_delete() before invoking */
82 /* this function because the first_agent_subtree member */
83 /* of the agent structures should be NULL */
84
agent_list_delete()85 void agent_list_delete()
86 {
87 Agent *ap = first_agent;
88 Agent *next;
89
90
91 while(ap)
92 {
93 next = ap->next_agent;
94
95 agent_free(ap);
96
97 ap = next;
98 }
99
100 first_agent = NULL;
101
102 return;
103 }
104
105
106 /****************************************************************/
107
free_string_content(String str)108 static void free_string_content(String str)
109 {
110 if(str.chars != NULL && str.len != 0){
111 free(str.chars);
112 str.chars = NULL;
113 str.len = 0;
114 }
115 }
116
117 /* The fisrt_agent_subtree member of the agent */
118 /* structure should be NULL */
119
agent_free(Agent * ap)120 void agent_free(Agent *ap)
121 {
122 if(ap == NULL)
123 {
124 return;
125 }
126
127 if(ap->first_agent_subtree)
128 {
129 error("BUG: agent_free(): first_agent_subtree not NULL");
130 }
131
132 /* free the extra element */
133
134 free_string_content(ap->agentPersonalFile);
135 free_string_content(ap->agentConfigFile);
136 free_string_content(ap->agentExecutable);
137 free_string_content(ap->agentVersionNum);
138 free_string_content(ap->agentProtocol);
139 free_string_content(ap->agentName);
140 if(ap->name) free(ap->name);
141 free(ap);
142 ap =NULL;
143 return;
144 }
145
146 /****************************************************************/
agent_find_by_id(int id)147 Agent *agent_find_by_id(int id)
148 {
149 Agent *ap;
150
151
152 for(ap = first_agent; ap; ap = ap->next_agent)
153 {
154 if(ap->agentID == id)
155 {
156 return ap;
157 }
158 }
159
160 return NULL;
161 }
162
163
agent_find_by_name(char * name)164 Agent *agent_find_by_name(char* name)
165 {
166 Agent *ap;
167
168
169 for(ap = first_agent; ap; ap = ap->next_agent)
170 {
171 if(!strcmp(ap->name,name))
172 {
173 return ap;
174 }
175 }
176
177 return NULL;
178 }
179
180 /* agent_find() is used to check if we have not */
181 /* two SNMP agents registered on the same UDP port */
182
agent_find(Address * address)183 Agent *agent_find(Address *address)
184 {
185 Agent *ap;
186
187
188 for(ap = first_agent; ap; ap = ap->next_agent)
189 {
190 if(ap->address.sin_port == address->sin_port)
191 {
192 return ap;
193 }
194 }
195
196 return NULL;
197 }
198
agent_update_subtree(Agent * agent)199 void agent_update_subtree(Agent* agent)
200 {
201 Subtree *sp;
202 if(agent == NULL) return ;
203 sp = agent->first_agent_subtree;
204 for(;sp;sp=sp->next_agent_subtree){
205 sp->regTreeStatus = agent->agentStatus;
206 }
207 }
208
agent_detach_from_list(Agent * agent)209 void agent_detach_from_list(Agent* agent)
210 {
211 Agent *ap, *last=NULL;
212
213 if(agent == NULL) return;
214 for(ap = first_agent; ap ; ap = ap->next_agent)
215 {
216 if(ap == agent)
217 break;
218 last = ap;
219 }
220 if(ap==NULL) return;
221 if(last == NULL){
222 first_agent = ap->next_agent;
223 }else{
224 last->next_agent = ap->next_agent;
225 }
226 ap->next_agent = NULL;
227 }
228
229
agent_destroy(Agent * agent)230 void agent_destroy(Agent* agent)
231 {
232 if(agent!=NULL){
233 if(agent->agentID==sap_agent_id-1)
234 sap_agent_id--;
235 }
236 agent_detach_from_list(agent);
237 agent_manager_list_free(agent->first_manager);
238 delete_all_table_from_agent(agent);
239 delete_all_subtree_from_agent(agent);
240 delete_agent_from_resource_list(agent);
241 agent_free(agent);
242 }
243
244 /*
245 ** Maximum number of consecutive timeouts before snmpdx will purge the
246 ** subagent from the internal tables.
247 */
248
249 static int MaxFails = 5 ;
250
SetFailThreshold(int v)251 int SetFailThreshold ( int v )
252 {
253 MaxFails = v ;
254 return 0 ;
255 }
256
257
258
259 /****************************************************************/
260
261 /* destroy hanging agent when no outstanding session which
262 relates to the agent */
destroy_hanging_agent()263 void destroy_hanging_agent()
264 {
265 Agent *ap;
266 int rslt ;
267
268 for (ap = first_agent; ap ; ap = ap->next_agent) {
269
270 if (ap->numOfFailRequest <= 5)
271 continue ;
272
273 /* Even if the subagent isn't responding, we need to let the
274 ** sessions timeout and rip-down thru the normal mechanism.
275 */
276 if (!no_outstanding_session_for_the_agent (ap))
277 continue ;
278
279 /* subagent is quiesced and not talking -- check proces */
280 if ( ap->agentProcessID != 0 && kill (ap->agentProcessID, 0) < 0) {
281 error ("Subagent died: %s PID=%d -- deleted from the agent table",
282 ap->name, ap->agentProcessID ) ;
283 agent_destroy (ap) ;
284 return ; /* only kill one at a time */
285 }
286
287 /* subagent appears to be alive but hung and not responding */
288
289 if (MaxFails <= 0 || ap->numOfFailRequest < MaxFails)
290 continue ;
291
292 /* If the subagent receives a request with a bad community string
293 // it is obliged to discard the string and _not_ respond. This
294 // doesn't jive with our stateful relay model. We timeout and
295 // can't distinguish a hung agent from an agent that is dropping
296 // packets because of the "bad" community strings. Thus, before
297 // putting the ax to an agent we see if it's still alive.
298 //
299 // The ssa_subagent_is_alive() routine "pings" the subagent with
300 // a valid but innocuous request packet. Unfortunately the dummy
301 // we build has the community string set to "public". If the subagent
302 // doesn't accept "public" requests it will ignore our ping attempt.
303 //
304 // Sunil indicated that snmpdx would pre-validate incoming community
305 // strings and only pass requests that would be accepted by the subagent.
306 // This doesn't appear to work as advertised.
307 */
308
309 if (ssa_subagent_is_alive (ap)) {
310 error ("Agent %s appeared dead but responded to ping", ap->name) ;
311 ap->numOfFailRequest = 0 ;
312 continue ;
313 }
314
315 error ("Agent not responding: %s -- deleted from the agent table", ap->name ) ;
316 agent_destroy(ap);
317 return;
318 }
319 }
320
321