]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/net/tcpip/v2_0/src/ecos/support.c
Initial revision
[karo-tx-redboot.git] / packages / net / tcpip / v2_0 / src / ecos / support.c
1 //==========================================================================
2 //
3 //      ecos/support.c
4 //
5 //      eCos wrapper and support functions
6 //
7 //==========================================================================
8 //####BSDCOPYRIGHTBEGIN####
9 //
10 // -------------------------------------------
11 //
12 // Portions of this software may have been derived from OpenBSD or other sources,
13 // and are covered by the appropriate copyright disclaimers included herein.
14 //
15 // -------------------------------------------
16 //
17 //####BSDCOPYRIGHTEND####
18 //==========================================================================
19 //#####DESCRIPTIONBEGIN####
20 //
21 // Author(s):    gthomas, hmt
22 // Contributors: gthomas, hmt
23 // Date:         2000-01-10
24 // Purpose:      
25 // Description:  
26 //              
27 //
28 //####DESCRIPTIONEND####
29 //
30 //==========================================================================
31
32
33 // Support routines, etc., used by network code
34
35 #include <sys/param.h>
36 #include <sys/malloc.h>
37 #include <sys/mbuf.h>
38 #include <sys/kernel.h>
39 #include <sys/domain.h>
40 #include <sys/protosw.h>
41 #include <sys/sockio.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <net/if.h>
45 #include <net/route.h>
46 #include <net/netisr.h>
47 #include <netinet/in.h>
48 #include <netinet/in_var.h>
49 #include <arpa/inet.h>
50
51 #include <machine/cpu.h>
52
53 #include <pkgconf/net.h>
54
55 #include <cyg/infra/diag.h>
56 #include <cyg/hal/hal_intr.h>
57 #include <cyg/kernel/kapi.h>
58
59 #include <cyg/infra/cyg_ass.h>
60
61 #if !CYGPKG_NET_DRIVER_FRAMEWORK   // Interface
62 #error At least one network driver framework must be defined!
63 #else
64 #include <cyg/io/eth/netdev.h>
65
66 // Define table boundaries
67 CYG_HAL_TABLE_BEGIN( __NETDEVTAB__, netdev );
68 CYG_HAL_TABLE_END( __NETDEVTAB_END__, netdev );
69
70 // Used for system-wide "ticks per second"
71 int hz = 100;
72 int tick = 10000;  // usec per "tick"
73
74 volatile struct timeval mono_time;
75 volatile struct timeval ktime;
76
77 // Low-level network debugging
78 int net_debug = 0;
79
80 #define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
81 static char netint_stack[STACK_SIZE];
82 static cyg_thread netint_thread_data;
83 static cyg_handle_t netint_thread_handle;
84
85 cyg_flag_t netint_flags;  
86 #define NETISR_ANY 0xFFFFFFFF  // Any possible bit...
87
88 extern void cyg_test_exit(void);  // TEMP
89 void
90 cyg_panic(const char *msg, ...)
91 {
92     cyg_uint32 old_ints;
93     CYG_FAIL( msg );
94     HAL_DISABLE_INTERRUPTS(old_ints);
95     diag_printf("PANIC: %s\n", msg);
96     cyg_test_exit();  // FIXME
97 }
98
99
100 // Round a number 'n' up to a multiple of 'm'
101 #define round(n,m) ((((n)+((m)-1))/(m))*(m))
102
103 #define NET_MEMPOOL_SIZE  round(CYGPKG_NET_MEM_USAGE/4,MSIZE)
104 #define NET_MBUFS_SIZE    round(CYGPKG_NET_MEM_USAGE/4,MSIZE)
105 #define NET_CLUSTERS_SIZE round(CYGPKG_NET_MEM_USAGE/2,MCLBYTES)
106
107 static unsigned char net_mempool_area[NET_MEMPOOL_SIZE];
108 static cyg_mempool_var net_mem_pool;
109 static cyg_handle_t    net_mem;
110 static unsigned char net_mbufs_area[NET_MBUFS_SIZE];
111 static cyg_mempool_fix net_mbufs_pool;
112 static cyg_handle_t    net_mbufs;
113 static unsigned char net_clusters_area[NET_CLUSTERS_SIZE];
114 static cyg_mempool_fix net_clusters_pool;
115 static cyg_handle_t    net_clusters;
116 static char            net_clusters_refcnt[(NET_CLUSTERS_SIZE/MCLBYTES)+1];
117
118 #ifdef CYGDBG_NET_TIMING_STATS
119 static struct net_stats  stats_malloc, stats_free, 
120     stats_memcpy, stats_memset,
121     stats_mbuf_alloc, stats_mbuf_free, stats_cluster_alloc;
122 extern struct net_stats stats_in_cksum;
123
124 // Display a number of ticks as microseconds
125 // Note: for improved calculation significance, values are kept in ticks*1000
126 static long rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION;
127 static long ns_per_system_clock;
128
129 static void
130 show_ticks_in_us(cyg_uint32 ticks)
131 {
132     long long ns;
133     ns_per_system_clock = 1000000/rtc_resolution[1];
134     ns = (ns_per_system_clock * ((long long)ticks * 1000)) / 
135         CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
136     ns += 5;  // for rounding to .01us
137     diag_printf("%7d.%02d", (int)(ns/1000), (int)((ns%1000)/10));
138 }
139
140 void
141 show_net_stats(struct net_stats *stats, const char *title)
142 {
143     int ave;
144     ave = stats->total_time / stats->count;
145     diag_printf("%s:\n", title);
146     diag_printf("  count: %6d", stats->count);
147     diag_printf(", min: ");
148     show_ticks_in_us(stats->min_time);
149     diag_printf(", max: ");
150     show_ticks_in_us(stats->max_time);
151     diag_printf(", total: ");
152     show_ticks_in_us(stats->total_time);
153     diag_printf(", ave: ");
154     show_ticks_in_us(ave);
155     diag_printf("\n");
156     // Reset stats
157     memset(stats, 0, sizeof(*stats));
158 }
159
160 void
161 show_net_times(void)
162 {
163     show_net_stats(&stats_malloc,        "Net malloc");
164     show_net_stats(&stats_free,          "Net free");
165     show_net_stats(&stats_mbuf_alloc,    "Mbuf alloc");
166     show_net_stats(&stats_mbuf_free,     "Mbuf free");
167     show_net_stats(&stats_cluster_alloc, "Cluster alloc");
168     show_net_stats(&stats_in_cksum,      "Checksum");
169     show_net_stats(&stats_memcpy,        "Net memcpy");
170     show_net_stats(&stats_memset,        "Net memset");
171 }
172 #endif /* CYGDBG_NET_TIMING_STATS */ 
173
174 void *
175 cyg_net_malloc(u_long size, int type, int flags)
176 {
177     void *res;
178     START_STATS();
179     if (flags & M_NOWAIT) {
180         res = cyg_mempool_var_try_alloc(net_mem, size);
181     } else {
182         res = cyg_mempool_var_alloc(net_mem, size);
183     }
184     FINISH_STATS(stats_malloc);
185     return (res);
186 }
187
188 void 
189 cyg_net_free(caddr_t addr, int type)
190 {
191     START_STATS();
192     cyg_mempool_var_free(net_mem, addr);
193     FINISH_STATS(stats_free);
194 }
195
196 void *
197 cyg_net_mbuf_alloc(int type, int flags)
198 {
199     void *res;    
200     START_STATS();
201     mbstat.m_mbufs++;
202     if (flags & M_NOWAIT) {
203         res = cyg_mempool_fix_try_alloc(net_mbufs);
204     } else {
205         res = cyg_mempool_fix_alloc(net_mbufs);
206     }
207     FINISH_STATS(stats_mbuf_alloc);
208     // Check that this nastiness works OK
209     CYG_ASSERT( dtom(res) == res, "dtom failed, base of mbuf" );
210     CYG_ASSERT( dtom((char *)res + MSIZE/2) == res, "dtom failed, mid mbuf" );
211     return (res);
212 }
213
214 void 
215 cyg_net_mbuf_free(caddr_t addr, int type)
216 {
217     START_STATS();
218     mbstat.m_mbufs--;
219     cyg_mempool_fix_free(net_mbufs, addr);
220     FINISH_STATS(stats_mbuf_free);
221 }
222
223 void *
224 cyg_net_cluster_alloc(void)
225 {
226     void *res;
227     START_STATS();
228     res = cyg_mempool_fix_try_alloc(net_clusters);
229     FINISH_STATS(stats_cluster_alloc);
230     return res;
231 }
232
233 static void
234 cyg_kmem_init(void)
235 {
236     unsigned char *p;
237 #ifdef CYGPKG_NET_DEBUG
238     diag_printf("Network stack using %d bytes for misc space\n", NET_MEMPOOL_SIZE);
239     diag_printf("                    %d bytes for mbufs\n", NET_MBUFS_SIZE);
240     diag_printf("                    %d bytes for mbuf clusters\n", NET_CLUSTERS_SIZE);
241 #endif
242     cyg_mempool_var_create(&net_mempool_area,
243                            NET_MEMPOOL_SIZE,
244                            &net_mem,
245                            &net_mem_pool);
246     // Align the mbufs on MSIZE boudaries so that dtom() can work.
247     p = (unsigned char *)(((long)(&net_mbufs_area) + MSIZE - 1) & ~(MSIZE-1));
248     cyg_mempool_fix_create(p,
249                            ((&(net_mbufs_area[NET_MBUFS_SIZE])) - p) & ~(MSIZE-1),
250                            MSIZE,
251                            &net_mbufs,
252                            &net_mbufs_pool);
253     cyg_mempool_fix_create(&net_clusters_area,
254                            NET_CLUSTERS_SIZE,
255                            MCLBYTES,
256                            &net_clusters,
257                            &net_clusters_pool);
258     mbutl = (struct mbuf *)&net_clusters_area;
259     mclrefcnt = net_clusters_refcnt;
260 }
261
262 void cyg_kmem_print_stats( void )
263 {
264     cyg_mempool_info info;
265
266     diag_printf( "Network stack mbuf stats:\n" );
267     diag_printf( "   mbufs %d, clusters %d, free clusters %d\n",
268                  mbstat.m_mbufs,        /* mbufs obtained from page pool */
269                  mbstat.m_clusters,     /* clusters obtained from page pool */
270                  /* mbstat.m_spare, */  /* spare field */
271                  mbstat.m_clfree        /* free clusters */
272         );
273     diag_printf( "   Failed to get %d times\n"
274                  "   Waited to get %d times\n"
275                  "   Drained queues to get %d times\n",
276                  mbstat.m_drops,        /* times failed to find space */
277                  mbstat.m_wait,         /* times waited for space */
278                  mbstat.m_drain         /* times drained protocols for space */
279                  /* mbstat.m_mtypes[256]; type specific mbuf allocations */
280         );
281
282     cyg_mempool_var_get_info( net_mem, &info );
283     diag_printf( "Misc mpool: total %7d, free %7d, max free block %d\n",
284                  info.totalmem,
285                  info.freemem,
286                  info.maxfree
287         );
288
289     cyg_mempool_fix_get_info( net_mbufs, &info );
290     diag_printf( "Mbufs pool: total %7d, free %7d, blocksize %4d\n",
291                  info.totalmem,
292                  info.freemem,
293                  info.blocksize
294         );
295
296
297     cyg_mempool_fix_get_info( net_clusters, &info );
298     diag_printf( "Clust pool: total %7d, free %7d, blocksize %4d\n",
299                  info.totalmem,
300                  info.freemem,
301                  info.blocksize
302         );
303 }
304
305 // This API is for our own automated network tests.  It's not in any header
306 // files because it's not at all supported.
307 int cyg_net_get_mem_stats( int which, cyg_mempool_info *p )
308 {
309     CYG_CHECK_DATA_PTR( p, "Bad pointer to mempool_info" );
310     CYG_ASSERT( 0 <= which, "Mempool selector underflow" );
311     CYG_ASSERT( 2 >=which, "Mempool selector overflow" );
312     
313     if ( p )
314         switch ( which ) {
315         case 0:
316             cyg_mempool_var_get_info( net_mem, p );
317             break;
318         case 1:
319             cyg_mempool_fix_get_info( net_mbufs, p );
320             break;
321         case 2:
322             cyg_mempool_fix_get_info( net_clusters, p );
323             break;
324         default:
325             return 0;
326         }
327     return (int)p;
328 }
329
330 int
331 cyg_mtocl(u_long x)
332 {
333     int res;
334     res = (((u_long)(x) - (u_long)mbutl) >> MCLSHIFT);
335     return res;
336 }
337
338 struct mbuf *
339 cyg_cltom(u_long x)
340 {
341     struct mbuf *res;
342     res = (struct mbuf *)((caddr_t)((u_long)mbutl + ((u_long)(x) << MCLSHIFT)));
343     return res;
344 }
345
346 externC void 
347 net_memcpy(void *d, void *s, int n)
348 {
349     START_STATS();
350     memcpy(d, s, n);
351     FINISH_STATS(stats_memcpy);
352 }
353
354 externC void 
355 net_memset(void *s, int v, int n)
356 {
357     START_STATS();
358     memset(s, v, n);
359     FINISH_STATS(stats_memset);
360 }
361
362 // Rather than bring in the whole BSD 'random' code...
363 int
364 arc4random(void)
365 {
366     cyg_uint32 res;
367     static unsigned long seed = 0xDEADB00B;
368     HAL_CLOCK_READ(&res);  // Not so bad... (but often 0..N where N is small)
369     seed = ((seed & 0x007F00FF) << 7) ^
370         ((seed & 0x0F80FF00) >> 8) ^ // be sure to stir those low bits
371         (res << 13) ^ (res >> 9);    // using the clock too!
372     return (int)seed;
373 }
374
375 void 
376 get_random_bytes(void *buf, size_t len)
377 {
378     unsigned long ranbuf, *lp;
379     lp = (unsigned long *)buf;
380     while (len > 0) {
381         ranbuf = arc4random();
382         *lp++ = ranbuf;
383         len -= sizeof(ranbuf);
384     }
385 }
386
387 void 
388 microtime(struct timeval *tp)
389 {
390     panic("microtime");
391 }
392
393 void
394 get_mono_time(void)
395 {
396     panic("get_mono_time");
397 }
398
399 void 
400 csignal(pid_t pgid, int signum, uid_t uid, uid_t euid)
401 {
402     panic("csignal");
403 }
404
405 int
406 bcmp(const void *_p1, const void *_p2, size_t len)
407 {
408     int res = 0;
409     unsigned char *p1 = (unsigned char *)_p1;
410     unsigned char *p2 = (unsigned char *)_p2;
411     while (len-- > 0) {
412         res = *p1++ - *p2++;
413         if (res) break;
414     }
415     return res;
416 }
417
418 int
419 copyout(const void *s, void *d, size_t len)
420 {
421     memcpy(d, s, len);
422     return 0;
423 }
424
425 int
426 copyin(const void *s, void *d, size_t len)
427 {
428     memcpy(d, s, len);
429     return 0;
430 }
431
432 void
433 ovbcopy(const void *s, void *d, size_t len)
434 {
435     memcpy(d, s, len);
436 }
437
438 // ------------------------------------------------------------------------
439 // THE NETWORK THREAD ITSELF
440 //
441 // Network software interrupt handler
442 //   This function is run as a separate thread to allow
443 // processing of network events (mostly incoming packets)
444 // at "user level" instead of at interrupt time.
445 //
446 static void
447 cyg_netint(cyg_addrword_t param)
448 {
449     cyg_flag_value_t curisr;
450     int spl;
451     while (true) {
452         curisr = cyg_flag_wait(&netint_flags, NETISR_ANY, 
453                                CYG_FLAG_WAITMODE_OR|CYG_FLAG_WAITMODE_CLR);
454         spl = splsoftnet(); // Prevent any overlapping "stack" processing
455 #ifdef INET
456         if (curisr & (1 << NETISR_ARP)) {
457             // Pending ARP requests
458             arpintr();
459         }
460         if (curisr & (1 << NETISR_IP)) {
461             // Pending IPv4 input
462             ipintr();
463         }
464 #endif
465 #ifdef INET6
466         if (curisr & (1 << NETISR_IPV6)) {
467             // Pending IPv6 input
468             ip6intr();
469         }
470 #endif
471 #if NBRIDGE > 0
472         if (curisr & (1 << NETISR_BRIDGE)) {
473             // Pending bridge input
474             bridgeintr();
475         }
476 #endif
477         splx(spl);
478     }
479 }
480
481
482 // This just sets one of the pseudo-ISR bits used above.
483 void
484 setsoftnet(void)
485 {
486     // This is called if we are out of MBUFs - it doesn't do anything, and
487     // that situation is handled OK, so don't bother with the diagnostic:
488
489     // diag_printf("setsoftnet\n");
490
491     // No need to do this because it is ignored anyway:
492     // schednetisr(NETISR_SOFTNET);
493 }
494
495
496 /* Update the kernel globel ktime. */
497 static void 
498 cyg_ktime_func(cyg_handle_t alarm,cyg_addrword_t data)
499 {
500     cyg_tick_count_t now = cyg_current_time();
501
502     ktime.tv_usec = (now % hz) * tick;
503     ktime.tv_sec = 1 + now / hz;
504 }
505
506 static void
507 cyg_ktime_init(void)
508 {
509     cyg_handle_t ktime_alarm_handle;
510     static cyg_alarm ktime_alarm;
511     cyg_handle_t counter;
512   
513     // Do not start at 0 - net stack thinks 0 an invalid time;
514     // Have a valid time available from right now:
515     ktime.tv_usec = 0;
516     ktime.tv_sec = 1;
517
518     cyg_clock_to_counter(cyg_real_time_clock(),&counter);
519     cyg_alarm_create(counter,
520                      cyg_ktime_func,
521                      0,
522                      &ktime_alarm_handle,
523                      &ktime_alarm);
524
525     /* We want one alarm every 10ms. */
526     cyg_alarm_initialize(ktime_alarm_handle,cyg_current_time()+1,1);
527     cyg_alarm_enable(ktime_alarm_handle);
528 }
529
530 //
531 // Network initialization
532 //   This function is called during system initialization to setup the whole
533 // networking environment.
534
535 // Linker magic to execute this function as 'init'
536 extern void cyg_do_net_init(void);
537
538 extern void ifinit(void);
539 extern void loopattach(int);
540 extern void bridgeattach(int);
541
542 // Internal init functions:
543 extern void cyg_alarm_timeout_init(void);
544 extern void cyg_tsleep_init(void);
545
546 void
547 cyg_net_init(void)
548 {
549     static int _init = false;
550     cyg_netdevtab_entry_t *t;
551
552     if (_init) return;
553
554     cyg_do_net_init();  // Just forces linking in the initializer/constructor
555     // Initialize interrupt "flags"
556     cyg_flag_init(&netint_flags);
557     // Initialize timeouts and net service thread (pseudo-DSRs)
558     cyg_alarm_timeout_init();
559     // Initialize tsleep/wakeup support
560     cyg_tsleep_init();
561     // Initialize network memory system
562     cyg_kmem_init();
563     mbinit();
564     cyg_ktime_init();
565
566     // Create network background thread
567     cyg_thread_create(CYGPKG_NET_THREAD_PRIORITY, // Priority
568                       cyg_netint,               // entry
569                       0,                        // entry parameter
570                       "Network support",        // Name
571                       &netint_stack[0],         // Stack
572                       STACK_SIZE,               // Size
573                       &netint_thread_handle,    // Handle
574                       &netint_thread_data       // Thread data structure
575         );
576     cyg_thread_resume(netint_thread_handle);    // Start it
577
578     // Initialize all network devices
579     for (t = &__NETDEVTAB__[0]; t != &__NETDEVTAB_END__; t++) {
580 //        diag_printf("Init device '%s'\n", t->name);
581         if (t->init(t)) {
582             t->status = CYG_NETDEVTAB_STATUS_AVAIL;
583         } else {
584             // What to do if device init fails?
585             t->status = 0;  // Device not [currently] available
586         }
587     }
588     // And attach the loopback interface
589 #ifdef CYGPKG_NET_NLOOP
590 #if 0 < CYGPKG_NET_NLOOP
591     loopattach(0);
592 #endif
593 #endif
594 #if NBRIDGE > 0
595     bridgeattach(0);
596 #endif
597     // Start up the network processing
598     ifinit();
599     domaininit();
600
601     // Done
602     _init = true;
603 }
604
605 // Copyright (C) 2002 Gary Thomas
606
607 #include <net/if.h>
608 #include <net/route.h>
609 #include <net/netdb.h>
610 externC void if_indextoname(int indx, char *buf, int len);
611
612 typedef void pr_fun(char *fmt, ...);
613
614 static void
615 _mask(struct sockaddr *sa, char *buf, int _len)
616 {
617     char *cp = ((char *)sa) + 4;
618     int len = sa->sa_len - 4;
619     int tot = 0;
620
621     while (len-- > 0) {
622         if (tot) *buf++ = '.';
623         buf += diag_sprintf(buf, "%d", *cp++);
624         tot++;
625     }
626
627     while (tot < 4) {
628         if (tot) *buf++ = '.';
629         buf += diag_sprintf(buf, "%d", 0);
630         tot++;
631     }
632 }
633
634 static void
635 _show_ifp(struct ifnet *ifp, pr_fun *pr)
636 {
637     struct ifaddr *ifa;
638     char addr[64], netmask[64], broadcast[64];
639
640     (*pr)("%-8s", ifp->if_xname);
641     TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
642         if (ifa->ifa_addr->sa_family != AF_LINK) {
643             getnameinfo (ifa->ifa_addr, ifa->ifa_addr->sa_len, addr, sizeof(addr), 0, 0, 0);
644             getnameinfo (ifa->ifa_dstaddr, ifa->ifa_dstaddr->sa_len, broadcast, sizeof(broadcast), 0, 0, 0);
645             _mask(ifa->ifa_netmask, netmask, 64);
646             (*pr)("IP: %s, Broadcast: %s, Netmask: %s\n", addr, broadcast, netmask);
647             (*pr)("        ");
648             if ((ifp->if_flags & IFF_UP)) (*pr)("UP ");
649             if ((ifp->if_flags & IFF_BROADCAST)) (*pr)("BROADCAST ");
650             if ((ifp->if_flags & IFF_LOOPBACK)) (*pr)("LOOPBACK ");
651             if ((ifp->if_flags & IFF_RUNNING)) (*pr)("RUNNING ");
652             if ((ifp->if_flags & IFF_PROMISC)) (*pr)("PROMISC ");
653             if ((ifp->if_flags & IFF_MULTICAST)) (*pr)("MULTICAST ");
654             if ((ifp->if_flags & IFF_ALLMULTI)) (*pr)("ALLMULTI ");
655             (*pr)("MTU: %d, Metric: %d\n", ifp->if_mtu, ifp->if_metric);
656             (*pr)("        Rx - Packets: %d, Bytes: %d", ifp->if_data.ifi_ipackets, ifp->if_data.ifi_ibytes);
657             (*pr)(", Tx - Packets: %d, Bytes: %d\n", ifp->if_data.ifi_opackets, ifp->if_data.ifi_obytes);
658         }
659     }
660 }
661
662 static int
663 _dumpentry(struct radix_node *rn, void *vw)
664 {
665     struct rtentry *rt = (struct rtentry *)rn;
666     struct sockaddr *dst, *gate, *netmask, *genmask;
667     char addr[32], *cp;
668     pr_fun *pr = (pr_fun *)vw;
669
670     dst = rt_key(rt);
671     gate = rt->rt_gateway;
672     netmask = rt_mask(rt);
673     genmask = rt->rt_genmask;
674     if ((rt->rt_flags & (RTF_UP | RTF_LLINFO)) == RTF_UP) {
675         if (netmask == NULL) {
676             return 0;
677         }
678         _inet_ntop(dst, addr, sizeof(addr));
679         (*pr)("%-15s ", addr);
680         if (gate != NULL) {
681             _inet_ntop(gate, addr, sizeof(addr));
682             (*pr)("%-15s ", addr);
683         } else {
684             (*pr)("%-15s ", " ");
685         }
686         if (netmask != NULL) {
687             _mask(netmask, addr, sizeof(addr));
688             (*pr)("%-15s ", addr);
689         } else {
690             (*pr)("%-15s ", " ");
691         }
692         cp = addr;
693         if ((rt->rt_flags & RTF_UP)) *cp++ = 'U';
694         if ((rt->rt_flags & RTF_GATEWAY)) *cp++ = 'G';
695         if ((rt->rt_flags & RTF_STATIC)) *cp++ = 'S';
696         if ((rt->rt_flags & RTF_DYNAMIC)) *cp++ = 'D';
697         *cp = '\0';
698         (*pr)("%-8s ", addr);  // Flags
699         if_indextoname(rt->rt_ifp->if_index, addr, 64);
700         (*pr)("%-8s ", addr);
701         (*pr)("\n");
702     }
703     return 0;
704 }
705
706 void
707 show_network_tables(pr_fun *pr)
708 {
709     int i, error;
710     struct radix_node_head *rnh;
711     struct ifnet *ifp;
712
713     cyg_scheduler_lock();
714     (*pr)("Routing tables\n");
715     (*pr)("Destination     Gateway         Mask            Flags    Interface\n");
716     for (i = 1; i <= AF_MAX; i++) {
717         if ((rnh = rt_tables[i]) != NULL) {
718             error = rnh->rnh_walktree(rnh, _dumpentry, pr);
719         }
720     }
721
722     (*pr)("Interface statistics\n");
723     for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next) {
724         _show_ifp(ifp, pr);
725     }
726     cyg_scheduler_unlock();
727 }
728
729 #endif // CYGPKG_NET_DRIVER_FRAMEWORK
730
731 // EOF support.c