Remove memory allocation in olsr_timer_add()
[oonf.git] / src / core / olsr_telnet.c
1 /*
2  * olsr_telnet.c
3  *
4  *  Created on: Sep 7, 2011
5  *      Author: rogge
6  */
7
8 #include "common/common_types.h"
9 #include "common/avl.h"
10 #include "common/avl_comp.h"
11
12 #include "config/cfg_schema.h"
13
14 #include "olsr_cfg.h"
15 #include "olsr_logging.h"
16 #include "olsr_memcookie.h"
17 #include "olsr_netaddr_acl.h"
18 #include "olsr_plugins.h"
19 #include "olsr_stream_socket.h"
20 #include "olsr_timer.h"
21 #include "olsr.h"
22 #include "olsr_telnet.h"
23
24 /* static function prototypes */
25 static void _call_stop_handler(struct olsr_telnet_data *data);
26 static void _cb_config_changed(void);
27 static int _cb_telnet_init(struct olsr_stream_session *);
28 static void _cb_telnet_cleanup(struct olsr_stream_session *);
29 static void _cb_telnet_create_error(struct olsr_stream_session *,
30     enum olsr_stream_errors);
31 static enum olsr_stream_session_state _cb_telnet_receive_data(
32     struct olsr_stream_session *);
33 static enum olsr_telnet_result _telnet_handle_command(
34     struct olsr_telnet_data *);
35 static struct olsr_telnet_command *_check_telnet_command(
36     struct olsr_telnet_data *data, const char *name,
37     struct olsr_telnet_command *cmd);
38
39 static void _cb_telnet_repeat_timer(void *data);
40 static enum olsr_telnet_result _cb_telnet_quit(struct olsr_telnet_data *data);
41 static enum olsr_telnet_result _cb_telnet_help(struct olsr_telnet_data *data);
42 static enum olsr_telnet_result _cb_telnet_echo(struct olsr_telnet_data *data);
43 static enum olsr_telnet_result _cb_telnet_repeat(struct olsr_telnet_data *data);
44 static enum olsr_telnet_result _cb_telnet_timeout(struct olsr_telnet_data *data);
45 static enum olsr_telnet_result _cb_telnet_version(struct olsr_telnet_data *data);
46 static enum olsr_telnet_result _cb_telnet_plugin(struct olsr_telnet_data *data);
47
48 /* global and static variables */
49 static struct cfg_schema_section telnet_section = {
50   .type = "telnet",
51   .mode = CFG_SSMODE_UNNAMED_OPTIONAL_STARTUP_TRIGGER,
52   .help = "Settings for the telnet interface",
53   .cb_delta_handler = _cb_config_changed,
54 };
55
56 static struct cfg_schema_entry telnet_entries[] = {
57   CFG_MAP_ACL_V46(olsr_stream_managed_config,
58       acl, "acl", "127.0.0.1", "Access control list for telnet interface"),
59   CFG_MAP_NETADDR_V4(olsr_stream_managed_config,
60       bindto_v4, "bindto_v4", "127.0.0.1", "Bind telnet ipv4 socket to this address", false),
61   CFG_MAP_NETADDR_V6(olsr_stream_managed_config,
62       bindto_v6, "bindto_v6", "::1", "Bind telnet ipv6 socket to this address", false),
63   CFG_MAP_INT_MINMAX(olsr_stream_managed_config,
64       port, "port", "2006", "Network port for telnet interface", 1, 65535),
65 };
66
67 /* built-in telnet commands */
68 static struct olsr_telnet_command _builtin[] = {
69   TELNET_CMD("quit", _cb_telnet_quit, "Ends telnet session"),
70   TELNET_CMD("exit", _cb_telnet_quit, "Ends telnet session"),
71   TELNET_CMD("help", _cb_telnet_help,
72       "help: Display the online help text and a list of commands"),
73   TELNET_CMD("echo", _cb_telnet_echo,"echo <string>: Prints a string"),
74   TELNET_CMD("repeat", _cb_telnet_repeat,
75       "repeat <seconds> <command>: Repeats a telnet command every X seconds"),
76   TELNET_CMD("timeout", _cb_telnet_timeout,
77       "timeout <seconds> :Sets telnet session timeout"),
78   TELNET_CMD("version", _cb_telnet_version, "Displays version of the program"),
79   TELNET_CMD("plugin", _cb_telnet_plugin,
80         "control plugins dynamically, parameters are 'list',"
81         " 'activate <plugin>', 'deactivate <plugin>', "
82         "'load <plugin>' and 'unload <plugin>'"),
83 };
84
85 /* remember if initialized or not */
86 OLSR_SUBSYSTEM_STATE(_telnet_state);
87
88 /* telnet session handling */
89 static struct olsr_memcookie_info *_telnet_memcookie;
90 static struct olsr_stream_managed _telnet_managed;
91 static struct olsr_timer_info _telnet_repeat_timerinfo = {
92   .name = "txt repeat timer",
93   .callback = _cb_telnet_repeat_timer,
94   .periodic = true,
95 };
96
97 struct avl_tree telnet_cmd_tree;
98
99 /**
100  * Initialize telnet subsystem
101  * @return 0 if initialized successfully, -1 otherwise
102  */
103 int
104 olsr_telnet_init(void) {
105   size_t i;
106
107   if (olsr_subsystem_is_initialized(&_telnet_state))
108     return 0;
109
110   _telnet_memcookie = olsr_memcookie_add("telnet session",
111       sizeof(struct olsr_telnet_session));
112   if (_telnet_memcookie == NULL) {
113     return -1;
114   }
115
116   olsr_timer_add(&_telnet_repeat_timerinfo );
117
118   cfg_schema_add_section(olsr_cfg_get_schema(), &telnet_section,
119       telnet_entries, ARRAYSIZE(telnet_entries));
120
121   olsr_stream_add_managed(&_telnet_managed);
122   _telnet_managed.config.session_timeout = 120000; /* 120 seconds */
123   _telnet_managed.config.maximum_input_buffer = 4096;
124   _telnet_managed.config.allowed_sessions = 3;
125   _telnet_managed.config.memcookie = _telnet_memcookie;
126   _telnet_managed.config.init = _cb_telnet_init;
127   _telnet_managed.config.cleanup = _cb_telnet_cleanup;
128   _telnet_managed.config.receive_data = _cb_telnet_receive_data;
129   _telnet_managed.config.create_error = _cb_telnet_create_error;
130
131   /* initialize telnet commands */
132   avl_init(&telnet_cmd_tree, avl_comp_strcasecmp, false, NULL);
133   for (i=0; i<ARRAYSIZE(_builtin); i++) {
134     olsr_telnet_add(&_builtin[i]);
135   }
136
137   olsr_subsystem_init(&_telnet_state);
138   return 0;
139 }
140
141 /**
142  * Cleanup all allocated data of telnet subsystem
143  */
144 void
145 olsr_telnet_cleanup(void) {
146   if (olsr_subsystem_cleanup(&_telnet_state))
147     return;
148
149   olsr_stream_remove_managed(&_telnet_managed, true);
150   cfg_schema_remove_section(olsr_cfg_get_schema(), &telnet_section);
151   olsr_memcookie_remove(_telnet_memcookie);
152 }
153
154 /**
155  * Add a new telnet command to telnet subsystem
156  * @param command pointer to initialized telnet command object
157  * @return -1 if an error happened, 0 otherwise
158  */
159 int
160 olsr_telnet_add(struct olsr_telnet_command *command) {
161   command->node.key = command->command;
162   if (avl_insert(&telnet_cmd_tree, &command->node)) {
163     return -1;
164   }
165   return 0;
166 }
167
168 /**
169  * Remove a telnet command from telnet subsystem
170  * @param command pointer to telnet command object
171  */
172 void
173 olsr_telnet_remove(struct olsr_telnet_command *command) {
174   avl_remove(&telnet_cmd_tree, &command->node);
175 }
176
177 void
178 olsr_telnet_stop(struct olsr_telnet_data *data) {
179   _call_stop_handler(data);
180   data->show_echo = true;
181   abuf_puts(data->out, "> ");
182   olsr_telnet_flush_session(data);
183 }
184
185 /**
186  * Execute a telnet command.
187  * @param cmd pointer to name of command
188  * @param para pointer to parameter string
189  * @param out buffer for output of command
190  * @param remote pointer to address which triggers the execution
191  * @return result of telnet command
192  */
193 enum olsr_telnet_result
194 olsr_telnet_execute(const char *cmd, const char *para,
195     struct autobuf *out, struct netaddr *remote) {
196   struct olsr_telnet_data data;
197   enum olsr_telnet_result result;
198
199   memset(&data, 0, sizeof(data));
200   data.command = cmd;
201   data.parameter = para;
202   data.out = out;
203   data.remote = remote;
204
205   result = _telnet_handle_command(&data);
206   olsr_telnet_stop(&data);
207   return result;
208 }
209
210 /**
211  * Handler for configuration changes
212  */
213 static void
214 _cb_config_changed(void) {
215   struct olsr_stream_managed_config config;
216
217   /* generate binary config */
218   memset(&config, 0, sizeof(config));
219   if (cfg_schema_tobin(&config, telnet_section.post,
220       telnet_entries, ARRAYSIZE(telnet_entries))) {
221     /* error in conversion */
222     OLSR_WARN(LOG_TELNET, "Cannot map telnet config to binary data");
223     goto apply_config_failed;
224   }
225
226   if (olsr_stream_apply_managed(&_telnet_managed, &config)) {
227     /* error while updating sockets */
228     goto apply_config_failed;
229   }
230
231   /* fall through */
232 apply_config_failed:
233   olsr_acl_remove(&config.acl);
234 }
235
236 /**
237  * Initialization of incoming telnet session
238  * @param session pointer to TCP session
239  * @return 0
240  */
241 static int
242 _cb_telnet_init(struct olsr_stream_session *session) {
243   struct olsr_telnet_session *telnet_session;
244
245   /* get telnet session pointer */
246   telnet_session = (struct olsr_telnet_session *)session;
247
248   telnet_session->data.show_echo = true;
249   telnet_session->data.stop_handler = NULL;
250   telnet_session->data.timeout_value = 120000;
251   telnet_session->data.out = &telnet_session->session.out;
252   telnet_session->data.remote = &telnet_session->session.remote_address;
253
254   list_init_head(&telnet_session->data.cleanup_list);
255
256   return 0;
257 }
258
259 /**
260  * Cleanup of telnet session
261  * @param session pointer to TCP session
262  */
263 static void
264 _cb_telnet_cleanup(struct olsr_stream_session *session) {
265   struct olsr_telnet_session *telnet_session;
266   struct olsr_telnet_cleanup *handler, *it;
267
268   /* get telnet session pointer */
269   telnet_session = (struct olsr_telnet_session *)session;
270
271   /* stop continuous commands */
272   olsr_telnet_stop(&telnet_session->data);
273
274   /* call all cleanup handlers */
275   list_for_each_element_safe(&telnet_session->data.cleanup_list, handler, node, it) {
276     /* remove from list first */
277     olsr_telnet_remove_cleanup(handler);
278
279     /* after this command the handler pointer might not be valid anymore */
280     handler->cleanup_handler(handler);
281   }
282 }
283
284 /**
285  * Create error string for telnet session
286  * @param session pointer to TCP stream
287  * @param error TCP error code to generate
288  */
289 static void
290 _cb_telnet_create_error(struct olsr_stream_session *session,
291     enum olsr_stream_errors error) {
292   switch(error) {
293     case STREAM_REQUEST_FORBIDDEN:
294       /* no message */
295       break;
296     case STREAM_REQUEST_TOO_LARGE:
297       abuf_puts(&session->out, "Input buffer overflow, ending connection\n");
298       break;
299     case STREAM_SERVICE_UNAVAILABLE:
300       abuf_puts(&session->out, "Telnet service unavailable, too many sessions\n");
301       break;
302   }
303 }
304
305 /* handle clean call of stop handler */
306 static void
307 _call_stop_handler(struct olsr_telnet_data *data) {
308   void (*stop_handler)(struct olsr_telnet_data *);
309
310   if (data->stop_handler) {
311     stop_handler = data->stop_handler;
312     data->stop_handler = NULL;
313     stop_handler(data);
314   }
315 }
316
317 /**
318  * Handler for receiving data from telnet session
319  * @param session pointer to TCP session
320  * @return TCP session state
321  */
322 static enum olsr_stream_session_state
323 _cb_telnet_receive_data(struct olsr_stream_session *session) {
324   static const char defaultCommand[] = "/link/neigh/topology/hna/mid/routes";
325   static char tmpbuf[128];
326
327   struct olsr_telnet_session *telnet_session;
328   enum olsr_telnet_result cmd_result;
329   char *eol;
330   int len;
331   bool processedCommand = false, chainCommands = false;
332
333   /* get telnet session pointer */
334   telnet_session = (struct olsr_telnet_session *)session;
335
336   /* loop over input */
337   while (abuf_getlen(&session->in) > 0) {
338     char *para = NULL, *cmd = NULL, *next = NULL;
339
340     /* search for end of line */
341     eol = memchr(abuf_getptr(&session->in), '\n', abuf_getlen(&session->in));
342
343     if (eol == NULL) {
344       break;
345     }
346
347     /* terminate line with a 0 */
348     if (eol != abuf_getptr(&session->in) && eol[-1] == '\r') {
349       eol[-1] = 0;
350     }
351     *eol++ = 0;
352
353     /* handle line */
354     OLSR_DEBUG(LOG_TELNET, "Interactive console: %s\n", abuf_getptr(&session->in));
355     cmd = abuf_getptr(&session->in);
356     processedCommand = true;
357
358     /* apply default command */
359     if (strcmp(cmd, "/") == 0) {
360       strcpy(tmpbuf, defaultCommand);
361       cmd = tmpbuf;
362     }
363
364     if (cmd[0] == '/') {
365       cmd++;
366       chainCommands = true;
367     }
368     while (cmd) {
369       len = abuf_getlen(&session->out);
370
371       /* handle difference between multicommand and singlecommand mode */
372       if (chainCommands) {
373         next = strchr(cmd, '/');
374         if (next) {
375           *next++ = 0;
376         }
377       }
378       para = strchr(cmd, ' ');
379       if (para != NULL) {
380         *para++ = 0;
381       }
382
383       /* if we are doing continous output, stop it ! */
384       _call_stop_handler(&telnet_session->data);
385
386       if (strlen(cmd) != 0) {
387         OLSR_DEBUG(LOG_TELNET, "Processing telnet command: '%s' '%s'",
388             cmd, para);
389
390         telnet_session->data.command = cmd;
391         telnet_session->data.parameter = para;
392         cmd_result = _telnet_handle_command(&telnet_session->data);
393         switch (cmd_result) {
394           case TELNET_RESULT_ACTIVE:
395             break;
396           case TELNET_RESULT_CONTINOUS:
397             telnet_session->data.show_echo = false;
398             break;
399           case TELNET_RESULT_INTERNAL_ERROR:
400             abuf_setlen(&session->out, len);
401             abuf_appendf(&session->out,
402                 "Error in autobuffer during command '%s'.\n", cmd);
403             break;
404           case _TELNET_RESULT_UNKNOWN_COMMAND:
405             abuf_setlen(&session->out, len);
406             abuf_appendf(&session->out, "Error, unknown command '%s'\n", cmd);
407             break;
408           case TELNET_RESULT_QUIT:
409             return STREAM_SESSION_SEND_AND_QUIT;
410         }
411         /* put an empty line behind each command */
412         if (telnet_session->data.show_echo) {
413           abuf_puts(&session->out, "\n");
414         }
415       }
416       cmd = next;
417     }
418
419     /* remove line from input buffer */
420     abuf_pull(&session->in, eol - abuf_getptr(&session->in));
421
422     if (abuf_getptr(&session->in)[0] == '/') {
423       /* end of multiple command line */
424       return STREAM_SESSION_SEND_AND_QUIT;
425     }
426   }
427
428   /* reset timeout */
429   olsr_stream_set_timeout(session, telnet_session->data.timeout_value);
430
431   /* print prompt */
432   if (processedCommand && session->state == STREAM_SESSION_ACTIVE
433       && telnet_session->data.show_echo) {
434     abuf_puts(&session->out, "> ");
435   }
436
437   return STREAM_SESSION_ACTIVE;
438 }
439
440 /**
441  * Helper function to call telnet command handler
442  * @param data pointer to telnet data
443  * @return telnet command result
444  */
445 static enum olsr_telnet_result
446 _telnet_handle_command(struct olsr_telnet_data *data) {
447   struct olsr_telnet_command *cmd;
448 #if !defined(REMOVE_LOG_INFO)
449   struct netaddr_str buf;
450 #endif
451   cmd = _check_telnet_command(data, data->command, NULL);
452   if (cmd == NULL) {
453     return _TELNET_RESULT_UNKNOWN_COMMAND;
454   }
455
456   OLSR_INFO(LOG_TELNET, "Executing command from %s: %s %s",
457       netaddr_to_string(&buf, data->remote), data->command,
458       data->parameter == NULL ? "" : data->parameter);
459   return cmd->handler(data);
460 }
461
462 /**
463  * Checks for existing (and allowed) telnet command.
464  * Either name or cmd should be NULL, but not both.
465  * @param data pointer to telnet data
466  * @param name pointer to command name (might be NULL)
467  * @param cmd pointer to telnet command object (might be NULL)
468  * @return telnet command object or NULL if not found or forbidden
469  */
470 static struct olsr_telnet_command *
471 _check_telnet_command(struct olsr_telnet_data *data,
472     const char *name, struct olsr_telnet_command *cmd) {
473 #if !defined(REMOVE_LOG_DEBUG)
474   struct netaddr_str buf;
475 #endif
476
477   if (cmd == NULL) {
478     cmd = avl_find_element(&telnet_cmd_tree, name, cmd, node);
479     if (cmd == NULL) {
480       return cmd;
481     }
482   }
483   if (cmd->acl == NULL) {
484     return cmd;
485   }
486
487   if (!olsr_acl_check_accept(cmd->acl, data->remote)) {
488     OLSR_DEBUG(LOG_TELNET, "Blocked telnet command '%s' to '%s' because of acl",
489         cmd->command, netaddr_to_string(&buf, data->remote));
490     return NULL;
491   }
492   return cmd;
493 }
494
495 /**
496  * Telnet command 'quit'
497  * @param data pointer to telnet data
498  * @return telnet command result
499  */
500 static enum olsr_telnet_result
501 _cb_telnet_quit(struct olsr_telnet_data *data __attribute__((unused))) {
502   return TELNET_RESULT_QUIT;
503 }
504
505 /**
506  * Telnet command 'help'
507  * @param data pointer to telnet data
508  * @return telnet command result
509  */
510 static enum olsr_telnet_result
511 _cb_telnet_help(struct olsr_telnet_data *data) {
512   struct olsr_telnet_command *ptr, *iterator;
513
514   if (data->parameter != NULL && data->parameter[0] != 0) {
515     ptr = _check_telnet_command(data, data->parameter, NULL);
516     if (ptr == NULL) {
517       abuf_appendf(data->out, "No help text found for command: %s\n", data->parameter);
518       return TELNET_RESULT_ACTIVE;
519     }
520
521     if (ptr->help_handler) {
522       ptr->help_handler(data);
523     }
524     else {
525       if (abuf_appendf(data->out, "%s", ptr->help) < 0) {
526         return TELNET_RESULT_INTERNAL_ERROR;
527       }
528     }
529     return TELNET_RESULT_ACTIVE;
530   }
531
532   if (abuf_puts(data->out, "Known commands:\n") < 0) {
533     return TELNET_RESULT_INTERNAL_ERROR;
534   }
535
536   FOR_ALL_TELNET_COMMANDS(ptr, iterator) {
537     if (_check_telnet_command(data, NULL, ptr)) {
538       if (abuf_appendf(data->out, "  %s\n", ptr->command) < 0) {
539         return TELNET_RESULT_INTERNAL_ERROR;
540       }
541     }
542   }
543
544   if (abuf_puts(data->out, "Use 'help <command> to see a help text for one command\n") < 0) {
545     return TELNET_RESULT_INTERNAL_ERROR;
546   }
547   return TELNET_RESULT_ACTIVE;
548 }
549
550 /**
551  * Telnet command 'echo'
552  * @param data pointer to telnet data
553  * @return telnet command result
554  */
555 static enum olsr_telnet_result
556 _cb_telnet_echo(struct olsr_telnet_data *data) {
557
558   if (abuf_appendf(data->out, "%s\n",
559       data->parameter == NULL ? "" : data->parameter) < 0) {
560     return TELNET_RESULT_INTERNAL_ERROR;
561   }
562   return TELNET_RESULT_ACTIVE;
563 }
564
565 /**
566  * Telnet command 'timeout'
567  * @param data pointer to telnet data
568  * @return telnet command result
569  */
570 static enum olsr_telnet_result
571 _cb_telnet_timeout(struct olsr_telnet_data *data) {
572   if (data->parameter == NULL) {
573     data->timeout_value = 0;
574   }
575   else {
576     data->timeout_value = (uint32_t)strtoul(data->parameter, NULL, 10) * 1000;
577   }
578   return TELNET_RESULT_ACTIVE;
579 }
580
581 /**
582  * Stop handler for repeating telnet commands
583  * @param data pointer to telnet data
584  */
585 static void
586 _cb_telnet_repeat_stophandler(struct olsr_telnet_data *data) {
587   olsr_timer_stop((struct olsr_timer_entry *)data->stop_data[0]);
588   free(data->stop_data[1]);
589
590   data->stop_handler = NULL;
591   data->stop_data[0] = NULL;
592   data->stop_data[1] = NULL;
593   data->stop_data[2] = NULL;
594 }
595
596 /**
597  * Timer event handler for repeating telnet commands
598  * @param ptr pointer to custom data
599  */
600 static void
601 _cb_telnet_repeat_timer(void *ptr) {
602   struct olsr_telnet_data *telnet_data = ptr;
603   struct olsr_telnet_session *session;
604
605   /* set command/parameter with repeat settings */
606   telnet_data->command = telnet_data->stop_data[1];
607   telnet_data->parameter = telnet_data->stop_data[2];
608
609   if (_telnet_handle_command(telnet_data) != TELNET_RESULT_ACTIVE) {
610     _call_stop_handler(telnet_data);
611   }
612
613   /* reconstruct original session pointer */
614   session = container_of(telnet_data, struct olsr_telnet_session, data);
615   olsr_stream_flush(&session->session);
616 }
617
618 /**
619  * Telnet command 'repeat'
620  * @param data pointer to telnet data
621  * @return telnet command result
622  */
623 static enum olsr_telnet_result
624 _cb_telnet_repeat(struct olsr_telnet_data *data) {
625   struct olsr_timer_entry *timer;
626   int interval = 0;
627   char *ptr = NULL;
628
629   if (data->stop_handler) {
630     abuf_puts(data->out, "Error, you cannot stack continous output commands\n");
631     return TELNET_RESULT_ACTIVE;
632   }
633
634   if (data->parameter == NULL || (ptr = strchr(data->parameter, ' ')) == NULL) {
635     abuf_puts(data->out, "Missing parameters for repeat\n");
636     return TELNET_RESULT_ACTIVE;
637   }
638
639   ptr++;
640
641   interval = atoi(data->parameter);
642
643   timer = olsr_timer_start(interval * 1000, 0, data, &_telnet_repeat_timerinfo);
644   data->stop_handler = _cb_telnet_repeat_stophandler;
645   data->stop_data[0] = timer;
646   data->stop_data[1] = strdup(ptr);
647   data->stop_data[2] = NULL;
648
649   /* split command/parameter and remember it */
650   ptr = strchr(data->stop_data[1], ' ');
651   if (ptr != NULL) {
652     /* found a parameter */
653     *ptr++ = 0;
654     data->stop_data[2] = ptr;
655   }
656
657   /* start command the first time */
658   data->command = data->stop_data[1];
659   data->parameter = data->stop_data[2];
660
661   if (_telnet_handle_command(data) != TELNET_RESULT_ACTIVE) {
662     _call_stop_handler(data);
663   }
664
665   return TELNET_RESULT_CONTINOUS;
666 }
667
668 /**
669  * Telnet command 'version'
670  * @param data pointer to telnet data
671  * @return telnet command result
672  */
673 static enum olsr_telnet_result
674 _cb_telnet_version(struct olsr_telnet_data *data) {
675   olsr_log_printversion(data->out);
676   return TELNET_RESULT_ACTIVE;
677 }
678
679 /**
680  * Telnet command 'plugin'
681  * @param data pointer to telnet data
682  * @return telnet command result
683  */
684 static enum olsr_telnet_result
685 _cb_telnet_plugin(struct olsr_telnet_data *data) {
686   struct olsr_plugin *plugin, *iterator;
687   const char *plugin_name = NULL;
688
689   if (data->parameter == NULL || strcasecmp(data->parameter, "list") == 0) {
690     if (abuf_puts(data->out, "Plugins:\n") < 0) {
691       return TELNET_RESULT_INTERNAL_ERROR;
692     }
693     OLSR_FOR_ALL_PLUGIN_ENTRIES(plugin, iterator) {
694       if (abuf_appendf(data->out, " %-30s\t%s\t%s\n",
695           plugin->name, olsr_plugins_is_enabled(plugin) ? "enabled" : "",
696           olsr_plugins_is_static(plugin) ? "static" : "") < 0) {
697         return TELNET_RESULT_INTERNAL_ERROR;
698       }
699     }
700     return TELNET_RESULT_ACTIVE;
701   }
702
703   plugin_name = strchr(data->parameter, ' ');
704   if (plugin_name == NULL) {
705     if (abuf_appendf(data->out, "Error, missing or unknown parameter\n") < 0) {
706       return TELNET_RESULT_INTERNAL_ERROR;
707     }
708     return TELNET_RESULT_ACTIVE;
709   }
710
711   /* skip whitespaces */
712   while (isspace(*plugin_name)) {
713     plugin_name++;
714   }
715
716   plugin = olsr_plugins_get(plugin_name);
717   if (str_hasnextword(data->parameter, "load") == NULL) {
718     if (plugin != NULL) {
719       abuf_appendf(data->out, "Plugin %s already loaded\n", plugin_name);
720       return TELNET_RESULT_ACTIVE;
721     }
722     plugin = olsr_plugins_load(plugin_name);
723     if (plugin != NULL) {
724       abuf_appendf(data->out, "Plugin %s successfully loaded\n", plugin_name);
725     }
726     else {
727       abuf_appendf(data->out, "Could not load plugin %s\n", plugin_name);
728     }
729     return TELNET_RESULT_ACTIVE;
730   }
731
732   if (plugin == NULL) {
733     if (abuf_appendf(data->out,
734         "Error, could not find plugin '%s'.\n", plugin_name) < 0) {
735       return TELNET_RESULT_INTERNAL_ERROR;
736     }
737     return TELNET_RESULT_ACTIVE;
738   }
739   if (str_hasnextword(data->parameter, "activate") == NULL) {
740     if (olsr_plugins_is_enabled(plugin)) {
741       abuf_appendf(data->out, "Plugin %s already active\n", plugin_name);
742     }
743     else {
744       if (olsr_plugins_enable(plugin)) {
745         abuf_appendf(data->out, "Could not activate plugin %s\n", plugin_name);
746       }
747       else {
748         abuf_appendf(data->out, "Plugin %s successfully activated\n", plugin_name);
749       }
750     }
751   }
752   else if (str_hasnextword(data->parameter, "deactivate") == NULL) {
753     if (!olsr_plugins_is_enabled(plugin)) {
754       abuf_appendf(data->out, "Plugin %s is not active\n", plugin_name);
755     }
756     else {
757       if (olsr_plugins_disable(plugin)) {
758         abuf_appendf(data->out, "Could not deactivate plugin %s\n", plugin_name);
759       }
760       else {
761         abuf_appendf(data->out, "Plugin %s successfully deactivated\n", plugin_name);
762       }
763     }
764   }
765   else if (str_hasnextword(data->parameter, "unload") == NULL) {
766     if (olsr_plugins_is_static(plugin)) {
767       abuf_appendf(data->out, "Plugin %s is static and cannot be unloaded\n", plugin_name);
768     }
769     else {
770       if (olsr_plugins_unload(plugin)) {
771         abuf_appendf(data->out, "Could not unload plugin %s\n", plugin_name);
772       }
773       else {
774         abuf_appendf(data->out, "Plugin %s successfully unloaded\n", plugin_name);
775       }
776     }
777   }
778   else {
779     abuf_appendf(data->out, "Unknown command '%s %s %s'.\n",
780         data->command, data->parameter, plugin_name);
781   }
782   return TELNET_RESULT_ACTIVE;
783 }