]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/redboot/v2_0/src/net/net_io.c
499d5d7472a76cda5329afc2fd0b55631dc09ef7
[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", &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 0
858         if (!have_net) {
859                 diag_printf("Sorry, networking is not available.\n");
860                 return;
861         }
862 #endif
863         init_opts(&opts[0], 'l', true, OPTION_ARG_TYPE_STR,
864                         &ip_addr, &ip_addr_set, "local IP address");
865         init_opts(&opts[1], 'h', true, OPTION_ARG_TYPE_STR,
866                         &host_addr, &host_addr_set, "default server address");
867         init_opts(&opts[2], 'b', false, OPTION_ARG_TYPE_FLG,
868                         &do_bootp, 0, "use BOOTP");
869         num_opts = 3;
870 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS
871         init_opts(&opts[num_opts], 'd', true, OPTION_ARG_TYPE_STR,
872                         &dns_addr, &dns_addr_set, "DNS server address");
873         num_opts++;
874 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS_FCONFIG_DOMAIN
875         init_opts(&opts[num_opts], 'D', true, OPTION_ARG_TYPE_STR,
876                         &dns_domain, &dns_domain_set, "DNS domain");
877         num_opts++;
878 #endif
879 #endif
880         CYG_ASSERT(num_opts <= NUM_ELEMS(opts), "Too many options");
881
882         if (!scan_opts(argc, argv, 1, opts, num_opts, 0, 0, "")) {
883                 return;
884         }
885         if (do_bootp) {
886                 if (__bootp_find_local_ip(&my_bootp_info) != 0) {
887                         diag_printf("Failed to get BOOTP address\n");
888                 }
889         }
890         if (ip_addr_set) {
891 #ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
892                 char *slash_pos;
893                 /* see if the (optional) mask length was given */
894                 if( (slash_pos = strchr(ip_addr, '/')) ) {
895                         unsigned long mask_len;
896                         unsigned long mask;
897                         *slash_pos = '\0';
898                         slash_pos++;
899                         if( !parse_num(slash_pos, &mask_len, 0, 0) ||
900                                 mask_len <= 0 || mask_len > 32 ) {
901                                 diag_printf("Invalid mask length: %s\n", slash_pos);
902                                 return;
903                         }
904                         mask = htonl((~0 << (32 - mask_len)) & ~0);
905                         memcpy(&__local_ip_mask, &mask, 4);
906                 }
907 #endif
908                 if (!_gethostbyname(ip_addr, (in_addr_t *)&host)) {
909                         diag_printf("Invalid local IP address: %s\n", ip_addr);
910                         return;
911                 }
912                 // Of course, each address goes in its own place :-)
913                 memcpy(&__local_ip_addr, &host.sin_addr, sizeof(host.sin_addr));
914         }
915         if (host_addr_set) {
916                 if (!_gethostbyname(host_addr, (in_addr_t *)&host)) {
917                         diag_printf("Invalid server address: %s\n", host_addr);
918                         return;
919                 }
920                 my_bootp_info.bp_siaddr = host.sin_addr;
921         }
922 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS
923         if (dns_addr_set) {
924                 set_dns(dns_addr);
925         }
926 #ifdef CYGPKG_REDBOOT_NETWORKING_DNS_FCONFIG_DOMAIN
927         if (dns_domain_set) {
928                 setdomainname(dns_domain, strlen(dns_domain));
929         }
930 #endif
931 #endif
932         show_addrs();
933         if (!have_net) {
934                 have_net = true;
935                 net_io_init();
936         }
937 }
938
939 // EOF net_io.c