added files
[bcm963xx.git] / userapps / opensource / zebra / lib / vty.c
1 /*
2  * Virtual terminal [aka TeletYpe] interface routine.
3  * Copyright (C) 1997, 98 Kunihiro Ishiguro
4  *
5  * This file is part of GNU Zebra.
6  *
7  * GNU Zebra is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the
9  * Free Software Foundation; either version 2, or (at your option) any
10  * later version.
11  *
12  * GNU Zebra is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
19  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20  * 02111-1307, USA.  
21  */
22
23 #include <zebra.h>
24
25 #include "linklist.h"
26 #include "buffer.h"
27 #include "version.h"
28 #include "command.h"
29 #include "sockunion.h"
30 #include "thread.h"
31 #include "memory.h"
32 #include "str.h"
33 #include "log.h"
34 #include "prefix.h"
35 #include "filter.h"
36
37 #if defined(BRCM_CMD_SUPPORT)
38 /* Vty events */
39 enum event 
40 {
41   VTY_SERV,
42   VTY_READ,
43   VTY_WRITE,
44   VTY_TIMEOUT_RESET,
45 #ifdef VTYSH
46   VTYSH_SERV,
47   VTYSH_READ
48 #endif /* VTYSH */
49 };
50
51 static void vty_event (enum event, int, struct vty *);
52 #endif /* BRCM_CMD_SUPPORT */
53
54 /* Extern host structure from command.c */
55 extern struct host host;
56 \f
57 /* Vector which store each vty structure. */
58 static vector vtyvec;
59
60 #if defined(BRCM_CMD_SUPPORT)
61 /* Vty timeout value. */
62 static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT;
63
64 /* Vty access-class command */
65 static char *vty_accesslist_name = NULL;
66 #endif /* BRCM_CMD_SUPPORT */
67
68 #ifdef HAVE_IPV6
69 /* Vty access-calss for IPv6. */
70 static char *vty_ipv6_accesslist_name = NULL;
71 #endif
72
73 /* VTY server thread. */
74 vector Vvty_serv_thread;
75
76 #if defined(BRCM_CMD_SUPPORT)
77 /* Current directory. */
78 char *vty_cwd = NULL;
79 #endif
80
81 /* Configure lock. */
82 static int vty_config;
83 #if defined(BRCM_CMD_SUPPORT)
84 /* Login password check. */
85 static int no_password_check = 0;
86
87 /* Integrated configuration file path */
88 char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
89 #endif /* BRCM_CMD_SUPPORT */
90
91 \f
92 /* VTY standard output function. */
93
94 #if defined(BRCM_CMD_SUPPORT)
95 int
96 vty_out (struct vty *vty, const char *format, ...)
97 {
98   va_list args;
99   int len = 0;
100   int size = 1024;
101   char buf[1024];
102   char *p = NULL;
103   
104   va_start (args, format);
105
106   if (vty_shell (vty))
107     vprintf (format, args);
108   else
109     {
110       /* Try to write to initial buffer.  */
111       len = vsnprintf (buf, sizeof buf, format, args);
112
113       /* Initial buffer is not enough.  */
114       if (len < 0 || len >= size)
115         {
116           while (1)
117             {
118               if (len > -1)
119                 size = len + 1;
120               else
121                 size = size * 2;
122
123               p = XREALLOC (MTYPE_VTY_OUT_BUF, p, size);
124               if (! p)
125                 return -1;
126
127               len = vsnprintf (p, size, format, args);
128
129               if (len > -1 && len < size)
130                 break;
131             }
132         }
133
134       /* When initial buffer is enough to store all output.  */
135       if (! p)
136         p = buf;
137
138       /* Pointer p must point out buffer. */
139       if (vty_shell_serv (vty))
140         write (vty->fd, (u_char *) p, len);
141       else
142         buffer_write (vty->obuf, (u_char *) p, len);
143
144       /* If p is not different with buf, it is allocated buffer.  */
145       if (p != buf)
146         XFREE (MTYPE_VTY_OUT_BUF, p);
147     }
148
149   va_end (args);
150
151   return len;
152 }
153 #else /* BRCM_CMD_SUPPORT */
154 int
155 vty_out (struct vty *vty, const char *format, ...)
156 {
157   return 1;
158 }
159 #endif /* BRCM_CMD_SUPPORT */
160
161 #if defined(BRCM_RIP_DEBUG) || defined(BRCM_CMD_SUPPORT)
162 int
163 vvty_out (struct vty *vty, const char *format, va_list va)
164 {
165   int len;
166   /* XXX need overflow check */
167   char buf[1024];
168
169   len = vsnprintf (buf, sizeof buf, format, va);
170
171   if (len < 0)
172     {    
173 #ifdef BRCM_RIP_DEBUG
174       zlog (NULL, LOG_INFO, "Vty closed due to vty output buffer shortage.");
175 #endif
176       return -1;
177     }
178
179   buffer_write (vty->obuf, (u_char *)buf, len);
180   return len;
181 }
182 #endif /* defined(BRCM_RIP_DEBUG) || defined(BRCM_CMD_SUPPORT) */
183
184 #if defined(BRCM_CMD_SUPPORT) || defined(BRCM_RIP_DEBUG)
185 /* Output current time to the vty. */
186 void
187 vty_time_print (struct vty *vty, int cr)
188 {
189   time_t clock;
190   struct tm *tm;
191 #define TIME_BUF 25
192   char buf [TIME_BUF];
193   int ret;
194   
195   time (&clock);
196   tm = localtime (&clock);
197
198   ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm);
199   if (ret == 0)
200     {
201 #ifdef BRCM_RIP_DEBUG
202       zlog (NULL, LOG_INFO, "strftime error");
203 #endif
204       return;
205     }
206   if (cr)
207     vty_out (vty, "%s\n", buf);
208   else
209     vty_out (vty, "%s ", buf);
210
211   return;
212 }
213 #endif /* || defined(BRCM_RIP_DEBUG) */
214
215 #if defined(BRCM_CMD_SUPPORT)
216 /* Say hello to vty interface. */
217 void
218 vty_hello (struct vty *vty)
219 {
220   if (host.motd)
221     vty_out (vty, host.motd);
222 }
223
224 /* Put out prompt and wait input from user. */
225 static void
226 vty_prompt (struct vty *vty)
227 {
228   struct utsname names;
229   const char*hostname;
230
231   if (vty->type == VTY_TERM)
232     {
233       hostname = host.name;
234       if (!hostname)
235         {
236           uname (&names);
237           hostname = names.nodename;
238         }
239       vty_out (vty, cmd_prompt (vty->node), hostname);
240     }
241 }
242
243 /* Send WILL TELOPT_ECHO to remote server. */
244 void
245 vty_will_echo (struct vty *vty)
246 {
247   char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
248   vty_out (vty, "%s", cmd);
249 }
250
251 /* Make suppress Go-Ahead telnet option. */
252 static void
253 vty_will_suppress_go_ahead (struct vty *vty)
254 {
255   char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
256   vty_out (vty, "%s", cmd);
257 }
258
259 /* Make don't use linemode over telnet. */
260 static void
261 vty_dont_linemode (struct vty *vty)
262 {
263   char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
264   vty_out (vty, "%s", cmd);
265 }
266
267 /* Use window size. */
268 static void
269 vty_do_window_size (struct vty *vty)
270 {
271   char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
272   vty_out (vty, "%s", cmd);
273 }
274
275 #if 0 /* Currently not used. */
276 /* Make don't use lflow vty interface. */
277 static void
278 vty_dont_lflow_ahead (struct vty *vty)
279 {
280   char cmd[] = { IAC, DONT, TELOPT_LFLOW, '\0' };
281   vty_out (vty, "%s", cmd);
282 }
283 #endif /* 0 */
284 #endif /* BRCM_CMD_SUPPORT */
285
286 /* Allocate new vty struct. */
287 struct vty *
288 vty_new ()
289 {
290   struct vty *new = XCALLOC (MTYPE_VTY, sizeof (struct vty));
291
292 #if defined(BRCM_CMD_SUPPORT)
293   new->obuf = (struct buffer *) buffer_new (100);
294 #endif
295   new->buf = XCALLOC (MTYPE_VTY, VTY_BUFSIZ);
296   new->max = VTY_BUFSIZ;
297   new->sb_buffer = NULL;
298
299   return new;
300 }
301
302 #if defined(BRCM_CMD_SUPPORT)
303 /* Authentication of vty */
304 static void
305 vty_auth (struct vty *vty, char *buf)
306 {
307   char *passwd = NULL;
308   enum node_type next_node = 0;
309   int fail;
310   char *crypt (const char *, const char *);
311
312   switch (vty->node)
313     {
314     case AUTH_NODE:
315       if (host.encrypt)
316         passwd = host.password_encrypt;
317       else
318         passwd = host.password;
319       if (host.advanced)
320         next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
321       else
322         next_node = VIEW_NODE;
323       break;
324     case AUTH_ENABLE_NODE:
325       if (host.encrypt)
326         passwd = host.enable_encrypt;
327       else
328         passwd = host.enable;
329       next_node = ENABLE_NODE;
330       break;
331     }
332
333   if (passwd)
334     {
335       if (host.encrypt)
336         fail = strcmp (crypt(buf, passwd), passwd);
337       else
338         fail = strcmp (buf, passwd);
339     }
340   else
341     fail = 1;
342
343   if (! fail)
344     {
345       vty->fail = 0;
346       vty->node = next_node;    /* Success ! */
347     }
348   else
349     {
350       vty->fail++;
351       if (vty->fail >= 3)
352         {
353           if (vty->node == AUTH_NODE)
354             {
355               vty_out (vty, "%% Bad passwords, too many failures!%s", VTY_NEWLINE);
356               vty->status = VTY_CLOSE;
357             }
358           else                  
359             {
360               /* AUTH_ENABLE_NODE */
361               vty->fail = 0;
362               vty_out (vty, "%% Bad enable passwords, too many failures!%s", VTY_NEWLINE);
363               vty->node = VIEW_NODE;
364             }
365         }
366     }
367 }
368
369 /* Command execution over the vty interface. */
370 int
371 vty_command (struct vty *vty, char *buf)
372 {
373   int ret;
374   vector vline;
375
376   /* Split readline string up into the vector */
377   vline = cmd_make_strvec (buf);
378
379   if (vline == NULL)
380     return CMD_SUCCESS;
381
382   ret = cmd_execute_command (vline, vty, NULL);
383
384   if (ret != CMD_SUCCESS)
385     switch (ret)
386       {
387       case CMD_WARNING:
388         if (vty->type == VTY_FILE)
389           vty_out (vty, "Warning...%s", VTY_NEWLINE);
390         break;
391       case CMD_ERR_AMBIGUOUS:
392         vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
393         break;
394       case CMD_ERR_NO_MATCH:
395         vty_out (vty, "%% Unknown command.%s", VTY_NEWLINE);
396         break;
397       case CMD_ERR_INCOMPLETE:
398         vty_out (vty, "%% Command incomplete.%s", VTY_NEWLINE);
399         break;
400       }
401   cmd_free_strvec (vline);
402
403   return ret;
404 }
405 \f
406 char telnet_backward_char = 0x08;
407 char telnet_space_char = ' ';
408
409 /* Basic function to write buffer to vty. */
410 static void
411 vty_write (struct vty *vty, char *buf, size_t nbytes)
412 {
413   if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
414     return;
415
416   /* Should we do buffering here ?  And make vty_flush (vty) ? */
417   buffer_write (vty->obuf, (u_char *)buf, nbytes);
418 }
419
420 /* Ensure length of input buffer.  Is buffer is short, double it. */
421 static void
422 vty_ensure (struct vty *vty, int length)
423 {
424   if (vty->max <= length)
425     {
426       vty->max *= 2;
427       vty->buf = XREALLOC (MTYPE_VTY, vty->buf, vty->max);
428     }
429 }
430
431 /* Basic function to insert character into vty. */
432 static void
433 vty_self_insert (struct vty *vty, char c)
434 {
435   int i;
436   int length;
437
438   vty_ensure (vty, vty->length + 1);
439   length = vty->length - vty->cp;
440   memmove (&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
441   vty->buf[vty->cp] = c;
442
443   vty_write (vty, &vty->buf[vty->cp], length + 1);
444   for (i = 0; i < length; i++)
445     vty_write (vty, &telnet_backward_char, 1);
446
447   vty->cp++;
448   vty->length++;
449 }
450
451 /* Self insert character 'c' in overwrite mode. */
452 static void
453 vty_self_insert_overwrite (struct vty *vty, char c)
454 {
455   vty_ensure (vty, vty->length + 1);
456   vty->buf[vty->cp++] = c;
457
458   if (vty->cp > vty->length)
459     vty->length++;
460
461   if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
462     return;
463
464   vty_write (vty, &c, 1);
465 }
466
467 /* Insert a word into vty interface with overwrite mode. */
468 static void
469 vty_insert_word_overwrite (struct vty *vty, char *str)
470 {
471   int len = strlen (str);
472   vty_write (vty, str, len);
473   strcpy (&vty->buf[vty->cp], str);
474   vty->cp += len;
475   vty->length = vty->cp;
476 }
477
478 /* Forward character. */
479 static void
480 vty_forward_char (struct vty *vty)
481 {
482   if (vty->cp < vty->length)
483     {
484       vty_write (vty, &vty->buf[vty->cp], 1);
485       vty->cp++;
486     }
487 }
488
489 /* Backward character. */
490 static void
491 vty_backward_char (struct vty *vty)
492 {
493   if (vty->cp > 0)
494     {
495       vty->cp--;
496       vty_write (vty, &telnet_backward_char, 1);
497     }
498 }
499
500 /* Move to the beginning of the line. */
501 static void
502 vty_beginning_of_line (struct vty *vty)
503 {
504   while (vty->cp)
505     vty_backward_char (vty);
506 }
507
508 /* Move to the end of the line. */
509 static void
510 vty_end_of_line (struct vty *vty)
511 {
512   while (vty->cp < vty->length)
513     vty_forward_char (vty);
514 }
515
516 static void vty_kill_line_from_beginning (struct vty *);
517 static void vty_redraw_line (struct vty *);
518
519 /* Print command line history.  This function is called from
520    vty_next_line and vty_previous_line. */
521 static void
522 vty_history_print (struct vty *vty)
523 {
524   int length;
525
526   vty_kill_line_from_beginning (vty);
527
528   /* Get previous line from history buffer */
529   length = strlen (vty->hist[vty->hp]);
530   memcpy (vty->buf, vty->hist[vty->hp], length);
531   vty->cp = vty->length = length;
532
533   /* Redraw current line */
534   vty_redraw_line (vty);
535 }
536
537 /* Show next command line history. */
538 void
539 vty_next_line (struct vty *vty)
540 {
541   int try_index;
542
543   if (vty->hp == vty->hindex)
544     return;
545
546   /* Try is there history exist or not. */
547   try_index = vty->hp;
548   if (try_index == (VTY_MAXHIST - 1))
549     try_index = 0;
550   else
551     try_index++;
552
553   /* If there is not history return. */
554   if (vty->hist[try_index] == NULL)
555     return;
556   else
557     vty->hp = try_index;
558
559   vty_history_print (vty);
560 }
561
562 /* Show previous command line history. */
563 void
564 vty_previous_line (struct vty *vty)
565 {
566   int try_index;
567
568   try_index = vty->hp;
569   if (try_index == 0)
570     try_index = VTY_MAXHIST - 1;
571   else
572     try_index--;
573
574   if (vty->hist[try_index] == NULL)
575     return;
576   else
577     vty->hp = try_index;
578
579   vty_history_print (vty);
580 }
581
582 /* This function redraw all of the command line character. */
583 static void
584 vty_redraw_line (struct vty *vty)
585 {
586   vty_write (vty, vty->buf, vty->length);
587   vty->cp = vty->length;
588 }
589
590 /* Forward word. */
591 static void
592 vty_forward_word (struct vty *vty)
593 {
594   while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
595     vty_forward_char (vty);
596   
597   while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
598     vty_forward_char (vty);
599 }
600
601 /* Backward word without skipping training space. */
602 static void
603 vty_backward_pure_word (struct vty *vty)
604 {
605   while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
606     vty_backward_char (vty);
607 }
608
609 /* Backward word. */
610 static void
611 vty_backward_word (struct vty *vty)
612 {
613   while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
614     vty_backward_char (vty);
615
616   while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
617     vty_backward_char (vty);
618 }
619
620 /* When '^D' is typed at the beginning of the line we move to the down
621    level. */
622 static void
623 vty_down_level (struct vty *vty)
624 {
625   vty_out (vty, "%s", VTY_NEWLINE);
626   config_exit (NULL, vty, 0, NULL);
627   vty_prompt (vty);
628   vty->cp = 0;
629 }
630
631 /* When '^Z' is received from vty, move down to the enable mode. */
632 void
633 vty_end_config (struct vty *vty)
634 {
635   vty_out (vty, "%s", VTY_NEWLINE);
636
637   switch (vty->node)
638     {
639     case VIEW_NODE:
640     case ENABLE_NODE:
641       /* Nothing to do. */
642       break;
643     case CONFIG_NODE:
644     case INTERFACE_NODE:
645     case ZEBRA_NODE:
646     case RIP_NODE:
647     case RIPNG_NODE:
648     case BGP_NODE:
649     case BGP_VPNV4_NODE:
650     case BGP_IPV4_NODE:
651     case BGP_IPV4M_NODE:
652     case BGP_IPV6_NODE:
653     case RMAP_NODE:
654     case OSPF_NODE:
655     case OSPF6_NODE:
656     case KEYCHAIN_NODE:
657     case KEYCHAIN_KEY_NODE:
658     case MASC_NODE:
659     case VTY_NODE:
660       vty_config_unlock (vty);
661       vty->node = ENABLE_NODE;
662       break;
663     default:
664       /* Unknown node, we have to ignore it. */
665       break;
666     }
667
668   vty_prompt (vty);
669   vty->cp = 0;
670 }
671
672 /* Delete a charcter at the current point. */
673 static void
674 vty_delete_char (struct vty *vty)
675 {
676   int i;
677   int size;
678
679   if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
680     return;
681
682   if (vty->length == 0)
683     {
684       vty_down_level (vty);
685       return;
686     }
687
688   if (vty->cp == vty->length)
689     return;                     /* completion need here? */
690
691   size = vty->length - vty->cp;
692
693   vty->length--;
694   memmove (&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
695   vty->buf[vty->length] = '\0';
696
697   vty_write (vty, &vty->buf[vty->cp], size - 1);
698   vty_write (vty, &telnet_space_char, 1);
699
700   for (i = 0; i < size; i++)
701     vty_write (vty, &telnet_backward_char, 1);
702 }
703
704 /* Delete a character before the point. */
705 static void
706 vty_delete_backward_char (struct vty *vty)
707 {
708   if (vty->cp == 0)
709     return;
710
711   vty_backward_char (vty);
712   vty_delete_char (vty);
713 }
714
715 /* Kill rest of line from current point. */
716 static void
717 vty_kill_line (struct vty *vty)
718 {
719   int i;
720   int size;
721
722   size = vty->length - vty->cp;
723   
724   if (size == 0)
725     return;
726
727   for (i = 0; i < size; i++)
728     vty_write (vty, &telnet_space_char, 1);
729   for (i = 0; i < size; i++)
730     vty_write (vty, &telnet_backward_char, 1);
731
732   memset (&vty->buf[vty->cp], 0, size);
733   vty->length = vty->cp;
734 }
735
736 /* Kill line from the beginning. */
737 static void
738 vty_kill_line_from_beginning (struct vty *vty)
739 {
740   vty_beginning_of_line (vty);
741   vty_kill_line (vty);
742 }
743
744 /* Delete a word before the point. */
745 static void
746 vty_forward_kill_word (struct vty *vty)
747 {
748   while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
749     vty_delete_char (vty);
750   while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
751     vty_delete_char (vty);
752 }
753
754 /* Delete a word before the point. */
755 static void
756 vty_backward_kill_word (struct vty *vty)
757 {
758   while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
759     vty_delete_backward_char (vty);
760   while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
761     vty_delete_backward_char (vty);
762 }
763
764 /* Transpose chars before or at the point. */
765 static void
766 vty_transpose_chars (struct vty *vty)
767 {
768   char c1, c2;
769
770   /* If length is short or point is near by the beginning of line then
771      return. */
772   if (vty->length < 2 || vty->cp < 1)
773     return;
774
775   /* In case of point is located at the end of the line. */
776   if (vty->cp == vty->length)
777     {
778       c1 = vty->buf[vty->cp - 1];
779       c2 = vty->buf[vty->cp - 2];
780
781       vty_backward_char (vty);
782       vty_backward_char (vty);
783       vty_self_insert_overwrite (vty, c1);
784       vty_self_insert_overwrite (vty, c2);
785     }
786   else
787     {
788       c1 = vty->buf[vty->cp];
789       c2 = vty->buf[vty->cp - 1];
790
791       vty_backward_char (vty);
792       vty_self_insert_overwrite (vty, c1);
793       vty_self_insert_overwrite (vty, c2);
794     }
795 }
796
797 /* Do completion at vty interface. */
798 static void
799 vty_complete_command (struct vty *vty)
800 {
801   int i;
802   int ret;
803   char **matched = NULL;
804   vector vline;
805
806   if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
807     return;
808
809   vline = cmd_make_strvec (vty->buf);
810   if (vline == NULL)
811     return;
812
813   /* In case of 'help \t'. */
814   if (isspace ((int) vty->buf[vty->length - 1]))
815     vector_set (vline, '\0');
816
817   matched = cmd_complete_command (vline, vty, &ret);
818   
819   cmd_free_strvec (vline);
820
821   vty_out (vty, "%s", VTY_NEWLINE);
822   switch (ret)
823     {
824     case CMD_ERR_AMBIGUOUS:
825       vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
826       vty_prompt (vty);
827       vty_redraw_line (vty);
828       break;
829     case CMD_ERR_NO_MATCH:
830       /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
831       vty_prompt (vty);
832       vty_redraw_line (vty);
833       break;
834     case CMD_COMPLETE_FULL_MATCH:
835       vty_prompt (vty);
836       vty_redraw_line (vty);
837       vty_backward_pure_word (vty);
838       vty_insert_word_overwrite (vty, matched[0]);
839       vty_self_insert (vty, ' ');
840       XFREE (MTYPE_TMP, matched[0]);
841       break;
842     case CMD_COMPLETE_MATCH:
843       vty_prompt (vty);
844       vty_redraw_line (vty);
845       vty_backward_pure_word (vty);
846       vty_insert_word_overwrite (vty, matched[0]);
847       XFREE (MTYPE_TMP, matched[0]);
848       vector_only_index_free (matched);
849       return;
850       break;
851     case CMD_COMPLETE_LIST_MATCH:
852       for (i = 0; matched[i] != NULL; i++)
853         {
854           if (i != 0 && ((i % 6) == 0))
855             vty_out (vty, "%s", VTY_NEWLINE);
856           vty_out (vty, "%-10s ", matched[i]);
857           XFREE (MTYPE_TMP, matched[i]);
858         }
859       vty_out (vty, "%s", VTY_NEWLINE);
860
861       vty_prompt (vty);
862       vty_redraw_line (vty);
863       break;
864     case CMD_ERR_NOTHING_TODO:
865       vty_prompt (vty);
866       vty_redraw_line (vty);
867       break;
868     default:
869       break;
870     }
871   if (matched)
872     vector_only_index_free (matched);
873 }
874
875 void
876 vty_describe_fold (struct vty *vty, int cmd_width,
877                  int desc_width, struct desc *desc)
878 {
879   char *buf, *cmd, *p;
880   int pos;
881
882   cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
883
884   if (desc_width <= 0)
885     {
886       vty_out (vty, "  %-*s  %s%s", cmd_width, cmd, desc->str, VTY_NEWLINE);
887       return;
888     }
889
890   buf = XCALLOC (MTYPE_TMP, strlen (desc->str) + 1);
891
892   for (p = desc->str; strlen (p) > desc_width; p += pos + 1)
893     {
894       for (pos = desc_width; pos > 0; pos--)
895       if (*(p + pos) == ' ')
896         break;
897
898       if (pos == 0)
899       break;
900
901       strncpy (buf, p, pos);
902       buf[pos] = '\0';
903       vty_out (vty, "  %-*s  %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
904
905       cmd = "";
906     }
907
908   vty_out (vty, "  %-*s  %s%s", cmd_width, cmd, p, VTY_NEWLINE);
909
910   XFREE (MTYPE_TMP, buf);
911 }
912
913 /* Describe matched command function. */
914 static void
915 vty_describe_command (struct vty *vty)
916 {
917   int ret;
918   vector vline;
919   vector describe;
920   int i, width, desc_width;
921   struct desc *desc, *desc_cr = NULL;
922
923   vline = cmd_make_strvec (vty->buf);
924
925   /* In case of '> ?'. */
926   if (vline == NULL)
927     {
928       vline = vector_init (1);
929       vector_set (vline, '\0');
930     }
931   else 
932     if (isspace ((int) vty->buf[vty->length - 1]))
933       vector_set (vline, '\0');
934
935   describe = cmd_describe_command (vline, vty, &ret);
936
937   vty_out (vty, "%s", VTY_NEWLINE);
938
939   /* Ambiguous error. */
940   switch (ret)
941     {
942     case CMD_ERR_AMBIGUOUS:
943       cmd_free_strvec (vline);
944       vty_out (vty, "%% Ambiguous command.%s", VTY_NEWLINE);
945       vty_prompt (vty);
946       vty_redraw_line (vty);
947       return;
948       break;
949     case CMD_ERR_NO_MATCH:
950       cmd_free_strvec (vline);
951       vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE);
952       vty_prompt (vty);
953       vty_redraw_line (vty);
954       return;
955       break;
956     }  
957
958   /* Get width of command string. */
959   width = 0;
960   for (i = 0; i < vector_max (describe); i++)
961     if ((desc = vector_slot (describe, i)) != NULL)
962       {
963         int len;
964
965         if (desc->cmd[0] == '\0')
966           continue;
967
968         len = strlen (desc->cmd);
969         if (desc->cmd[0] == '.')
970           len--;
971
972         if (width < len)
973           width = len;
974       }
975
976   /* Get width of description string. */
977   desc_width = vty->width - (width + 6);
978
979   /* Print out description. */
980   for (i = 0; i < vector_max (describe); i++)
981     if ((desc = vector_slot (describe, i)) != NULL)
982       {
983         if (desc->cmd[0] == '\0')
984           continue;
985         
986         if (strcmp (desc->cmd, "<cr>") == 0)
987           {
988             desc_cr = desc;
989             continue;
990           }
991
992         if (!desc->str)
993           vty_out (vty, "  %-s%s",
994                    desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
995                    VTY_NEWLINE);
996         else if (desc_width >= strlen (desc->str))
997           vty_out (vty, "  %-*s  %s%s", width,
998                    desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
999                    desc->str, VTY_NEWLINE);
1000         else
1001           vty_describe_fold (vty, width, desc_width, desc);
1002
1003 #if 0
1004         vty_out (vty, "  %-*s %s%s", width
1005                  desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1006                  desc->str ? desc->str : "", VTY_NEWLINE);
1007 #endif /* 0 */
1008       }
1009
1010   if ((desc = desc_cr))
1011     {
1012       if (!desc->str)
1013         vty_out (vty, "  %-s%s",
1014                  desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1015                  VTY_NEWLINE);
1016       else if (desc_width >= strlen (desc->str))
1017         vty_out (vty, "  %-*s  %s%s", width,
1018                  desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
1019                  desc->str, VTY_NEWLINE);
1020       else
1021         vty_describe_fold (vty, width, desc_width, desc);
1022     }
1023
1024   cmd_free_strvec (vline);
1025   vector_free (describe);
1026
1027   vty_prompt (vty);
1028   vty_redraw_line (vty);
1029 }
1030
1031 void
1032 vty_clear_buf (struct vty *vty)
1033 {
1034   memset (vty->buf, 0, vty->max);
1035 }
1036
1037 /* ^C stop current input and do not add command line to the history. */
1038 static void
1039 vty_stop_input (struct vty *vty)
1040 {
1041   vty->cp = vty->length = 0;
1042   vty_clear_buf (vty);
1043   vty_out (vty, "%s", VTY_NEWLINE);
1044
1045   switch (vty->node)
1046     {
1047     case VIEW_NODE:
1048     case ENABLE_NODE:
1049       /* Nothing to do. */
1050       break;
1051     case CONFIG_NODE:
1052     case INTERFACE_NODE:
1053     case ZEBRA_NODE:
1054     case RIP_NODE:
1055     case RIPNG_NODE:
1056     case BGP_NODE:
1057     case RMAP_NODE:
1058     case OSPF_NODE:
1059     case OSPF6_NODE:
1060     case KEYCHAIN_NODE:
1061     case KEYCHAIN_KEY_NODE:
1062     case MASC_NODE:
1063     case VTY_NODE:
1064       vty_config_unlock (vty);
1065       vty->node = ENABLE_NODE;
1066       break;
1067     default:
1068       /* Unknown node, we have to ignore it. */
1069       break;
1070     }
1071   vty_prompt (vty);
1072
1073   /* Set history pointer to the latest one. */
1074   vty->hp = vty->hindex;
1075 }
1076
1077 /* Add current command line to the history buffer. */
1078 static void
1079 vty_hist_add (struct vty *vty)
1080 {
1081   int index;
1082
1083   if (vty->length == 0)
1084     return;
1085
1086   index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
1087
1088   /* Ignore the same string as previous one. */
1089   if (vty->hist[index])
1090     if (strcmp (vty->buf, vty->hist[index]) == 0)
1091       {
1092       vty->hp = vty->hindex;
1093       return;
1094       }
1095
1096   /* Insert history entry. */
1097   if (vty->hist[vty->hindex])
1098     XFREE (MTYPE_VTY_HIST, vty->hist[vty->hindex]);
1099   vty->hist[vty->hindex] = XSTRDUP (MTYPE_VTY_HIST, vty->buf);
1100
1101   /* History index rotation. */
1102   vty->hindex++;
1103   if (vty->hindex == VTY_MAXHIST)
1104     vty->hindex = 0;
1105
1106   vty->hp = vty->hindex;
1107 }
1108
1109 /* #define TELNET_OPTION_DEBUG */
1110
1111 /* Get telnet window size. */
1112 static int
1113 vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
1114 {
1115 #ifdef TELNET_OPTION_DEBUG
1116   int i;
1117
1118   for (i = 0; i < nbytes; i++)
1119     {
1120       switch (buf[i])
1121         {
1122         case IAC:
1123           vty_out (vty, "IAC ");
1124           break;
1125         case WILL:
1126           vty_out (vty, "WILL ");
1127           break;
1128         case WONT:
1129           vty_out (vty, "WONT ");
1130           break;
1131         case DO:
1132           vty_out (vty, "DO ");
1133           break;
1134         case DONT:
1135           vty_out (vty, "DONT ");
1136           break;
1137         case SB:
1138           vty_out (vty, "SB ");
1139           break;
1140         case SE:
1141           vty_out (vty, "SE ");
1142           break;
1143         case TELOPT_ECHO:
1144           vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
1145           break;
1146         case TELOPT_SGA:
1147           vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
1148           break;
1149         case TELOPT_NAWS:
1150           vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
1151           break;
1152         default:
1153           vty_out (vty, "%x ", buf[i]);
1154           break;
1155         }
1156     }
1157   vty_out (vty, "%s", VTY_NEWLINE);
1158
1159 #endif /* TELNET_OPTION_DEBUG */
1160
1161   switch (buf[0])
1162     {
1163     case SB:
1164       buffer_reset(vty->sb_buffer);
1165       vty->iac_sb_in_progress = 1;
1166       return 0;
1167       break;
1168     case SE: 
1169       {
1170         char *buffer = (char *)vty->sb_buffer->head->data;
1171         int length = vty->sb_buffer->length;
1172
1173         if (buffer == NULL)
1174           return 0;
1175
1176         if (!vty->iac_sb_in_progress)
1177           return 0;
1178
1179         if (buffer[0] == '\0')
1180           {
1181             vty->iac_sb_in_progress = 0;
1182             return 0;
1183           }
1184         switch (buffer[0])
1185           {
1186           case TELOPT_NAWS:
1187             if (length < 5)
1188               break;
1189             vty->width = buffer[2];
1190             vty->height = vty->lines >= 0 ? vty->lines : buffer[4];
1191             break;
1192           }
1193         vty->iac_sb_in_progress = 0;
1194         return 0;
1195         break;
1196       }
1197     default:
1198       break;
1199     }
1200   return 1;
1201 }
1202
1203 /* Execute current command line. */
1204 static int
1205 vty_execute (struct vty *vty)
1206 {
1207   int ret;
1208
1209   ret = CMD_SUCCESS;
1210
1211   switch (vty->node)
1212     {
1213     case AUTH_NODE:
1214     case AUTH_ENABLE_NODE:
1215       vty_auth (vty, vty->buf);
1216       break;
1217     default:
1218       ret = vty_command (vty, vty->buf);
1219       if (vty->type == VTY_TERM)
1220         vty_hist_add (vty);
1221       break;
1222     }
1223
1224   /* Clear command line buffer. */
1225   vty->cp = vty->length = 0;
1226   vty_clear_buf (vty);
1227
1228   if (vty->status != VTY_CLOSE 
1229       && vty->status != VTY_START
1230       && vty->status != VTY_CONTINUE)
1231     vty_prompt (vty);
1232
1233   return ret;
1234 }
1235
1236 #define CONTROL(X)  ((X) - '@')
1237 #define VTY_NORMAL     0
1238 #define VTY_PRE_ESCAPE 1
1239 #define VTY_ESCAPE     2
1240
1241 /* Escape character command map. */
1242 static void
1243 vty_escape_map (unsigned char c, struct vty *vty)
1244 {
1245   switch (c)
1246     {
1247     case ('A'):
1248       vty_previous_line (vty);
1249       break;
1250     case ('B'):
1251       vty_next_line (vty);
1252       break;
1253     case ('C'):
1254       vty_forward_char (vty);
1255       break;
1256     case ('D'):
1257       vty_backward_char (vty);
1258       break;
1259     default:
1260       break;
1261     }
1262
1263   /* Go back to normal mode. */
1264   vty->escape = VTY_NORMAL;
1265 }
1266
1267 /* Quit print out to the buffer. */
1268 static void
1269 vty_buffer_reset (struct vty *vty)
1270 {
1271   buffer_reset (vty->obuf);
1272   vty_prompt (vty);
1273   vty_redraw_line (vty);
1274 }
1275
1276 /* Read data via vty socket. */
1277 static int
1278 vty_read (struct thread *thread)
1279 {
1280   int i;
1281   int ret;
1282   int nbytes;
1283   unsigned char buf[VTY_READ_BUFSIZ];
1284
1285   int vty_sock = THREAD_FD (thread);
1286   struct vty *vty = THREAD_ARG (thread);
1287   vty->t_read = NULL;
1288
1289   /* Read raw data from socket */
1290   nbytes = read (vty->fd, buf, VTY_READ_BUFSIZ);
1291   if (nbytes <= 0)
1292     vty->status = VTY_CLOSE;
1293
1294   for (i = 0; i < nbytes; i++) 
1295     {
1296       if (buf[i] == IAC)
1297         {
1298           if (!vty->iac)
1299             {
1300               vty->iac = 1;
1301               continue;
1302             }
1303           else
1304             {
1305               vty->iac = 0;
1306             }
1307         }
1308       
1309       if (vty->iac_sb_in_progress && !vty->iac)
1310         {
1311             buffer_putc(vty->sb_buffer, buf[i]);
1312             continue;
1313         }
1314
1315       if (vty->iac)
1316         {
1317           /* In case of telnet command */
1318           ret = vty_telnet_option (vty, buf + i, nbytes - i);
1319           vty->iac = 0;
1320           i += ret;
1321           continue;
1322         }
1323
1324       if (vty->status == VTY_MORE)
1325         {
1326           switch (buf[i])
1327             {
1328             case CONTROL('C'):
1329             case 'q':
1330             case 'Q':
1331               if (vty->output_func)
1332                 (*vty->output_func) (vty, 1);
1333               vty_buffer_reset (vty);
1334               break;
1335             default:
1336               if (vty->output_func)
1337                 (*vty->output_func) (vty, 0);
1338               break;
1339             }
1340           continue;
1341         }
1342
1343       /* Escape character. */
1344       if (vty->escape == VTY_ESCAPE)
1345         {
1346           vty_escape_map (buf[i], vty);
1347           continue;
1348         }
1349
1350       /* Pre-escape status. */
1351       if (vty->escape == VTY_PRE_ESCAPE)
1352         {
1353           switch (buf[i])
1354             {
1355             case '[':
1356               vty->escape = VTY_ESCAPE;
1357               break;
1358             case 'b':
1359               vty_backward_word (vty);
1360               vty->escape = VTY_NORMAL;
1361               break;
1362             case 'f':
1363               vty_forward_word (vty);
1364               vty->escape = VTY_NORMAL;
1365               break;
1366             case 'd':
1367               vty_forward_kill_word (vty);
1368               vty->escape = VTY_NORMAL;
1369               break;
1370             case CONTROL('H'):
1371             case 0x7f:
1372               vty_backward_kill_word (vty);
1373               vty->escape = VTY_NORMAL;
1374               break;
1375             default:
1376               vty->escape = VTY_NORMAL;
1377               break;
1378             }
1379           continue;
1380         }
1381
1382       switch (buf[i])
1383         {
1384         case CONTROL('A'):
1385           vty_beginning_of_line (vty);
1386           break;
1387         case CONTROL('B'):
1388           vty_backward_char (vty);
1389           break;
1390         case CONTROL('C'):
1391           vty_stop_input (vty);
1392           break;
1393         case CONTROL('D'):
1394           vty_delete_char (vty);
1395           break;
1396         case CONTROL('E'):
1397           vty_end_of_line (vty);
1398           break;
1399         case CONTROL('F'):
1400           vty_forward_char (vty);
1401           break;
1402         case CONTROL('H'):
1403         case 0x7f:
1404           vty_delete_backward_char (vty);
1405           break;
1406         case CONTROL('K'):
1407           vty_kill_line (vty);
1408           break;
1409         case CONTROL('N'):
1410           vty_next_line (vty);
1411           break;
1412         case CONTROL('P'):
1413           vty_previous_line (vty);
1414           break;
1415         case CONTROL('T'):
1416           vty_transpose_chars (vty);
1417           break;
1418         case CONTROL('U'):
1419           vty_kill_line_from_beginning (vty);
1420           break;
1421         case CONTROL('W'):
1422           vty_backward_kill_word (vty);
1423           break;
1424         case CONTROL('Z'):
1425           vty_end_config (vty);
1426           break;
1427         case '\n':
1428         case '\r':
1429           vty_out (vty, "%s", VTY_NEWLINE);
1430           vty_execute (vty);
1431           break;
1432         case '\t':
1433           vty_complete_command (vty);
1434           break;
1435         case '?':
1436           if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
1437             vty_self_insert (vty, buf[i]);
1438           else
1439             vty_describe_command (vty);
1440           break;
1441         case '\033':
1442           if (i + 1 < nbytes && buf[i + 1] == '[')
1443             {
1444               vty->escape = VTY_ESCAPE;
1445               i++;
1446             }
1447           else
1448             vty->escape = VTY_PRE_ESCAPE;
1449           break;
1450         default:
1451           if (buf[i] > 31 && buf[i] < 127)
1452             vty_self_insert (vty, buf[i]);
1453           break;
1454         }
1455     }
1456
1457   /* Check status. */
1458   if (vty->status == VTY_CLOSE)
1459     vty_close (vty);
1460   else
1461     {
1462       vty_event (VTY_WRITE, vty_sock, vty);
1463       vty_event (VTY_READ, vty_sock, vty);
1464     }
1465   return 0;
1466 }
1467
1468 /* Flush buffer to the vty. */
1469 static int
1470 vty_flush (struct thread *thread)
1471 {
1472   int erase;
1473   int dont_more;
1474   int vty_sock = THREAD_FD (thread);
1475   struct vty *vty = THREAD_ARG (thread);
1476   vty->t_write = NULL;
1477
1478   /* Tempolary disable read thread. */
1479   if (vty->lines == 0)
1480     if (vty->t_read)
1481       {
1482         thread_cancel (vty->t_read);
1483         vty->t_read = NULL;
1484       }
1485
1486   /* Function execution continue. */
1487   if (vty->status == VTY_START || vty->status == VTY_CONTINUE)
1488     {
1489       if (vty->status == VTY_CONTINUE)
1490         erase = 1;
1491       else
1492         erase = 0;
1493
1494       if (vty->output_func == NULL)
1495         dont_more = 1;
1496       else
1497         dont_more = 0;
1498
1499       if (vty->lines == 0)
1500         {
1501           erase = 0;
1502           dont_more = 1;
1503         }
1504
1505       buffer_flush_vty_all (vty->obuf, vty->fd, erase, dont_more);
1506
1507       if (vty->status == VTY_CLOSE)
1508         {
1509           vty_close (vty);
1510           return 0;
1511         }
1512
1513       if (vty->output_func == NULL)
1514         {
1515           vty->status = VTY_NORMAL;
1516           vty_prompt (vty);
1517           vty_event (VTY_WRITE, vty_sock, vty);
1518         }
1519       else
1520         vty->status = VTY_MORE;
1521
1522       if (vty->lines == 0)
1523         {
1524           if (vty->output_func == NULL)
1525             vty_event (VTY_READ, vty_sock, vty);
1526           else
1527             {
1528               if (vty->output_func)
1529                 (*vty->output_func) (vty, 0);
1530               vty_event (VTY_WRITE, vty_sock, vty);
1531             }
1532         }
1533     }
1534   else
1535     {
1536       if (vty->status == VTY_MORE)
1537         erase = 1;
1538       else
1539         erase = 0;
1540
1541       if (vty->lines == 0)
1542         buffer_flush_window (vty->obuf, vty->fd, vty->width, 25, 0, 1);
1543       else
1544         buffer_flush_window (vty->obuf, vty->fd, vty->width,
1545                              vty->lines >= 0 ? vty->lines : vty->height,
1546                              erase, 0);
1547   
1548       if (buffer_empty (vty->obuf))
1549         {
1550           if (vty->status == VTY_CLOSE)
1551             vty_close (vty);
1552           else
1553             {
1554               vty->status = VTY_NORMAL;
1555           
1556               if (vty->lines == 0)
1557                 vty_event (VTY_READ, vty_sock, vty);
1558             }
1559         }
1560       else
1561         {
1562           vty->status = VTY_MORE;
1563
1564           if (vty->lines == 0)
1565             vty_event (VTY_WRITE, vty_sock, vty);
1566         }
1567     }
1568
1569   return 0;
1570 }
1571
1572 /* Create new vty structure. */
1573 struct vty *
1574 vty_create (int vty_sock, union sockunion *su)
1575 {
1576   struct vty *vty;
1577
1578   /* Allocate new vty structure and set up default values. */
1579   vty = vty_new ();
1580   vty->fd = vty_sock;
1581   vty->type = VTY_TERM;
1582   vty->address = sockunion_su2str (su);
1583   if (no_password_check)
1584     {
1585       if (host.advanced)
1586         vty->node = ENABLE_NODE;
1587       else
1588         vty->node = VIEW_NODE;
1589     }
1590   else
1591     vty->node = AUTH_NODE;
1592   vty->fail = 0;
1593   vty->cp = 0;
1594   vty_clear_buf (vty);
1595   vty->length = 0;
1596   memset (vty->hist, 0, sizeof (vty->hist));
1597   vty->hp = 0;
1598   vty->hindex = 0;
1599   vector_set_index (vtyvec, vty_sock, vty);
1600   vty->status = VTY_NORMAL;
1601   vty->v_timeout = vty_timeout_val;
1602   if (host.lines >= 0)
1603     vty->lines = host.lines;
1604   else
1605     vty->lines = -1;
1606   vty->iac = 0;
1607   vty->iac_sb_in_progress = 0;
1608   vty->sb_buffer = buffer_new (1024);
1609
1610   if (! no_password_check)
1611     {
1612       /* Vty is not available if password isn't set. */
1613       if (host.password == NULL && host.password_encrypt == NULL)
1614         {
1615           vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
1616           vty->status = VTY_CLOSE;
1617           vty_close (vty);
1618           return NULL;
1619         }
1620     }
1621
1622   /* Say hello to the world. */
1623   vty_hello (vty);
1624   if (! no_password_check)
1625     vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
1626
1627   /* Setting up terminal. */
1628   vty_will_echo (vty);
1629   vty_will_suppress_go_ahead (vty);
1630
1631   vty_dont_linemode (vty);
1632   vty_do_window_size (vty);
1633   /* vty_dont_lflow_ahead (vty); */
1634
1635   vty_prompt (vty);
1636
1637   /* Add read/write thread. */
1638   vty_event (VTY_WRITE, vty_sock, vty);
1639   vty_event (VTY_READ, vty_sock, vty);
1640
1641   return vty;
1642 }
1643
1644 /* Accept connection from the network. */
1645 static int
1646 vty_accept (struct thread *thread)
1647 {
1648   int vty_sock;
1649   struct vty *vty;
1650   union sockunion su;
1651   int ret;
1652   unsigned int on;
1653   int accept_sock;
1654   struct prefix *p = NULL;
1655   struct access_list *acl = NULL;
1656
1657   accept_sock = THREAD_FD (thread);
1658
1659   /* We continue hearing vty socket. */
1660   vty_event (VTY_SERV, accept_sock, NULL);
1661
1662   memset (&su, 0, sizeof (union sockunion));
1663
1664   /* We can handle IPv4 or IPv6 socket. */
1665   vty_sock = sockunion_accept (accept_sock, &su);
1666   if (vty_sock < 0)
1667     {
1668 #ifdef BRCM_RIP_DEBUG
1669       zlog_warn ("can't accept vty socket : %s", strerror (errno));
1670 #endif
1671       return -1;
1672     }
1673
1674 #ifdef BRCM_LIST_SUPPORT
1675   p = sockunion2hostprefix (&su);
1676
1677   /* VTY's accesslist apply. */
1678   if (p->family == AF_INET && vty_accesslist_name)
1679     {
1680       if ((acl = access_list_lookup (AFI_IP, vty_accesslist_name)) &&
1681           (access_list_apply (acl, p) == FILTER_DENY))
1682         {
1683           char *buf;
1684 #ifdef BRCM_RIP_DEBUG
1685           zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1686                 (buf = sockunion_su2str (&su)));
1687 #endif
1688           free (buf);
1689           close (vty_sock);
1690           
1691           /* continue accepting connections */
1692           vty_event (VTY_SERV, accept_sock, NULL);
1693           
1694           prefix_free (p);
1695
1696           return 0;
1697         }
1698     }
1699 #endif /* BRCM_LIST_SUPPORT */
1700
1701 #ifdef HAVE_IPV6
1702   /* VTY's ipv6 accesslist apply. */
1703   if (p->family == AF_INET6 && vty_ipv6_accesslist_name)
1704     {
1705       if ((acl = access_list_lookup (AFI_IP6, vty_ipv6_accesslist_name)) &&
1706           (access_list_apply (acl, p) == FILTER_DENY))
1707         {
1708           char *buf;
1709 #ifdef BRCM_RIP_DEBUG
1710           zlog (NULL, LOG_INFO, "Vty connection refused from %s",
1711                 (buf = sockunion_su2str (&su)));
1712 #endif
1713           free (buf);
1714           close (vty_sock);
1715           
1716           /* continue accepting connections */
1717           vty_event (VTY_SERV, accept_sock, NULL);
1718           
1719           prefix_free (p);
1720
1721           return 0;
1722         }
1723     }
1724 #endif /* HAVE_IPV6 */
1725   
1726   prefix_free (p);
1727
1728   on = 1;
1729   ret = setsockopt (vty_sock, IPPROTO_TCP, TCP_NODELAY, 
1730                     (char *) &on, sizeof (on));
1731   if (ret < 0)
1732 #ifdef BRCM_RIP_DEBUG
1733     zlog (NULL, LOG_INFO, "can't set sockopt to vty_sock : %s", 
1734           strerror (errno));
1735 #endif
1736   vty = vty_create (vty_sock, &su);
1737
1738   return 0;
1739 }
1740
1741 #if defined(HAVE_IPV6) && !defined(NRL)
1742 void
1743 vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
1744 {
1745   int ret;
1746   struct addrinfo req;
1747   struct addrinfo *ainfo;
1748   struct addrinfo *ainfo_save;
1749   int sock;
1750   char port_str[BUFSIZ];
1751
1752   memset (&req, 0, sizeof (struct addrinfo));
1753   req.ai_flags = AI_PASSIVE;
1754   req.ai_family = AF_UNSPEC;
1755   req.ai_socktype = SOCK_STREAM;
1756   sprintf (port_str, "%d", port);
1757   port_str[sizeof (port_str) - 1] = '\0';
1758
1759   ret = getaddrinfo (hostname, port_str, &req, &ainfo);
1760
1761   if (ret != 0)
1762     {
1763       fprintf (stderr, "getaddrinfo failed: %s\n", gai_strerror (ret));
1764       exit (1);
1765     }
1766
1767   ainfo_save = ainfo;
1768
1769   do
1770     {
1771       if (ainfo->ai_family != AF_INET
1772 #ifdef HAVE_IPV6
1773           && ainfo->ai_family != AF_INET6
1774 #endif /* HAVE_IPV6 */
1775           )
1776         continue;
1777
1778       sock = socket (ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
1779       if (sock < 0)
1780         continue;
1781
1782       sockopt_reuseaddr (sock);
1783       sockopt_reuseport (sock);
1784
1785       ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
1786       if (ret < 0)
1787         {
1788           close (sock); /* Avoid sd leak. */
1789         continue;
1790         }
1791
1792       ret = listen (sock, 3);
1793       if (ret < 0) 
1794         {
1795           close (sock); /* Avoid sd leak. */
1796         continue;
1797         }
1798
1799       vty_event (VTY_SERV, sock, NULL);
1800     }
1801   while ((ainfo = ainfo->ai_next) != NULL);
1802
1803   freeaddrinfo (ainfo_save);
1804 }
1805 #endif /* HAVE_IPV6 && ! NRL */
1806
1807 /* Make vty server socket. */
1808 void
1809 vty_serv_sock_family (unsigned short port, int family)
1810 {
1811   int ret;
1812   union sockunion su;
1813   int accept_sock;
1814
1815   memset (&su, 0, sizeof (union sockunion));
1816   su.sa.sa_family = family;
1817
1818   /* Make new socket. */
1819   accept_sock = sockunion_stream_socket (&su);
1820   if (accept_sock < 0)
1821     return;
1822
1823   /* This is server, so reuse address. */
1824   sockopt_reuseaddr (accept_sock);
1825   sockopt_reuseport (accept_sock);
1826
1827   /* Bind socket to universal address and given port. */
1828   ret = sockunion_bind (accept_sock, &su, port, NULL);
1829   if (ret < 0)
1830     {
1831       close (accept_sock);      /* Avoid sd leak. */
1832       return;
1833     }
1834
1835   /* Listen socket under queue 3. */
1836   ret = listen (accept_sock, 3);
1837   if (ret < 0) 
1838     {
1839 #ifdef BRCM_RIP_DEBUG
1840       zlog (NULL, LOG_WARNING, "can't listen socket");
1841 #endif
1842       close (accept_sock);      /* Avoid sd leak. */
1843       return;
1844     }
1845
1846   /* Add vty server event. */
1847   vty_event (VTY_SERV, accept_sock, NULL);
1848 }
1849
1850 #ifdef VTYSH
1851 /* For sockaddr_un. */
1852 #include <sys/un.h>
1853
1854 /* VTY shell UNIX domain socket. */
1855 void
1856 vty_serv_un (char *path)
1857 {
1858   int ret;
1859   int sock, len;
1860   struct sockaddr_un serv;
1861   mode_t old_mask;
1862
1863   /* First of all, unlink existing socket */
1864   unlink (path);
1865
1866   /* Set umask */
1867   old_mask = umask (0077);
1868
1869   /* Make UNIX domain socket. */
1870   sock = socket (AF_UNIX, SOCK_STREAM, 0);
1871   if (sock < 0)
1872     {
1873       perror ("sock");
1874       return;
1875     }
1876
1877   /* Make server socket. */
1878   memset (&serv, 0, sizeof (struct sockaddr_un));
1879   serv.sun_family = AF_UNIX;
1880   strncpy (serv.sun_path, path, strlen (path));
1881 #ifdef HAVE_SUN_LEN
1882   len = serv.sun_len = SUN_LEN(&serv);
1883 #else
1884   len = sizeof (serv.sun_family) + strlen (serv.sun_path);
1885 #endif /* HAVE_SUN_LEN */
1886
1887   ret = bind (sock, (struct sockaddr *) &serv, len);
1888   if (ret < 0)
1889     {
1890       perror ("bind");
1891       close (sock);     /* Avoid sd leak. */
1892       return;
1893     }
1894
1895   ret = listen (sock, 5);
1896   if (ret < 0)
1897     {
1898       perror ("listen");
1899       close (sock);     /* Avoid sd leak. */
1900       return;
1901     }
1902
1903   umask (old_mask);
1904
1905   vty_event (VTYSH_SERV, sock, NULL);
1906 }
1907
1908 /* #define VTYSH_DEBUG 1 */
1909
1910 static int
1911 vtysh_accept (struct thread *thread)
1912 {
1913   int accept_sock;
1914   int sock;
1915   int client_len;
1916   struct sockaddr_un client;
1917   struct vty *vty;
1918   
1919   accept_sock = THREAD_FD (thread);
1920
1921   vty_event (VTYSH_SERV, accept_sock, NULL);
1922
1923   memset (&client, 0, sizeof (struct sockaddr_un));
1924   client_len = sizeof (struct sockaddr_un);
1925
1926   sock = accept (accept_sock, (struct sockaddr *) &client, &client_len);
1927
1928   if (sock < 0)
1929     {
1930 #ifdef BRCM_RIP_DEBUG
1931       zlog_warn ("can't accept vty socket : %s", strerror (errno));
1932 #endif
1933       return -1;
1934     }
1935
1936 #ifdef VTYSH_DEBUG
1937   printf ("VTY shell accept\n");
1938 #endif /* VTYSH_DEBUG */
1939
1940   vty = vty_new ();
1941   vty->fd = sock;
1942   vty->type = VTY_SHELL_SERV;
1943   vty->node = VIEW_NODE;
1944
1945   vty_event (VTYSH_READ, sock, vty);
1946
1947   return 0;
1948 }
1949
1950 static int
1951 vtysh_read (struct thread *thread)
1952 {
1953   int ret;
1954   int sock;
1955   int nbytes;
1956   struct vty *vty;
1957   unsigned char buf[VTY_READ_BUFSIZ];
1958   u_char header[4] = {0, 0, 0, 0};
1959
1960   sock = THREAD_FD (thread);
1961   vty = THREAD_ARG (thread);
1962   vty->t_read = NULL;
1963
1964   nbytes = read (sock, buf, VTY_READ_BUFSIZ);
1965   if (nbytes <= 0)
1966     {
1967       vty_close (vty);
1968 #ifdef VTYSH_DEBUG
1969       printf ("close vtysh\n");
1970 #endif /* VTYSH_DEBUG */
1971       return 0;
1972     }
1973
1974 #ifdef VTYSH_DEBUG
1975   printf ("line: %s\n", buf);
1976 #endif /* VTYSH_DEBUG */
1977
1978   vty_ensure (vty, nbytes);
1979   memcpy (vty->buf, buf, nbytes);
1980   
1981   /* Pass this line to parser. */
1982   ret = vty_execute (vty);
1983
1984   vty_clear_buf (vty);
1985
1986   /* Return result. */
1987 #ifdef VTYSH_DEBUG
1988   printf ("result: %d\n", ret);
1989   printf ("vtysh node: %d\n", vty->node);
1990 #endif /* VTYSH_DEBUG */
1991
1992   header[3] = ret;
1993   write (vty->fd, header, 4);
1994
1995   vty_event (VTYSH_READ, sock, vty);
1996
1997   return 0;
1998 }
1999 #endif /* VTYSH */
2000
2001 /* Determine address family to bind. */
2002 void
2003 vty_serv_sock (const char *hostname, unsigned short port, char *path)
2004 {
2005   /* If port is set to 0, do not listen on TCP/IP at all! */
2006   if (port)
2007     {
2008
2009 #ifdef HAVE_IPV6
2010 #ifdef NRL
2011       vty_serv_sock_family (port, AF_INET);
2012       vty_serv_sock_family (port, AF_INET6);
2013 #else /* ! NRL */
2014       vty_serv_sock_addrinfo (hostname, port);
2015 #endif /* NRL*/
2016 #else /* ! HAVE_IPV6 */
2017       vty_serv_sock_family (port, AF_INET);
2018 #endif /* HAVE_IPV6 */
2019     }
2020
2021 #ifdef VTYSH
2022   vty_serv_un (path);
2023 #endif /* VTYSH */
2024 }
2025 #endif /* BRCM_CMD_SUPPORT */
2026
2027 /* Close vty interface. */
2028 void
2029 vty_close (struct vty *vty)
2030 {
2031   int i;
2032
2033 #if defined(BRCM_CMD_SUPPORT)
2034   /* Cancel threads.*/
2035   if (vty->t_read)
2036     thread_cancel (vty->t_read);
2037   if (vty->t_write)
2038     thread_cancel (vty->t_write);
2039   if (vty->t_timeout)
2040     thread_cancel (vty->t_timeout);
2041   if (vty->t_output)
2042     thread_cancel (vty->t_output);
2043
2044   /* Flush buffer. */
2045   if (! buffer_empty (vty->obuf))
2046     buffer_flush_all (vty->obuf, vty->fd);
2047
2048   /* Free input buffer. */
2049   buffer_free (vty->obuf);
2050
2051   /* Free SB buffer. */
2052   if (vty->sb_buffer)
2053     buffer_free (vty->sb_buffer);
2054 #endif /* BRCM_CMD_SUPPORT */
2055
2056   /* Free command history. */
2057   for (i = 0; i < VTY_MAXHIST; i++)
2058     if (vty->hist[i])
2059       XFREE (MTYPE_VTY_HIST, vty->hist[i]);
2060
2061   /* Unset vector. */
2062   vector_unset (vtyvec, vty->fd);
2063
2064   /* Close socket. */
2065   if (vty->fd > 0)
2066     close (vty->fd);
2067
2068   if (vty->address)
2069     XFREE (0, vty->address);
2070   if (vty->buf)
2071     XFREE (MTYPE_VTY, vty->buf);
2072
2073   /* Check configure. */
2074   vty_config_unlock (vty);
2075
2076   /* OK free vty. */
2077   XFREE (MTYPE_VTY, vty);
2078 }
2079
2080 #if defined(BRCM_CMD_SUPPORT)
2081 /* When time out occur output message then close connection. */
2082 static int
2083 vty_timeout (struct thread *thread)
2084 {
2085   struct vty *vty;
2086
2087   vty = THREAD_ARG (thread);
2088   vty->t_timeout = NULL;
2089   vty->v_timeout = 0;
2090
2091   /* Clear buffer*/
2092   buffer_reset (vty->obuf);
2093   vty_out (vty, "%sVty connection is timed out.%s", VTY_NEWLINE, VTY_NEWLINE);
2094
2095   /* Close connection. */
2096   vty->status = VTY_CLOSE;
2097   vty_close (vty);
2098
2099   return 0;
2100 }
2101 #endif /* BRCM_CMD_SUPPORT */
2102
2103
2104 /* Read up configuration file from file_name. */
2105 static void
2106 vty_read_file (FILE *confp)
2107 {
2108   int ret;
2109   struct vty *vty;
2110
2111   vty = vty_new ();
2112   vty->fd = 0;                  /* stdout */
2113   vty->type = VTY_TERM;
2114   vty->node = CONFIG_NODE;
2115   
2116   /* Execute configuration file */
2117   ret = config_from_file (vty, confp);
2118
2119   if (ret != CMD_SUCCESS) 
2120     {
2121       switch (ret)
2122         {
2123         case CMD_ERR_AMBIGUOUS:
2124           fprintf (stderr, "Ambiguous command.\n");
2125           break;
2126         case CMD_ERR_NO_MATCH:
2127           fprintf (stderr, "There is no such command.\n");
2128           break;
2129         }
2130       fprintf (stderr, "Error occured during reading below line.\n%s\n", 
2131                vty->buf);
2132       vty_close (vty);
2133       exit (1);
2134     }
2135
2136   vty_close (vty);
2137 }
2138
2139 #if defined(BRCM_CMD_SUPPORT)
2140 FILE *
2141 vty_use_backup_config (char *fullpath)
2142 {
2143   char *fullpath_sav, *fullpath_tmp;
2144   FILE *ret = NULL;
2145   struct stat buf;
2146   int tmp, sav;
2147   int c;
2148   char buffer[512];
2149   
2150   fullpath_sav = malloc (strlen (fullpath) + strlen (CONF_BACKUP_EXT) + 1);
2151   strcpy (fullpath_sav, fullpath);
2152   strcat (fullpath_sav, CONF_BACKUP_EXT);
2153   if (stat (fullpath_sav, &buf) == -1)
2154     {
2155       free (fullpath_sav);
2156       return NULL;
2157     }
2158
2159   fullpath_tmp = malloc (strlen (fullpath) + 8);
2160   sprintf (fullpath_tmp, "%s.XXXXXX", fullpath);
2161   
2162   /* Open file to configuration write. */
2163   tmp = mkstemp (fullpath_tmp);
2164   if (tmp < 0)
2165     {
2166       free (fullpath_sav);
2167       free (fullpath_tmp);
2168       return NULL;
2169     }
2170
2171   sav = open (fullpath_sav, O_RDONLY);
2172   if (sav < 0)
2173     {
2174       free (fullpath_sav);
2175       free (fullpath_tmp);
2176       unlink (fullpath_tmp);
2177       return NULL;
2178     }
2179   
2180   while((c = read (sav, buffer, 512)) > 0)
2181     write (tmp, buffer, c);
2182   
2183   close (sav);
2184   close (tmp);
2185   
2186   if (link (fullpath_tmp, fullpath) == 0)
2187     ret = fopen (fullpath, "r");
2188
2189   unlink (fullpath_tmp);
2190   
2191   free (fullpath_sav);
2192   free (fullpath_tmp);
2193   return fopen (fullpath, "r");
2194 }
2195 #endif /* BRCM_CMD_SUPPORT */
2196
2197 /* Read up configuration file from file_name. */
2198 void
2199 vty_read_config (char *config_file,
2200                  char *config_current_dir,
2201                  char *config_default_dir)
2202 {
2203   char *cwd;
2204   FILE *confp = NULL;
2205   char *fullpath;
2206
2207   /* If -f flag specified. */
2208   if (config_file != NULL)
2209     {
2210       if (! IS_DIRECTORY_SEP (config_file[0]))
2211         {
2212           cwd = getcwd (NULL, MAXPATHLEN);
2213           fullpath = XMALLOC (MTYPE_TMP, 
2214                               strlen (cwd) + strlen (config_file) + 2);
2215           sprintf (fullpath, "%s/%s", cwd, config_file);
2216         }
2217       else
2218         fullpath = config_file;
2219
2220       confp = fopen (fullpath, "r");
2221
2222       if (confp == NULL)
2223         {
2224 #if defined(BRCM_CMD_SUPPORT)
2225           confp = vty_use_backup_config (fullpath);
2226           if (confp)
2227             fprintf (stderr, "WARNING: using backup configuration file!\n");
2228           else
2229             {
2230               fprintf (stderr, "can't open configuration file [%s]\n", 
2231                        config_file);
2232 #endif /* BRCM_CMD_SUPPORT */
2233               exit(1);
2234 #if defined(BRCM_CMD_SUPPORT)
2235             }
2236 #endif
2237         }
2238     }
2239   else
2240     {
2241       /* Relative path configuration file open. */
2242       if (config_current_dir)
2243         {
2244           confp = fopen (config_current_dir, "r");
2245 #if defined(BRCM_CMD_SUPPORT)
2246           if (confp == NULL)
2247             {
2248               confp = vty_use_backup_config (config_current_dir);
2249               if (confp)
2250                 fprintf (stderr, "WARNING: using backup configuration file!\n");
2251             }
2252 #endif /* BRCM_CMD_SUPPORT */
2253         }
2254
2255       /* If there is no relative path exists, open system default file. */
2256       if (confp == NULL)
2257         {
2258 #ifdef VTYSH
2259           int ret;
2260           struct stat conf_stat;
2261
2262           /* !!!!PLEASE LEAVE!!!!
2263              This is NEEDED for use with vtysh -b, or else you can get
2264              a real configuration food fight with a lot garbage in the
2265              merged configuration file it creates coming from the per
2266              daemon configuration files.  This also allows the daemons
2267              to start if there default configuration file is not
2268              present or ignore them, as needed when using vtysh -b to
2269              configure the daemons at boot - MAG */
2270
2271           /* Stat for vtysh Zebra.conf, if found startup and wait for
2272              boot configuration */
2273
2274           if ( strstr(config_default_dir, "vtysh") == NULL)
2275             {
2276               ret = stat (integrate_default, &conf_stat);
2277               if (ret >= 0)
2278                 {
2279                   return;
2280                 }
2281             }
2282 #endif /* VTYSH */
2283
2284 #if defined(BRCM_CMD_SUPPORT)
2285           confp = fopen (config_default_dir, "r");
2286           if (confp == NULL)
2287             {
2288               confp = vty_use_backup_config (config_default_dir);
2289               if (confp)
2290                 {
2291                   fprintf (stderr, "WARNING: using backup configuration file!\n");
2292                   fullpath = config_default_dir;
2293                 }
2294               else
2295                 {
2296                   fprintf (stderr, "can't open configuration file [%s]\n",
2297                            config_default_dir);
2298                   exit (1);
2299                 }
2300             }      
2301           else
2302             fullpath = config_default_dir;
2303 #endif /* BRCM_CMD_SUPPORT */
2304         }
2305       else
2306         {
2307           /* Rleative path configuration file. */
2308           cwd = getcwd (NULL, MAXPATHLEN);
2309           fullpath = XMALLOC (MTYPE_TMP, 
2310                               strlen (cwd) + strlen (config_current_dir) + 2);
2311           sprintf (fullpath, "%s/%s", cwd, config_current_dir);
2312         }  
2313     }  
2314   vty_read_file (confp);
2315
2316   fclose (confp);
2317
2318   host_config_set (fullpath);
2319 }
2320
2321 #if defined(BRCM_CMD_SUPPORT) || defined(BRCM_RIP_DEBUG)
2322 /* Small utility function which output loggin to the VTY. */
2323 void
2324 vty_log (const char *proto_str, const char *format, va_list va)
2325 {
2326   int i;
2327   struct vty *vty;
2328
2329   for (i = 0; i < vector_max (vtyvec); i++)
2330     if ((vty = vector_slot (vtyvec, i)) != NULL)
2331       if (vty->monitor)
2332         {
2333           vty_time_print (vty, 0);
2334           vty_out (vty, "%s: ", proto_str);
2335           vvty_out (vty, format, va);
2336           vty_out (vty, "\r\n");
2337         }
2338 }
2339 #endif /* BRCM_CMD_SUPPORT */
2340
2341 int
2342 vty_config_lock (struct vty *vty)
2343 {
2344   if (vty_config == 0)
2345     {
2346       vty->config = 1;
2347       vty_config = 1;
2348     }
2349   return vty->config;
2350 }
2351
2352 int
2353 vty_config_unlock (struct vty *vty)
2354 {
2355   if (vty_config == 1 && vty->config == 1)
2356     {
2357       vty->config = 0;
2358       vty_config = 0;
2359     }
2360   return vty->config;
2361 }
2362 \f
2363 /* Master of the threads. */
2364 extern struct thread_master *master;
2365 /* struct thread_master *master; */
2366
2367 #if defined(BRCM_CMD_SUPPORT)
2368 static void
2369 vty_event (enum event event, int sock, struct vty *vty)
2370 {
2371   struct thread *vty_serv_thread;
2372
2373   switch (event)
2374     {
2375     case VTY_SERV:
2376       vty_serv_thread = thread_add_read (master, vty_accept, vty, sock);
2377       vector_set_index (Vvty_serv_thread, sock, vty_serv_thread);
2378       break;
2379 #ifdef VTYSH
2380     case VTYSH_SERV:
2381       thread_add_read (master, vtysh_accept, vty, sock);
2382       break;
2383     case VTYSH_READ:
2384       thread_add_read (master, vtysh_read, vty, sock);
2385       break;
2386 #endif /* VTYSH */
2387     case VTY_READ:
2388       vty->t_read = thread_add_read (master, vty_read, vty, sock);
2389
2390       /* Time out treatment. */
2391       if (vty->v_timeout)
2392         {
2393           if (vty->t_timeout)
2394             thread_cancel (vty->t_timeout);
2395           vty->t_timeout = 
2396             thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2397         }
2398       break;
2399     case VTY_WRITE:
2400       if (! vty->t_write)
2401         vty->t_write = thread_add_write (master, vty_flush, vty, sock);
2402       break;
2403     case VTY_TIMEOUT_RESET:
2404       if (vty->t_timeout)
2405         {
2406           thread_cancel (vty->t_timeout);
2407           vty->t_timeout = NULL;
2408         }
2409       if (vty->v_timeout)
2410         {
2411           vty->t_timeout = 
2412             thread_add_timer (master, vty_timeout, vty, vty->v_timeout);
2413         }
2414       break;
2415     }
2416 }
2417 \f
2418 DEFUN (config_who,
2419        config_who_cmd,
2420        "who",
2421        "Display who is on vty\n")
2422 {
2423   int i;
2424   struct vty *v;
2425
2426   for (i = 0; i < vector_max (vtyvec); i++)
2427     if ((v = vector_slot (vtyvec, i)) != NULL)
2428       vty_out (vty, "%svty[%d] connected from %s.%s",
2429                v->config ? "*" : " ",
2430                i, v->address, VTY_NEWLINE);
2431   return CMD_SUCCESS;
2432 }
2433
2434 /* Move to vty configuration mode. */
2435 DEFUN (line_vty,
2436        line_vty_cmd,
2437        "line vty",
2438        "Configure a terminal line\n"
2439        "Virtual terminal\n")
2440 {
2441   vty->node = VTY_NODE;
2442   return CMD_SUCCESS;
2443 }
2444
2445 /* Set time out value. */
2446 int
2447 exec_timeout (struct vty *vty, char *min_str, char *sec_str)
2448 {
2449   unsigned long timeout = 0;
2450
2451   /* min_str and sec_str are already checked by parser.  So it must be
2452      all digit string. */
2453   if (min_str)
2454     {
2455       timeout = strtol (min_str, NULL, 10);
2456       timeout *= 60;
2457     }
2458   if (sec_str)
2459     timeout += strtol (sec_str, NULL, 10);
2460
2461   vty_timeout_val = timeout;
2462   vty->v_timeout = timeout;
2463   vty_event (VTY_TIMEOUT_RESET, 0, vty);
2464
2465
2466   return CMD_SUCCESS;
2467 }
2468
2469 DEFUN (exec_timeout_min,
2470        exec_timeout_min_cmd,
2471        "exec-timeout <0-35791>",
2472        "Set timeout value\n"
2473        "Timeout value in minutes\n")
2474 {
2475   return exec_timeout (vty, argv[0], NULL);
2476 }
2477
2478 DEFUN (exec_timeout_sec,
2479        exec_timeout_sec_cmd,
2480        "exec-timeout <0-35791> <0-2147483>",
2481        "Set the EXEC timeout\n"
2482        "Timeout in minutes\n"
2483        "Timeout in seconds\n")
2484 {
2485   return exec_timeout (vty, argv[0], argv[1]);
2486 }
2487
2488 DEFUN (no_exec_timeout,
2489        no_exec_timeout_cmd,
2490        "no exec-timeout",
2491        NO_STR
2492        "Set the EXEC timeout\n")
2493 {
2494   return exec_timeout (vty, NULL, NULL);
2495 }
2496
2497 /* Set vty access class. */
2498 DEFUN (vty_access_class,
2499        vty_access_class_cmd,
2500        "access-class WORD",
2501        "Filter connections based on an IP access list\n"
2502        "IP access list\n")
2503 {
2504   if (vty_accesslist_name)
2505     XFREE(MTYPE_VTY, vty_accesslist_name);
2506
2507   vty_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2508
2509   return CMD_SUCCESS;
2510 }
2511
2512 /* Clear vty access class. */
2513 DEFUN (no_vty_access_class,
2514        no_vty_access_class_cmd,
2515        "no access-class [WORD]",
2516        NO_STR
2517        "Filter connections based on an IP access list\n"
2518        "IP access list\n")
2519 {
2520   if (! vty_accesslist_name || (argc && strcmp(vty_accesslist_name, argv[0])))
2521     {
2522       vty_out (vty, "Access-class is not currently applied to vty%s",
2523                VTY_NEWLINE);
2524       return CMD_WARNING;
2525     }
2526
2527   XFREE(MTYPE_VTY, vty_accesslist_name);
2528
2529   vty_accesslist_name = NULL;
2530
2531   return CMD_SUCCESS;
2532 }
2533
2534 #ifdef HAVE_IPV6
2535 /* Set vty access class. */
2536 DEFUN (vty_ipv6_access_class,
2537        vty_ipv6_access_class_cmd,
2538        "ipv6 access-class WORD",
2539        IPV6_STR
2540        "Filter connections based on an IP access list\n"
2541        "IPv6 access list\n")
2542 {
2543   if (vty_ipv6_accesslist_name)
2544     XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2545
2546   vty_ipv6_accesslist_name = XSTRDUP(MTYPE_VTY, argv[0]);
2547
2548   return CMD_SUCCESS;
2549 }
2550
2551 /* Clear vty access class. */
2552 DEFUN (no_vty_ipv6_access_class,
2553        no_vty_ipv6_access_class_cmd,
2554        "no ipv6 access-class [WORD]",
2555        NO_STR
2556        IPV6_STR
2557        "Filter connections based on an IP access list\n"
2558        "IPv6 access list\n")
2559 {
2560   if (! vty_ipv6_accesslist_name ||
2561       (argc && strcmp(vty_ipv6_accesslist_name, argv[0])))
2562     {
2563       vty_out (vty, "IPv6 access-class is not currently applied to vty%s",
2564                VTY_NEWLINE);
2565       return CMD_WARNING;
2566     }
2567
2568   XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2569
2570   vty_ipv6_accesslist_name = NULL;
2571
2572   return CMD_SUCCESS;
2573 }
2574 #endif /* HAVE_IPV6 */
2575
2576 /* vty login. */
2577 DEFUN (vty_login,
2578        vty_login_cmd,
2579        "login",
2580        "Enable password checking\n")
2581 {
2582   no_password_check = 0;
2583   return CMD_SUCCESS;
2584 }
2585
2586 DEFUN (no_vty_login,
2587        no_vty_login_cmd,
2588        "no login",
2589        NO_STR
2590        "Enable password checking\n")
2591 {
2592   no_password_check = 1;
2593   return CMD_SUCCESS;
2594 }
2595
2596 DEFUN (service_advanced_vty,
2597        service_advanced_vty_cmd,
2598        "service advanced-vty",
2599        "Set up miscellaneous service\n"
2600        "Enable advanced mode vty interface\n")
2601 {
2602   host.advanced = 1;
2603   return CMD_SUCCESS;
2604 }
2605
2606 DEFUN (no_service_advanced_vty,
2607        no_service_advanced_vty_cmd,
2608        "no service advanced-vty",
2609        NO_STR
2610        "Set up miscellaneous service\n"
2611        "Enable advanced mode vty interface\n")
2612 {
2613   host.advanced = 0;
2614   return CMD_SUCCESS;
2615 }
2616
2617 DEFUN (terminal_monitor,
2618        terminal_monitor_cmd,
2619        "terminal monitor",
2620        "Set terminal line parameters\n"
2621        "Copy debug output to the current terminal line\n")
2622 {
2623   vty->monitor = 1;
2624   return CMD_SUCCESS;
2625 }
2626
2627 DEFUN (terminal_no_monitor,
2628        terminal_no_monitor_cmd,
2629        "terminal no monitor",
2630        "Set terminal line parameters\n"
2631        NO_STR
2632        "Copy debug output to the current terminal line\n")
2633 {
2634   vty->monitor = 0;
2635   return CMD_SUCCESS;
2636 }
2637
2638 DEFUN (show_history,
2639        show_history_cmd,
2640        "show history",
2641        SHOW_STR
2642        "Display the session command history\n")
2643 {
2644   int index;
2645
2646   for (index = vty->hindex + 1; index != vty->hindex;)
2647     {
2648       if (index == VTY_MAXHIST)
2649         {
2650           index = 0;
2651           continue;
2652         }
2653
2654       if (vty->hist[index] != NULL)
2655         vty_out (vty, "  %s%s", vty->hist[index], VTY_NEWLINE);
2656
2657       index++;
2658     }
2659
2660   return CMD_SUCCESS;
2661 }
2662
2663 /* Display current configuration. */
2664 int
2665 vty_config_write (struct vty *vty)
2666 {
2667   vty_out (vty, "line vty%s", VTY_NEWLINE);
2668
2669   if (vty_accesslist_name)
2670     vty_out (vty, " access-class %s%s",
2671              vty_accesslist_name, VTY_NEWLINE);
2672
2673 #ifdef HAVE_IPV6
2674   if (vty_ipv6_accesslist_name)
2675     vty_out (vty, " ipv6 access-class %s%s",
2676              vty_ipv6_accesslist_name, VTY_NEWLINE);
2677 #endif
2678
2679   /* exec-timeout */
2680   if (vty_timeout_val != VTY_TIMEOUT_DEFAULT)
2681     vty_out (vty, " exec-timeout %ld %ld%s", 
2682              vty_timeout_val / 60,
2683              vty_timeout_val % 60, VTY_NEWLINE);
2684
2685   /* login */
2686   if (no_password_check)
2687     vty_out (vty, " no login%s", VTY_NEWLINE);
2688
2689   vty_out (vty, "!%s", VTY_NEWLINE);
2690
2691   return CMD_SUCCESS;
2692 }
2693
2694 struct cmd_node vty_node =
2695 {
2696   VTY_NODE,
2697   "%s(config-line)# ",
2698 };
2699
2700 /* Reset all VTY status. */
2701 void
2702 vty_reset ()
2703 {
2704   int i;
2705   struct vty *vty;
2706   struct thread *vty_serv_thread;
2707
2708   for (i = 0; i < vector_max (vtyvec); i++)
2709     if ((vty = vector_slot (vtyvec, i)) != NULL)
2710       {
2711         buffer_reset (vty->obuf);
2712         vty->status = VTY_CLOSE;
2713         vty_close (vty);
2714       }
2715
2716   for (i = 0; i < vector_max (Vvty_serv_thread); i++)
2717     if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
2718       {
2719         thread_cancel (vty_serv_thread);
2720         vector_slot (Vvty_serv_thread, i) = NULL;
2721         close (i);
2722       }
2723
2724   vty_timeout_val = VTY_TIMEOUT_DEFAULT;
2725
2726   if (vty_accesslist_name)
2727     {
2728       XFREE(MTYPE_VTY, vty_accesslist_name);
2729       vty_accesslist_name = NULL;
2730     }
2731
2732 #ifdef BRCM_LIST_SUPPORT
2733   if (vty_ipv6_accesslist_name)
2734     {
2735       XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2736       vty_ipv6_accesslist_name = NULL;
2737     }
2738 #endif
2739 }
2740
2741 /* for ospf6d easy temprary reload function */
2742 /* vty_reset + close accept socket */
2743 void
2744 vty_finish ()
2745 {
2746   int i;
2747   struct vty *vty;
2748   struct thread *vty_serv_thread;
2749
2750   for (i = 0; i < vector_max (vtyvec); i++)
2751     if ((vty = vector_slot (vtyvec, i)) != NULL)
2752       {
2753         buffer_reset (vty->obuf);
2754         vty->status = VTY_CLOSE;
2755         vty_close (vty);
2756       }
2757
2758   for (i = 0; i < vector_max (Vvty_serv_thread); i++)
2759     if ((vty_serv_thread = vector_slot (Vvty_serv_thread, i)) != NULL)
2760       {
2761         thread_cancel (vty_serv_thread);
2762         vector_slot (Vvty_serv_thread, i) = NULL;
2763         close (i);
2764       }
2765
2766   vty_timeout_val = VTY_TIMEOUT_DEFAULT;
2767
2768 #ifdef BRCM_LIST_SUPPORT
2769   if (vty_accesslist_name)
2770     {
2771       XFREE(MTYPE_VTY, vty_accesslist_name);
2772       vty_accesslist_name = NULL;
2773     }
2774
2775   if (vty_ipv6_accesslist_name)
2776     {
2777       XFREE(MTYPE_VTY, vty_ipv6_accesslist_name);
2778       vty_ipv6_accesslist_name = NULL;
2779     }
2780 #endif
2781 }
2782
2783 void
2784 vty_save_cwd ()
2785 {
2786   char *cwd;
2787
2788   cwd = getcwd (NULL, MAXPATHLEN);
2789
2790   vty_cwd = XMALLOC (MTYPE_TMP, strlen (cwd) + 1);
2791   strcpy (vty_cwd, cwd);
2792 }
2793
2794 char *
2795 vty_get_cwd ()
2796 {
2797   return vty_cwd;
2798 }
2799
2800 int
2801 vty_shell (struct vty *vty)
2802 {
2803   return vty->type == VTY_SHELL ? 1 : 0;
2804 }
2805
2806 int
2807 vty_shell_serv (struct vty *vty)
2808 {
2809   return vty->type == VTY_SHELL_SERV ? 1 : 0;
2810 }
2811
2812 void
2813 vty_init_vtysh ()
2814 {
2815   vtyvec = vector_init (VECTOR_MIN_SIZE);
2816 }
2817 #endif /* BRCM_CMD_SUPPORT */
2818
2819 /* Install vty's own commands like `who' command. */
2820 void
2821 vty_init ()
2822 {
2823   /* For further configuration read, preserve current directory. */
2824 #if defined(BRCM_CMD_SUPPORT)
2825   vty_save_cwd ();
2826 #endif
2827
2828   vtyvec = vector_init (VECTOR_MIN_SIZE);
2829
2830   /* Initilize server thread vector. */
2831   Vvty_serv_thread = vector_init (VECTOR_MIN_SIZE);
2832
2833 #if defined(BRCM_CMD_SUPPORT)
2834   /* Install bgp top node. */
2835   install_node (&vty_node, vty_config_write);
2836
2837   install_element (VIEW_NODE, &config_who_cmd);
2838   install_element (VIEW_NODE, &show_history_cmd);
2839   install_element (ENABLE_NODE, &config_who_cmd);
2840   install_element (CONFIG_NODE, &line_vty_cmd);
2841   install_element (CONFIG_NODE, &service_advanced_vty_cmd);
2842   install_element (CONFIG_NODE, &no_service_advanced_vty_cmd);
2843   install_element (CONFIG_NODE, &show_history_cmd);
2844   install_element (ENABLE_NODE, &terminal_monitor_cmd);
2845   install_element (ENABLE_NODE, &terminal_no_monitor_cmd);
2846   install_element (ENABLE_NODE, &show_history_cmd);
2847
2848   install_default (VTY_NODE);
2849   install_element (VTY_NODE, &exec_timeout_min_cmd);
2850   install_element (VTY_NODE, &exec_timeout_sec_cmd);
2851   install_element (VTY_NODE, &no_exec_timeout_cmd);
2852   install_element (VTY_NODE, &vty_access_class_cmd);
2853   install_element (VTY_NODE, &no_vty_access_class_cmd);
2854   install_element (VTY_NODE, &vty_login_cmd);
2855   install_element (VTY_NODE, &no_vty_login_cmd);
2856 #ifdef HAVE_IPV6
2857   install_element (VTY_NODE, &vty_ipv6_access_class_cmd);
2858   install_element (VTY_NODE, &no_vty_ipv6_access_class_cmd);
2859 #endif /* HAVE_IPV6 */
2860 #endif /* BRCM_CMD_SUPPORT */
2861 }
2862