unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / redboot / v2_0 / src / net / net_io.c
1 //==========================================================================
2 //
3 //      net/net_io.c
4 //
5 //      Stand-alone network logical I/O support for RedBoot
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
12 // Copyright (C) 2002, 2003, 2004 Gary Thomas
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):    gthomas
45 // Contributors: gthomas
46 // Date:         2000-07-14
47 // Purpose:      
48 // Description:  
49 //              
50 // This code is part of RedBoot (tm).
51 //
52 //####DESCRIPTIONEND####
53 //
54 //==========================================================================
55
56 #include <redboot.h>
57 #include <net/net.h>
58 #include <cyg/hal/hal_misc.h>   // Helper functions
59 #include <cyg/hal/hal_if.h>     // HAL I/O interfaces
60 #include <cyg/hal/drv_api.h>
61 #include <cyg/hal/hal_intr.h>
62 #include <cyg/infra/cyg_ass.h>         // assertion macros
63
64 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
65 #include <flash_config.h>
66
67 RedBoot_config_option("GDB connection port",
68                       gdb_port,
69                       ALWAYS_ENABLED, true,
70                       CONFIG_INT,
71                       CYGNUM_REDBOOT_NETWORKING_TCP_PORT
72     );
73 RedBoot_config_option("Network debug at boot time", 
74                       net_debug, 
75                       ALWAYS_ENABLED, true,
76                       CONFIG_BOOL,
77                       false
78     );
79 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
80 RedBoot_config_option("Default network device", 
81                       net_device, 
82                       ALWAYS_ENABLED, true,
83                       CONFIG_NETPORT,
84                       CYGDAT_REDBOOT_DEFAULT_NETWORK_DEVICE
85     );
86 #endif
87 // Note: the following options are related.  If 'bootp' is false, then
88 // the other values are used in the configuration.  Because of the way
89 // that configuration tables are generated, they should have names which
90 // are related.  The configuration options will show up lexicographically
91 // ordered, thus the peculiar naming.  In this case, the 'use' option is
92 // negated (if false, the others apply) which makes the names even more
93 // confusing.
94
95 #ifndef CYGSEM_REDBOOT_DEFAULT_NO_BOOTP
96 #define CYGSEM_REDBOOT_DEFAULT_NO_BOOTP 0
97 #endif
98 RedBoot_config_option("Use BOOTP for network configuration",
99                       bootp, 
100                       ALWAYS_ENABLED, true,
101                       CONFIG_BOOL,
102                       !CYGSEM_REDBOOT_DEFAULT_NO_BOOTP
103     );
104 RedBoot_config_option("Local IP address",
105                       bootp_my_ip,
106                       "bootp", false,
107                       CONFIG_IP,
108                       0
109     );
110 #ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
111 RedBoot_config_option("Local IP address mask",
112                       bootp_my_ip_mask,
113                       "bootp", false,
114                       CONFIG_IP,
115                       0
116     );
117 RedBoot_config_option("Gateway IP address",
118                       bootp_my_gateway_ip,
119                       "bootp", false,
120                       CONFIG_IP,
121                       0
122     );
123 #endif
124 RedBoot_config_option("Default server IP address",
125                       bootp_server_ip,
126                       ALWAYS_ENABLED, true,
127                       CONFIG_IP,
128                       0
129     );
130
131 // Note: the following options are related too.
132 RedBoot_config_option("Force console for special debug messages",
133                       info_console_force, 
134                       ALWAYS_ENABLED, true,
135                       CONFIG_BOOL,
136                       false
137     );
138 RedBoot_config_option("Console number for special debug messages",
139                       info_console_number, 
140                       "info_console_force", true,
141                       CONFIG_INT,
142                       0
143     );
144 #endif
145
146 #define TCP_CHANNEL CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS
147
148 #ifdef DEBUG_TCP
149 int show_tcp = 0;
150 #endif 
151
152 static tcp_socket_t tcp_sock;
153 static int state;
154 static int _timeout = 500;
155 static int orig_console, orig_debug;
156
157 static int in_buflen = 0;
158 static unsigned char in_buf[64];
159 static unsigned char *in_bufp;
160 static int out_buflen = 0;
161 static unsigned char out_buf[1024];
162 static unsigned char *out_bufp;
163 static bool flush_output_lines = false;
164
165 // Functions in this module
166 static void net_io_flush(void);
167 static void net_io_revert_console(void);
168 static void net_io_putc(void*, cyg_uint8);
169
170 // Special characters used by Telnet - must be interpretted here
171 #define TELNET_IAC    0xFF // Interpret as command (escape)
172 #define TELNET_IP     0xF4 // Interrupt process
173 #define TELNET_WILL   0xFB // I Will do XXX
174 #define TELNET_WONT   0xFC // I Won't do XXX
175 #define TELNET_DO     0xFD // Will you XXX
176 #define TELNET_DONT   0xFE // Don't you XXX
177 #define TELNET_TM     0x06 // Time marker (special DO/WONT after IP)
178
179 static cyg_bool
180 _net_io_getc_nonblock(void* __ch_data, cyg_uint8* ch)
181 {
182     if (in_buflen == 0) {
183         __tcp_poll();
184         if (tcp_sock.state == _CLOSE_WAIT) {
185             // This connection is breaking
186             if (tcp_sock.data_bytes == 0 && tcp_sock.rxcnt == 0) {
187                 __tcp_close(&tcp_sock);
188                 return false;
189             }
190         }
191         if (tcp_sock.state == _CLOSED) {
192             // The connection is gone
193             net_io_revert_console();
194             *ch = '\n';
195             return true;
196         }
197         in_buflen = __tcp_read(&tcp_sock, in_buf, sizeof(in_buf));
198         in_bufp = in_buf;
199 #ifdef DEBUG_TCP
200         if (show_tcp && (in_buflen > 0)) {
201             int old_console;
202             old_console = start_console();  
203             diag_printf("%s:%d\n", __FUNCTION__, __LINE__);  
204             diag_dump_buf(in_buf, in_buflen);  
205             end_console(old_console);
206         }
207 #endif // DEBUG_TCP
208     }
209     if (in_buflen) {
210         *ch = *in_bufp++;
211         in_buflen--;
212         return true;
213     } else {
214         return false;
215     }
216 }
217
218 static cyg_bool
219 net_io_getc_nonblock(void* __ch_data, cyg_uint8* ch)
220 {
221     cyg_uint8 esc;
222
223     if (!_net_io_getc_nonblock(__ch_data, ch))
224         return false;
225
226     if (gdb_active || *ch != TELNET_IAC)
227         return true;
228
229     // Telnet escape - need to read/handle more
230     while (!_net_io_getc_nonblock(__ch_data, &esc)) ;
231
232     switch (esc) {
233     case TELNET_IAC:
234         // The other special case - escaped escape
235         return true;
236     case TELNET_IP:
237         // Special case for ^C == Interrupt Process
238         *ch = 0x03;  
239         // Just in case the other end needs synchronizing
240         net_io_putc(__ch_data, TELNET_IAC);
241         net_io_putc(__ch_data, TELNET_WONT);
242         net_io_putc(__ch_data, TELNET_TM);
243         net_io_flush();
244         return true;
245     case TELNET_DO:
246         // Telnet DO option
247         while (!_net_io_getc_nonblock(__ch_data, &esc)) ;                
248         // Respond with WONT option
249         net_io_putc(__ch_data, TELNET_IAC);
250         net_io_putc(__ch_data, TELNET_WONT);
251         net_io_putc(__ch_data, esc);
252         return false;  // Ignore this whole thing!
253     case TELNET_WILL:
254         // Telnet WILL option
255         while (!_net_io_getc_nonblock(__ch_data, &esc)) ;                
256         // Respond with DONT option
257         net_io_putc(__ch_data, TELNET_IAC);
258         net_io_putc(__ch_data, TELNET_DONT);
259         net_io_putc(__ch_data, esc);
260         return false;  // Ignore this whole thing!
261     default:
262         return false;
263     }
264 }
265
266 static cyg_uint8
267 net_io_getc(void* __ch_data)
268 {
269     cyg_uint8 ch;
270     int idle_timeout = 10;  // 10ms
271
272     CYGARC_HAL_SAVE_GP();
273     while (true) {
274         if (net_io_getc_nonblock(__ch_data, &ch)) break;
275         if (--idle_timeout == 0) {
276             net_io_flush();
277             idle_timeout = 10;
278         }
279     }
280     CYGARC_HAL_RESTORE_GP();
281     return ch;
282 }
283
284 static void
285 net_io_flush(void)
286 {
287     int n;
288     char *bp = out_buf;
289
290 #ifdef DEBUG_TCP
291     if (show_tcp) {
292         int old_console;
293         old_console = start_console();  
294         diag_printf("%s.%d\n", __FUNCTION__, __LINE__);
295         diag_dump_buf(out_buf, out_buflen);  
296         end_console(old_console);
297     }
298 #endif // SHOW_TCP
299     n = __tcp_write_block(&tcp_sock, bp, out_buflen);
300     if (n < 0) {
301         // The connection is gone!
302         net_io_revert_console();
303     } else {
304         out_buflen -= n;
305         bp += n;
306     }
307     out_bufp = out_buf;  out_buflen = 0;
308     // Check interrupt flag
309     if (CYGACC_CALL_IF_CONSOLE_INTERRUPT_FLAG()) {
310         CYGACC_CALL_IF_CONSOLE_INTERRUPT_FLAG_SET(0);
311         cyg_hal_user_break(0);
312     }
313 }
314
315 static void
316 net_io_putc(void* __ch_data, cyg_uint8 c)
317 {
318     static bool have_dollar, have_hash;
319     static int hash_count;
320
321     CYGARC_HAL_SAVE_GP();
322     *out_bufp++ = c;
323     if (c == '$') have_dollar = true;
324     if (have_dollar && (c == '#')) {
325         have_hash = true;
326         hash_count = 0;
327     }
328     if ((++out_buflen == sizeof(out_buf)) ||
329         (flush_output_lines && c == '\n') ||
330         (have_hash && (++hash_count == 3))) {
331         net_io_flush();
332         have_dollar = false;
333     }
334     CYGARC_HAL_RESTORE_GP();
335 }
336
337 static void
338 net_io_write(void* __ch_data, const cyg_uint8* __buf, cyg_uint32 __len)
339 {
340     int old_console;
341
342     old_console = start_console();
343     diag_printf("%s.%d\n", __FUNCTION__, __LINE__);
344     end_console(old_console);
345 #if 0
346     CYGARC_HAL_SAVE_GP();
347
348     while(__len-- > 0)
349         net_io_putc(__ch_data, *__buf++);
350
351     CYGARC_HAL_RESTORE_GP();
352 #endif
353 }
354
355 static void
356 net_io_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
357 {
358     int old_console;
359
360     old_console = start_console();
361     diag_printf("%s.%d\n", __FUNCTION__, __LINE__);
362     end_console(old_console);
363 #if 0
364     CYGARC_HAL_SAVE_GP();
365
366     while(__len-- > 0)
367         *__buf++ = net_io_getc(__ch_data);
368
369     CYGARC_HAL_RESTORE_GP();
370 #endif
371 }
372
373 static cyg_bool
374 net_io_getc_timeout(void* __ch_data, cyg_uint8* ch)
375 {
376     int delay_count;
377     cyg_bool res;
378
379     CYGARC_HAL_SAVE_GP();
380     net_io_flush();  // Make sure any output has been sent
381     delay_count = _timeout;
382
383     for(;;) {
384         res = net_io_getc_nonblock(__ch_data, ch);
385         if (res || 0 == delay_count--)
386             break;
387     }
388
389     CYGARC_HAL_RESTORE_GP();
390
391     return res;
392 }
393
394 static int
395 net_io_control(void *__ch_data, __comm_control_cmd_t __func, ...)
396 {
397     static int vector = 0;
398     int ret = 0;
399     static int irq_state = 0;
400
401     CYGARC_HAL_SAVE_GP();
402
403     switch (__func) {
404     case __COMMCTL_IRQ_ENABLE:
405         irq_state = 1;
406         if (vector == 0) {
407             vector = eth_drv_int_vector();
408         }
409         HAL_INTERRUPT_UNMASK(vector); 
410         break;
411     case __COMMCTL_IRQ_DISABLE:
412         ret = irq_state;
413         irq_state = 0;
414         if (vector == 0) {
415             vector = eth_drv_int_vector();
416         }
417         HAL_INTERRUPT_MASK(vector);
418         break;
419     case __COMMCTL_DBG_ISR_VECTOR:
420         ret = vector;
421         break;
422     case __COMMCTL_SET_TIMEOUT:
423     {
424         va_list ap;
425
426         va_start(ap, __func);
427
428         ret = _timeout;
429         _timeout = va_arg(ap, cyg_uint32);
430
431         va_end(ap);
432         break;
433     }
434     case __COMMCTL_FLUSH_OUTPUT:
435         net_io_flush();
436         break;
437     case __COMMCTL_ENABLE_LINE_FLUSH:
438         flush_output_lines = true;
439         break;
440     case __COMMCTL_DISABLE_LINE_FLUSH:
441         flush_output_lines = false;
442         break;
443     default:
444         break;
445     }
446     CYGARC_HAL_RESTORE_GP();
447     return ret;
448 }
449
450 static int
451 net_io_isr(void *__ch_data, int* __ctrlc, 
452            CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
453 {
454     char ch;
455
456     CYGARC_HAL_SAVE_GP();
457     *__ctrlc = 0;
458     if (net_io_getc_nonblock(__ch_data, &ch)) {
459         if (ch == 0x03) {
460             *__ctrlc = 1;
461         }
462     }
463     CYGARC_HAL_RESTORE_GP();
464     return CYG_ISR_HANDLED;
465 }
466
467 // TEMP
468
469 int 
470 start_console(void)
471 {
472     int cur_console =
473         CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
474
475 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
476     int i = 0;
477     if ( flash_get_config( "info_console_force", &i, CONFIG_BOOL) )
478         if ( i )
479             if ( ! flash_get_config( "info_console_number", &i, CONFIG_INT) )
480                 i = 0; // the default, if that call failed.
481     if ( i )
482         CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
483     else
484 #endif
485         CYGACC_CALL_IF_SET_CONSOLE_COMM(0);
486
487     return cur_console;
488 }
489
490 void
491 end_console(int old_console)
492 {
493     // Restore original console
494     CYGACC_CALL_IF_SET_CONSOLE_COMM(old_console);
495 }
496 // TEMP
497
498 static void
499 net_io_revert_console(void)
500 {
501 #ifdef CYGPKG_REDBOOT_ANY_CONSOLE
502     console_selected = false;
503 #endif
504     CYGACC_CALL_IF_SET_CONSOLE_COMM(orig_console);
505     CYGACC_CALL_IF_SET_DEBUG_COMM(orig_debug);
506     console_echo = true;
507 }
508
509 static void
510 net_io_assume_console(void)
511 {
512 #ifdef CYGPKG_REDBOOT_ANY_CONSOLE
513     console_selected = true;
514 #endif
515     console_echo = false;
516     orig_console = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
517     CYGACC_CALL_IF_SET_CONSOLE_COMM(TCP_CHANNEL);
518     orig_debug = CYGACC_CALL_IF_SET_DEBUG_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
519     CYGACC_CALL_IF_SET_DEBUG_COMM(TCP_CHANNEL);
520 }
521
522 static void
523 net_io_init(void)
524 {
525     static int init = 0;
526     if (!init) {
527         hal_virtual_comm_table_t* comm;
528         int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
529
530         // Setup procs in the vector table
531         CYGACC_CALL_IF_SET_CONSOLE_COMM(TCP_CHANNEL);
532         comm = CYGACC_CALL_IF_CONSOLE_PROCS();
533         //CYGACC_COMM_IF_CH_DATA_SET(*comm, chan);
534         CYGACC_COMM_IF_WRITE_SET(*comm, net_io_write);
535         CYGACC_COMM_IF_READ_SET(*comm, net_io_read);
536         CYGACC_COMM_IF_PUTC_SET(*comm, net_io_putc);
537         CYGACC_COMM_IF_GETC_SET(*comm, net_io_getc);
538         CYGACC_COMM_IF_CONTROL_SET(*comm, net_io_control);
539         CYGACC_COMM_IF_DBG_ISR_SET(*comm, net_io_isr);
540         CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, net_io_getc_timeout);
541
542         // Disable interrupts via this interface to set static
543         // state into correct state.
544         net_io_control( comm, __COMMCTL_IRQ_DISABLE );
545         
546         // Restore original console
547         CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
548
549         init = 1;
550         gdb_active = false;
551     }
552     __tcp_listen(&tcp_sock, gdb_port);
553     state = tcp_sock.state; 
554 #ifdef DEBUG_TCP
555     diag_printf("show tcp = %p\n", (void *)&show_tcp);
556 #endif
557 }
558
559 // Check for incoming TCP debug connection
560 void
561 net_io_test(bool is_idle)
562 {
563     if (!is_idle) return;  // Only care about idle case
564     if (!have_net) return;
565     __tcp_poll();
566     if (state != tcp_sock.state) {
567         // Something has changed
568         if (tcp_sock.state == _ESTABLISHED) {
569             // A new connection has arrived
570             net_io_assume_console();
571             in_bufp = in_buf;  in_buflen = 1;  *in_bufp = '\r';
572             out_bufp = out_buf;  out_buflen = 0;
573         }
574         if (tcp_sock.state == _CLOSED) {
575             net_io_init();  // Get ready for another connection
576         }
577     }
578     state = tcp_sock.state;
579 }
580
581 // This schedules the 'net_io_test()' function to be run by RedBoot's
582 // main command loop when idle (i.e. when no input arrives after some
583 // period of time).
584 RedBoot_idle(net_io_test, RedBoot_IDLE_NETIO);
585
586 //
587 // Network initialization
588 //
589 #include <cyg/io/eth/eth_drv.h>
590 #include <cyg/io/eth/netdev.h>
591 #include <cyg/hal/hal_tables.h>
592
593 // Define table boundaries
594 CYG_HAL_TABLE_BEGIN( __NETDEVTAB__, netdev );
595 CYG_HAL_TABLE_END( __NETDEVTAB_END__, netdev );
596
597 RedBoot_init(net_init, RedBoot_INIT_NET);
598
599 static void
600 show_addrs(void)
601 {
602     diag_printf("IP: %s", inet_ntoa((in_addr_t *)&__local_ip_addr));
603 #ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
604     diag_printf("/%s", inet_ntoa((in_addr_t *)&__local_ip_mask));
605     diag_printf(", Gateway: %s\n", inet_ntoa((in_addr_t *)&__local_ip_gate));
606 #else
607     diag_printf(", ");
608 #endif
609     diag_printf("Default server: %s", inet_ntoa(&my_bootp_info.bp_siaddr));
610 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS
611     show_dns();
612 #endif
613     diag_printf("\n");
614 }
615
616 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
617 static void
618 flash_get_IP(char *id, ip_addr_t *val)
619 {
620     ip_addr_t my_ip;
621     int i;
622
623     if (flash_get_config(id, &my_ip, CONFIG_IP)) {
624         if (my_ip[0] != 0 || my_ip[1] != 0 ||
625             my_ip[2] != 0 || my_ip[3] != 0) {
626             // 'id' is set to something so let it override any static IP
627             for (i=0; i<4; i++)
628                 (*val)[i] = my_ip[i];
629         }        
630     }
631 }
632 #endif
633
634 static cyg_netdevtab_entry_t *
635 net_devtab_entry(unsigned index)
636 {
637     cyg_netdevtab_entry_t *t = &__NETDEVTAB__[index];
638
639     if (t < &__NETDEVTAB__[0] || t >= &__NETDEVTAB_END__)
640         return NULL;
641
642     return t;
643 }
644
645 const char *
646 net_devname(unsigned index)
647 {
648     cyg_netdevtab_entry_t *t = net_devtab_entry(index);
649     if (t)
650         return t->name;
651     return NULL;
652 }
653
654 int
655 net_devindex(char *name)
656 {
657     const char *devname;
658     int index;
659
660     for (index = 0; (devname = net_devname(index)) != NULL; index++)
661         if (!strcmp(name, devname))
662             return index;
663     return -1;
664 }
665
666 static void
667 show_eth_info(void)
668 {
669     diag_printf("Ethernet %s: MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
670                 __local_enet_sc->dev_name,
671                 __local_enet_addr[0],
672                 __local_enet_addr[1],
673                 __local_enet_addr[2],
674                 __local_enet_addr[3],
675                 __local_enet_addr[4],
676                 __local_enet_addr[5]);
677 }
678
679 void
680 net_init(void)
681 {
682     cyg_netdevtab_entry_t *t;
683     unsigned index;
684     struct eth_drv_sc *primary_net = (struct eth_drv_sc *)0;
685 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
686     char *default_devname = CYGDAT_REDBOOT_DEFAULT_NETWORK_DEVICE;
687     int default_index;
688 #endif
689 #ifdef CYGDAT_REDBOOT_DEFAULT_BOOTP_SERVER_IP_ADDR
690     char ip_addr[16];
691 #endif
692
693     // Set defaults as appropriate
694 #ifdef CYGSEM_REDBOOT_DEFAULT_NO_BOOTP
695     use_bootp = false;
696 #else
697     use_bootp = true;
698 #endif
699 #ifdef CYGDBG_REDBOOT_NET_DEBUG
700     net_debug = true;
701 #else
702     net_debug = false;
703 #endif
704     gdb_port = CYGNUM_REDBOOT_NETWORKING_TCP_PORT;
705 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
706     // Fetch values from saved config data, if available
707 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
708     flash_get_config("net_device", &default_devname, CONFIG_NETPORT);
709 #endif
710     flash_get_config("net_debug", &net_debug, CONFIG_BOOL);
711     flash_get_config("gdb_port", &gdb_port, CONFIG_INT);
712     flash_get_config("bootp", &use_bootp, CONFIG_BOOL);
713     if (!use_bootp) {
714         flash_get_IP("bootp_my_ip", &__local_ip_addr);
715 #ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
716         flash_get_IP("bootp_my_ip_mask", &__local_ip_mask);
717         flash_get_IP("bootp_my_gateway_ip", &__local_ip_gate);
718 #endif
719     }
720 #endif
721 # ifdef CYGDBG_IO_ETH_DRIVERS_DEBUG
722     // Don't override if the user has deliberately set something more
723     // verbose.
724     if (0 == cyg_io_eth_net_debug)
725         cyg_io_eth_net_debug = net_debug;
726 # endif
727     have_net = false;
728     // Make sure the recv buffers are set up
729     eth_drv_buffers_init();
730     __pktbuf_init();
731
732     // Initialize network device(s).
733 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
734     default_index = net_devindex(default_devname);
735     if (default_index < 0)
736         default_index = 0;
737 #ifdef CYGSEM_REDBOOT_NETWORK_INIT_ONE_DEVICE
738     if ((t = net_devtab_entry(default_index)) != NULL && t->init(t)) {
739         t->status = CYG_NETDEVTAB_STATUS_AVAIL;
740         primary_net = __local_enet_sc;
741     } else
742 #endif
743 #endif // (CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
744     for (index = 0; (t = net_devtab_entry(index)) != NULL; index++) {
745 #ifdef CYGSEM_REDBOOT_NETWORK_INIT_ONE_DEVICE
746         if (index == default_index)
747             continue;
748 #endif
749         if (t->init(t)) {
750             t->status = CYG_NETDEVTAB_STATUS_AVAIL;
751             if (primary_net == (struct eth_drv_sc *)0) {
752                 primary_net = __local_enet_sc;
753             }
754 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
755 #   ifdef CYGSEM_REDBOOT_NETWORK_INIT_ONE_DEVICE
756             break;
757 #   else
758             if (index == default_index) {
759                 primary_net = __local_enet_sc;
760             }
761 #   endif // CYGSEM_REDBOOT_NETWORK_INIT_ONE_DEVICE
762 #endif
763         }
764     }
765     __local_enet_sc = primary_net;
766
767     if (!__local_enet_sc) {
768         diag_printf("No network interfaces found\n");
769         return;
770     }    
771     // Initialize the network [if present]
772     if (use_bootp) {
773         if (__bootp_find_local_ip(&my_bootp_info) == 0) {
774             have_net = true;
775         } else {
776             // Is it an unset address, or has it been set to a static addr
777             if (__local_ip_addr[0] == 0 && __local_ip_addr[1] == 0 &&
778                 __local_ip_addr[2] == 0 && __local_ip_addr[3] == 0) {
779                 show_eth_info();
780                 diag_printf("Can't get BOOTP info for device!\n");
781             } else {
782                 diag_printf("Can't get BOOTP info, using default IP address\n");
783                 have_net = true;
784             }
785         }
786     } else {
787         if (__local_ip_addr[0] == 0 && __local_ip_addr[1] == 0 &&
788             __local_ip_addr[2] == 0 && __local_ip_addr[3] == 0) {
789             show_eth_info();
790             diag_printf("No IP info for device!\n");
791         } else {
792             enet_addr_t enet_addr;
793             have_net = true;  // Assume values in FLASH were OK
794             // Tell the world that we are using this fixed IP address
795             if (__arp_request((ip_addr_t *)__local_ip_addr, &enet_addr, 1) >= 0) {
796                 diag_printf("Warning: IP address %s in use\n",
797                             inet_ntoa((in_addr_t *)&__local_ip_addr));
798             }
799         }
800     }
801     if (have_net) {
802         show_eth_info();
803 #ifdef CYGDAT_REDBOOT_DEFAULT_BOOTP_SERVER_IP_ADDR
804         diag_sprintf(ip_addr, "%d.%d.%d.%d", 
805                      CYGDAT_REDBOOT_DEFAULT_BOOTP_SERVER_IP_ADDR);
806         inet_aton(ip_addr, &my_bootp_info.bp_siaddr);
807 #endif
808 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
809         flash_get_IP("bootp_server_ip", (ip_addr_t *)&my_bootp_info.bp_siaddr);
810 #endif
811 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS
812         redboot_dns_res_init();
813 #endif
814         show_addrs();
815         net_io_init();
816     }
817 }
818
819 static char usage[] = "[-b] [-l <local_ip_address>[/<mask_len>]] [-h <server_address>]"
820 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS
821         " [-d <dns_server_address>]"
822 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS_FCONFIG_DOMAIN                                                  
823         " [-D <dns_domain_name>]" 
824 #endif
825 #endif
826         ;
827
828 // Exported CLI function
829 static void do_ip_addr(int argc, char *argv[]);
830 RedBoot_cmd("ip_address", 
831             "Set/change IP addresses", 
832             usage,
833             do_ip_addr
834     );
835
836 void 
837 do_ip_addr(int argc, char *argv[])
838 {
839     struct option_info opts[5];
840     char *ip_addr, *host_addr;
841     bool ip_addr_set, host_addr_set;
842     bool do_bootp = false;
843     struct sockaddr_in host;
844 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS
845     char *dns_addr;
846     bool dns_addr_set;
847 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS_FCONFIG_DOMAIN 
848     char *dns_domain;
849     bool dns_domain_set;
850 #endif
851 #endif
852     int num_opts;
853  
854     if (!have_net) {
855         net_init();
856     }
857     if (!have_net) {
858         diag_printf("Sorry, networking is not available.\n");
859         return;
860     }
861
862     init_opts(&opts[0], 'l', true, OPTION_ARG_TYPE_STR, 
863               &ip_addr, &ip_addr_set, "local IP address");
864     init_opts(&opts[1], 'h', true, OPTION_ARG_TYPE_STR, 
865               &host_addr, &host_addr_set, "default server address");
866     init_opts(&opts[2], 'b', false, OPTION_ARG_TYPE_FLG,
867               &do_bootp, 0, "use BOOTP");
868     num_opts = 3;
869 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS
870     init_opts(&opts[num_opts], 'd', true, OPTION_ARG_TYPE_STR, 
871               (void *)&dns_addr, (bool *)&dns_addr_set, "DNS server address");
872     num_opts++;
873 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS_FCONFIG_DOMAIN 
874     init_opts(&opts[num_opts], 'D', true, OPTION_ARG_TYPE_STR, 
875               (void *)&dns_domain, (bool *)&dns_domain_set, "DNS domain");
876     num_opts++;
877 #endif
878 #endif
879     CYG_ASSERT(num_opts <= NUM_ELEMS(opts), "Too many options");
880
881     if (!scan_opts(argc, argv, 1, opts, num_opts, 0, 0, "")) {
882         return;
883     }
884     if (do_bootp) {
885         if (__bootp_find_local_ip(&my_bootp_info) != 0) {
886             diag_printf("Failed to get BOOTP address\n");
887         }
888     }
889     if (ip_addr_set) {
890 #ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
891         char *slash_pos;
892         /* see if the (optional) mask length was given */
893         if( (slash_pos = strchr(ip_addr, '/')) ) {
894             unsigned long mask_len;
895             unsigned long mask;
896             *slash_pos = '\0';
897             slash_pos++;
898             if( !parse_num(slash_pos, &mask_len, 0, 0) ||  
899                 mask_len <= 0 || mask_len > 32 ) {
900                 diag_printf("Invalid mask length: %s\n", slash_pos);
901                 return;
902             }
903             mask = htonl((0xffffffff << (32-mask_len))&0xffffffff);
904             memcpy(&__local_ip_mask, &mask, 4);
905         }
906 #endif        
907         if (!_gethostbyname(ip_addr, (in_addr_t *)&host)) {
908             diag_printf("Invalid local IP address: %s\n", ip_addr);
909             return;
910         }
911         // Of course, each address goes in its own place :-)
912         memcpy(&__local_ip_addr, &host.sin_addr, sizeof(host.sin_addr));
913     }
914     if (host_addr_set) {
915         if (!_gethostbyname(host_addr, (in_addr_t *)&host)) {
916             diag_printf("Invalid server address: %s\n", host_addr);
917             return;
918         }
919         my_bootp_info.bp_siaddr = host.sin_addr;
920     }
921 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS
922     if (dns_addr_set) {
923         set_dns(dns_addr);
924     }
925 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS_FCONFIG_DOMAIN 
926     if (dns_domain_set) {
927       setdomainname(dns_domain, strlen(dns_domain));
928     }
929 #endif
930 #endif
931     show_addrs();
932     if (!have_net) {
933         have_net = true;
934         net_io_init();
935     }
936 }
937
938 // EOF net_io.c