]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/redboot/v2_0/src/net/net_io.c
d87c4bdbbfca9d4dc77ce38dc5a43f18148f607d
[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_WONT   0xFC // I Won't do it
174 #define TELNET_DO     0xFD // Will you XXX
175 #define TELNET_TM     0x06 // Time marker (special DO/WONT after IP)
176
177 static cyg_bool
178 _net_io_getc_nonblock(void* __ch_data, cyg_uint8* ch)
179 {
180     if (in_buflen == 0) {
181         __tcp_poll();
182         if (tcp_sock.state == _CLOSE_WAIT) {
183             // This connection is breaking
184             if (tcp_sock.data_bytes == 0 && tcp_sock.rxcnt == 0) {
185                 __tcp_close(&tcp_sock);
186                 return false;
187             }
188         }
189         if (tcp_sock.state == _CLOSED) {
190             // The connection is gone
191             net_io_revert_console();
192             *ch = '\n';
193             return true;
194         }
195         in_buflen = __tcp_read(&tcp_sock, in_buf, sizeof(in_buf));
196         in_bufp = in_buf;
197 #ifdef DEBUG_TCP
198         if (show_tcp && (in_buflen > 0)) {
199             int old_console;
200             old_console = start_console();  
201             diag_printf("%s:%d\n", __FUNCTION__, __LINE__);  
202             diag_dump_buf(in_buf, in_buflen);  
203             end_console(old_console);
204         }
205 #endif // DEBUG_TCP
206     }
207     if (in_buflen) {
208         *ch = *in_bufp++;
209         in_buflen--;
210         return true;
211     } else {
212         return false;
213     }
214 }
215
216 static cyg_bool
217 net_io_getc_nonblock(void* __ch_data, cyg_uint8* ch)
218 {
219     cyg_uint8 esc;
220
221     if (!_net_io_getc_nonblock(__ch_data, ch))
222         return false;
223
224     if (gdb_active || *ch != TELNET_IAC)
225         return true;
226
227     // Telnet escape - need to read/handle more
228     while (!_net_io_getc_nonblock(__ch_data, &esc)) ;
229
230     switch (esc) {
231     case TELNET_IAC:
232         // The other special case - escaped escape
233         return true;
234     case TELNET_IP:
235         // Special case for ^C == Interrupt Process
236         *ch = 0x03;  
237         // Just in case the other end needs synchronizing
238         net_io_putc(__ch_data, TELNET_IAC);
239         net_io_putc(__ch_data, TELNET_WONT);
240         net_io_putc(__ch_data, TELNET_TM);
241         net_io_flush();
242         return true;
243     case TELNET_DO:
244         // Telnet DO option
245         while (!_net_io_getc_nonblock(__ch_data, &esc)) ;                
246         // Respond with WONT option
247         net_io_putc(__ch_data, TELNET_IAC);
248         net_io_putc(__ch_data, TELNET_WONT);
249         net_io_putc(__ch_data, esc);
250         return false;  // Ignore this whole thing!
251     default:
252         return false;
253     }
254 }
255
256 static cyg_uint8
257 net_io_getc(void* __ch_data)
258 {
259     cyg_uint8 ch;
260     int idle_timeout = 10;  // 10ms
261
262     CYGARC_HAL_SAVE_GP();
263     while (true) {
264         if (net_io_getc_nonblock(__ch_data, &ch)) break;
265         if (--idle_timeout == 0) {
266             net_io_flush();
267             idle_timeout = 10;
268         }
269     }
270     CYGARC_HAL_RESTORE_GP();
271     return ch;
272 }
273
274 static void
275 net_io_flush(void)
276 {
277     int n;
278     char *bp = out_buf;
279
280 #ifdef DEBUG_TCP
281     if (show_tcp) {
282         int old_console;
283         old_console = start_console();  
284         diag_printf("%s.%d\n", __FUNCTION__, __LINE__);
285         diag_dump_buf(out_buf, out_buflen);  
286         end_console(old_console);
287     }
288 #endif // SHOW_TCP
289     n = __tcp_write_block(&tcp_sock, bp, out_buflen);
290     if (n < 0) {
291         // The connection is gone!
292         net_io_revert_console();
293     } else {
294         out_buflen -= n;
295         bp += n;
296     }
297     out_bufp = out_buf;  out_buflen = 0;
298     // Check interrupt flag
299     if (CYGACC_CALL_IF_CONSOLE_INTERRUPT_FLAG()) {
300         CYGACC_CALL_IF_CONSOLE_INTERRUPT_FLAG_SET(0);
301         cyg_hal_user_break(0);
302     }
303 }
304
305 static void
306 net_io_putc(void* __ch_data, cyg_uint8 c)
307 {
308     static bool have_dollar, have_hash;
309     static int hash_count;
310
311     CYGARC_HAL_SAVE_GP();
312     *out_bufp++ = c;
313     if (c == '$') have_dollar = true;
314     if (have_dollar && (c == '#')) {
315         have_hash = true;
316         hash_count = 0;
317     }
318     if ((++out_buflen == sizeof(out_buf)) ||
319         (flush_output_lines && c == '\n') ||
320         (have_hash && (++hash_count == 3))) {
321         net_io_flush();
322         have_dollar = false;
323     }
324     CYGARC_HAL_RESTORE_GP();
325 }
326
327 static void
328 net_io_write(void* __ch_data, const cyg_uint8* __buf, cyg_uint32 __len)
329 {
330     int old_console;
331
332     old_console = start_console();
333     diag_printf("%s.%d\n", __FUNCTION__, __LINE__);
334     end_console(old_console);
335 #if 0
336     CYGARC_HAL_SAVE_GP();
337
338     while(__len-- > 0)
339         net_io_putc(__ch_data, *__buf++);
340
341     CYGARC_HAL_RESTORE_GP();
342 #endif
343 }
344
345 static void
346 net_io_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
347 {
348     int old_console;
349
350     old_console = start_console();
351     diag_printf("%s.%d\n", __FUNCTION__, __LINE__);
352     end_console(old_console);
353 #if 0
354     CYGARC_HAL_SAVE_GP();
355
356     while(__len-- > 0)
357         *__buf++ = net_io_getc(__ch_data);
358
359     CYGARC_HAL_RESTORE_GP();
360 #endif
361 }
362
363 static cyg_bool
364 net_io_getc_timeout(void* __ch_data, cyg_uint8* ch)
365 {
366     int delay_count;
367     cyg_bool res;
368
369     CYGARC_HAL_SAVE_GP();
370     net_io_flush();  // Make sure any output has been sent
371     delay_count = _timeout;
372
373     for(;;) {
374         res = net_io_getc_nonblock(__ch_data, ch);
375         if (res || 0 == delay_count--)
376             break;
377     }
378
379     CYGARC_HAL_RESTORE_GP();
380
381     return res;
382 }
383
384 static int
385 net_io_control(void *__ch_data, __comm_control_cmd_t __func, ...)
386 {
387     static int vector = 0;
388     int ret = 0;
389     static int irq_state = 0;
390
391     CYGARC_HAL_SAVE_GP();
392
393     switch (__func) {
394     case __COMMCTL_IRQ_ENABLE:
395         irq_state = 1;
396         if (vector == 0) {
397             vector = eth_drv_int_vector();
398         }
399         HAL_INTERRUPT_UNMASK(vector); 
400         break;
401     case __COMMCTL_IRQ_DISABLE:
402         ret = irq_state;
403         irq_state = 0;
404         if (vector == 0) {
405             vector = eth_drv_int_vector();
406         }
407         HAL_INTERRUPT_MASK(vector);
408         break;
409     case __COMMCTL_DBG_ISR_VECTOR:
410         ret = vector;
411         break;
412     case __COMMCTL_SET_TIMEOUT:
413     {
414         va_list ap;
415
416         va_start(ap, __func);
417
418         ret = _timeout;
419         _timeout = va_arg(ap, cyg_uint32);
420
421         va_end(ap);
422         break;
423     }
424     case __COMMCTL_FLUSH_OUTPUT:
425         net_io_flush();
426         break;
427     case __COMMCTL_ENABLE_LINE_FLUSH:
428         flush_output_lines = true;
429         break;
430     case __COMMCTL_DISABLE_LINE_FLUSH:
431         flush_output_lines = false;
432         break;
433     default:
434         break;
435     }
436     CYGARC_HAL_RESTORE_GP();
437     return ret;
438 }
439
440 static int
441 net_io_isr(void *__ch_data, int* __ctrlc, 
442            CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
443 {
444     char ch;
445
446     CYGARC_HAL_SAVE_GP();
447     *__ctrlc = 0;
448     if (net_io_getc_nonblock(__ch_data, &ch)) {
449         if (ch == 0x03) {
450             *__ctrlc = 1;
451         }
452     }
453     CYGARC_HAL_RESTORE_GP();
454     return CYG_ISR_HANDLED;
455 }
456
457 // TEMP
458
459 int 
460 start_console(void)
461 {
462     int cur_console =
463         CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
464
465 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
466     int i = 0;
467     if ( flash_get_config( "info_console_force", &i, CONFIG_BOOL) )
468         if ( i )
469             if ( ! flash_get_config( "info_console_number", &i, CONFIG_INT) )
470                 i = 0; // the default, if that call failed.
471     if ( i )
472         CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
473     else
474 #endif
475         CYGACC_CALL_IF_SET_CONSOLE_COMM(0);
476
477     return cur_console;
478 }
479
480 void
481 end_console(int old_console)
482 {
483     // Restore original console
484     CYGACC_CALL_IF_SET_CONSOLE_COMM(old_console);
485 }
486 // TEMP
487
488 static void
489 net_io_revert_console(void)
490 {
491 #ifdef CYGPKG_REDBOOT_ANY_CONSOLE
492     console_selected = false;
493 #endif
494     CYGACC_CALL_IF_SET_CONSOLE_COMM(orig_console);
495     CYGACC_CALL_IF_SET_DEBUG_COMM(orig_debug);
496     console_echo = true;
497 }
498
499 static void
500 net_io_assume_console(void)
501 {
502 #ifdef CYGPKG_REDBOOT_ANY_CONSOLE
503     console_selected = true;
504 #endif
505     console_echo = false;
506     orig_console = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
507     CYGACC_CALL_IF_SET_CONSOLE_COMM(TCP_CHANNEL);
508     orig_debug = CYGACC_CALL_IF_SET_DEBUG_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
509     CYGACC_CALL_IF_SET_DEBUG_COMM(TCP_CHANNEL);
510 }
511
512 static void
513 net_io_init(void)
514 {
515     static int init = 0;
516     if (!init) {
517         hal_virtual_comm_table_t* comm;
518         int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
519
520         // Setup procs in the vector table
521         CYGACC_CALL_IF_SET_CONSOLE_COMM(TCP_CHANNEL);
522         comm = CYGACC_CALL_IF_CONSOLE_PROCS();
523         //CYGACC_COMM_IF_CH_DATA_SET(*comm, chan);
524         CYGACC_COMM_IF_WRITE_SET(*comm, net_io_write);
525         CYGACC_COMM_IF_READ_SET(*comm, net_io_read);
526         CYGACC_COMM_IF_PUTC_SET(*comm, net_io_putc);
527         CYGACC_COMM_IF_GETC_SET(*comm, net_io_getc);
528         CYGACC_COMM_IF_CONTROL_SET(*comm, net_io_control);
529         CYGACC_COMM_IF_DBG_ISR_SET(*comm, net_io_isr);
530         CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, net_io_getc_timeout);
531
532         // Disable interrupts via this interface to set static
533         // state into correct state.
534         net_io_control( comm, __COMMCTL_IRQ_DISABLE );
535         
536         // Restore original console
537         CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
538
539         init = 1;
540         gdb_active = false;
541     }
542     __tcp_listen(&tcp_sock, gdb_port);
543     state = tcp_sock.state; 
544 #ifdef DEBUG_TCP
545     diag_printf("show tcp = %p\n", (void *)&show_tcp);
546 #endif
547 }
548
549 // Check for incoming TCP debug connection
550 void
551 net_io_test(bool is_idle)
552 {
553     if (!is_idle) return;  // Only care about idle case
554     if (!have_net) return;
555     __tcp_poll();
556     if (state != tcp_sock.state) {
557         // Something has changed
558         if (tcp_sock.state == _ESTABLISHED) {
559             // A new connection has arrived
560             net_io_assume_console();
561             in_bufp = in_buf;  in_buflen = 1;  *in_bufp = '\r';
562             out_bufp = out_buf;  out_buflen = 0;
563         }
564         if (tcp_sock.state == _CLOSED) {
565             net_io_init();  // Get ready for another connection
566         }
567     }
568     state = tcp_sock.state;
569 }
570
571 // This schedules the 'net_io_test()' function to be run by RedBoot's
572 // main command loop when idle (i.e. when no input arrives after some
573 // period of time).
574 RedBoot_idle(net_io_test, RedBoot_IDLE_NETIO);
575
576 //
577 // Network initialization
578 //
579 #include <cyg/io/eth/eth_drv.h>
580 #include <cyg/io/eth/netdev.h>
581 #include <cyg/hal/hal_tables.h>
582
583 // Define table boundaries
584 CYG_HAL_TABLE_BEGIN( __NETDEVTAB__, netdev );
585 CYG_HAL_TABLE_END( __NETDEVTAB_END__, netdev );
586
587 RedBoot_init(net_init, RedBoot_INIT_LAST);
588
589 static void
590 show_addrs(void)
591 {
592     diag_printf("IP: %s", inet_ntoa((in_addr_t *)&__local_ip_addr));
593 #ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
594     diag_printf("/%s", inet_ntoa((in_addr_t *)&__local_ip_mask));
595     diag_printf(", Gateway: %s\n", inet_ntoa((in_addr_t *)&__local_ip_gate));
596 #else
597     diag_printf(", ");
598 #endif
599     diag_printf("Default server: %s", inet_ntoa(&my_bootp_info.bp_siaddr));
600 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS
601     show_dns();
602 #endif
603     diag_printf("\n");
604 }
605
606 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
607 static void
608 flash_get_IP(char *id, ip_addr_t *val)
609 {
610     ip_addr_t my_ip;
611     int i;
612
613     if (flash_get_config(id, &my_ip, CONFIG_IP)) {
614         if (my_ip[0] != 0 || my_ip[1] != 0 ||
615             my_ip[2] != 0 || my_ip[3] != 0) {
616             // 'id' is set to something so let it override any static IP
617             for (i=0; i<4; i++)
618                 (*val)[i] = my_ip[i];
619         }        
620     }
621 }
622 #endif
623
624 static cyg_netdevtab_entry_t *
625 net_devtab_entry(unsigned index)
626 {
627     cyg_netdevtab_entry_t *t = &__NETDEVTAB__[index];
628
629     if (t < &__NETDEVTAB__[0] || t >= &__NETDEVTAB_END__)
630         return NULL;
631
632     return t;
633 }
634
635 const char *
636 net_devname(unsigned index)
637 {
638     cyg_netdevtab_entry_t *t = net_devtab_entry(index);
639     if (t)
640         return t->name;
641     return NULL;
642 }
643
644 int
645 net_devindex(char *name)
646 {
647     const char *devname;
648     int index;
649
650     for (index = 0; (devname = net_devname(index)) != NULL; index++)
651         if (!strcmp(name, devname))
652             return index;
653     return -1;
654 }
655
656 static void
657 show_eth_info(void)
658 {
659     diag_printf("Ethernet %s: MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
660                 __local_enet_sc->dev_name,
661                 __local_enet_addr[0],
662                 __local_enet_addr[1],
663                 __local_enet_addr[2],
664                 __local_enet_addr[3],
665                 __local_enet_addr[4],
666                 __local_enet_addr[5]);
667 }
668
669 void
670 net_init(void)
671 {
672     cyg_netdevtab_entry_t *t;
673     unsigned index;
674     struct eth_drv_sc *primary_net = (struct eth_drv_sc *)0;
675 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
676     char *default_devname;
677     int default_index;
678 #endif
679 #ifdef CYGDAT_REDBOOT_DEFAULT_BOOTP_SERVER_IP_ADDR
680     char ip_addr[16];
681 #endif
682
683     // Set defaults as appropriate
684 #ifdef CYGSEM_REDBOOT_DEFAULT_NO_BOOTP
685     use_bootp = false;
686 #else
687     use_bootp = true;
688 #endif
689 #ifdef CYGDBG_REDBOOT_NET_DEBUG
690     net_debug = true;
691 #else
692     net_debug = false;
693 #endif
694     gdb_port = CYGNUM_REDBOOT_NETWORKING_TCP_PORT;
695 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
696     // Fetch values from saved config data, if available
697 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
698     flash_get_config("net_device", &default_devname, CONFIG_NETPORT);
699 #endif
700     flash_get_config("net_debug", &net_debug, CONFIG_BOOL);
701     flash_get_config("gdb_port", &gdb_port, CONFIG_INT);
702     flash_get_config("bootp", &use_bootp, CONFIG_BOOL);
703     if (!use_bootp) {
704         flash_get_IP("bootp_my_ip", &__local_ip_addr);
705 #ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
706         flash_get_IP("bootp_my_ip_mask", &__local_ip_mask);
707         flash_get_IP("bootp_my_gateway_ip", &__local_ip_gate);
708 #endif
709     }
710 #endif
711 # ifdef CYGDBG_IO_ETH_DRIVERS_DEBUG
712     // Don't override if the user has deliberately set something more
713     // verbose.
714     if (0 == cyg_io_eth_net_debug)
715         cyg_io_eth_net_debug = net_debug;
716 # endif
717     have_net = false;
718     // Make sure the recv buffers are set up
719     eth_drv_buffers_init();
720     __pktbuf_init();
721
722     // Initialize network device(s).
723 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
724     default_index = net_devindex(default_devname);
725     if (default_index < 0)
726         default_index = 0;
727 #ifdef CYGSEM_REDBOOT_NETWORK_INIT_ONE_DEVICE
728     if ((t = net_devtab_entry(default_index)) != NULL && t->init(t)) {
729         t->status = CYG_NETDEVTAB_STATUS_AVAIL;
730         primary_net = __local_enet_sc;
731     } else
732 #endif
733 #endif
734     for (index = 0; (t = net_devtab_entry(index)) != NULL; index++) {
735 #ifdef CYGSEM_REDBOOT_NETWORK_INIT_ONE_DEVICE
736         if (index == default_index)
737             continue;
738 #endif
739         if (t->init(t)) {
740             t->status = CYG_NETDEVTAB_STATUS_AVAIL;
741             if (primary_net == (struct eth_drv_sc *)0) {
742                 primary_net = __local_enet_sc;
743             }
744 #if defined(CYGHWR_NET_DRIVERS) && (CYGHWR_NET_DRIVERS > 1)
745             if (index == default_index) {
746                 primary_net = __local_enet_sc;
747             }
748 #endif
749         }
750     }
751     __local_enet_sc = primary_net;
752
753     if (!__local_enet_sc) {
754         diag_printf("No network interfaces found\n");
755         return;
756     }    
757     // Initialize the network [if present]
758     if (use_bootp) {
759         if (__bootp_find_local_ip(&my_bootp_info) == 0) {
760             have_net = true;
761         } else {
762             // Is it an unset address, or has it been set to a static addr
763             if (__local_ip_addr[0] == 0 && __local_ip_addr[1] == 0 &&
764                 __local_ip_addr[2] == 0 && __local_ip_addr[3] == 0) {
765                 show_eth_info();
766                 diag_printf("Can't get BOOTP info for device!\n");
767             } else {
768                 diag_printf("Can't get BOOTP info, using default IP address\n");
769                 have_net = true;
770             }
771         }
772     } else {
773         if (__local_ip_addr[0] == 0 && __local_ip_addr[1] == 0 &&
774             __local_ip_addr[2] == 0 && __local_ip_addr[3] == 0) {
775             show_eth_info();
776             diag_printf("No IP info for device!\n");
777         } else {
778             enet_addr_t enet_addr;
779             have_net = true;  // Assume values in FLASH were OK
780             // Tell the world that we are using this fixed IP address
781             if (__arp_request((ip_addr_t *)__local_ip_addr, &enet_addr, 1) >= 0) {
782                 diag_printf("Warning: IP address %s in use\n", inet_ntoa((in_addr_t *)&__local_ip_addr));
783             }
784         }
785     }
786     if (have_net) {
787         show_eth_info();
788 #ifdef CYGDAT_REDBOOT_DEFAULT_BOOTP_SERVER_IP_ADDR
789         diag_sprintf(ip_addr, "%d.%d.%d.%d", 
790                      CYGDAT_REDBOOT_DEFAULT_BOOTP_SERVER_IP_ADDR);
791         inet_aton(ip_addr, &my_bootp_info.bp_siaddr);
792 #endif
793 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
794         flash_get_IP("bootp_server_ip", (ip_addr_t *)&my_bootp_info.bp_siaddr);
795 #endif
796 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS
797         redboot_dns_res_init();
798 #endif
799         show_addrs();
800         net_io_init();
801     }
802 }
803
804 static char usage[] = "[-b] [-l <local_ip_address>[/<mask_len>]] [-h <server_address>]"
805 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS
806         " [-d <dns_server_address]"
807 #endif
808         ;
809
810 // Exported CLI function
811 static void do_ip_addr(int argc, char *argv[]);
812 RedBoot_cmd("ip_address", 
813             "Set/change IP addresses", 
814             usage,
815             do_ip_addr
816     );
817
818 void 
819 do_ip_addr(int argc, char *argv[])
820 {
821     struct option_info opts[4];
822     char *ip_addr, *host_addr;
823     bool ip_addr_set, host_addr_set;
824     bool do_bootp = false;
825     struct sockaddr_in host;
826 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS
827     char *dns_addr;
828     bool dns_addr_set;
829 #endif
830     int num_opts;
831
832     init_opts(&opts[0], 'l', true, OPTION_ARG_TYPE_STR, 
833               (void *)&ip_addr, (bool *)&ip_addr_set, "local IP address");
834     init_opts(&opts[1], 'h', true, OPTION_ARG_TYPE_STR, 
835               (void *)&host_addr, (bool *)&host_addr_set, "default server address");
836     init_opts(&opts[2], 'b', false, OPTION_ARG_TYPE_FLG,
837               &do_bootp, 0, "use BOOTP");
838     num_opts = 3;
839 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS
840     init_opts(&opts[num_opts], 'd', true, OPTION_ARG_TYPE_STR, 
841               (void *)&dns_addr, (bool *)&dns_addr_set, "DNS server address");
842     num_opts++;
843 #endif
844
845     CYG_ASSERT(num_opts <= NUM_ELEMS(opts), "Too many options");
846
847     if (!scan_opts(argc, argv, 1, opts, num_opts, 0, 0, "")) {
848         return;
849     }
850     if (do_bootp) {
851         if (__bootp_find_local_ip(&my_bootp_info) != 0) {
852             diag_printf("Failed to get BOOTP address\n");
853         }
854     }
855     if (ip_addr_set) {
856 #ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
857         char *slash_pos;
858         /* see if the (optional) mask length was given */
859         if( (slash_pos = strchr(ip_addr, '/')) ) {
860             unsigned long mask_len;
861             unsigned long mask;
862             *slash_pos = '\0';
863             slash_pos++;
864             if (!parse_num(slash_pos, &mask_len, 0, 0) ||
865                 mask_len <= 0 || mask_len > 32 ) {
866                 diag_printf("Invalid mask length: %s\n", slash_pos);
867                 return;
868             }
869             mask = htonl((0xffffffff << (32-mask_len))&0xffffffff);
870             memcpy(&__local_ip_mask, &mask, 4);
871         }
872 #endif        
873         if (!_gethostbyname(ip_addr, (in_addr_t *)&host)) {
874             diag_printf("Invalid local IP address: %s\n", ip_addr);
875             return;
876         }
877         // Of course, each address goes in its own place :-)
878         memcpy(&__local_ip_addr, &host.sin_addr, sizeof(host.sin_addr));
879     }
880     if (host_addr_set) {
881         if (!_gethostbyname(host_addr, (in_addr_t *)&host)) {
882             diag_printf("Invalid server address: %s\n", host_addr);
883             return;
884         }
885         my_bootp_info.bp_siaddr = host.sin_addr;
886     }
887 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS
888     if (dns_addr_set) {
889         set_dns(dns_addr);
890     }
891 #endif
892     show_addrs();
893     if (!have_net) {
894         have_net = true;
895         net_io_init();
896     }
897 }
898
899 // EOF net_io.c