]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/net/bsd_tcpip/v2_0/src/ecos/support.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / net / bsd_tcpip / v2_0 / src / ecos / support.c
1 //==========================================================================
2 //
3 //      src/ecos/support.c
4 //
5 //==========================================================================
6 //####BSDCOPYRIGHTBEGIN####
7 //
8 // -------------------------------------------
9 //
10 // Portions of this software may have been derived from OpenBSD, 
11 // FreeBSD or other sources, and are covered by the appropriate
12 // copyright disclaimers included herein.
13 //
14 // Portions created by Red Hat are
15 // Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
16 //
17 // Copyright (C) 2002, 2003 Gary Thomas
18 // Copyright (C) 2003 Andrew Lunn
19 // -------------------------------------------
20 //
21 //####BSDCOPYRIGHTEND####
22 //==========================================================================
23
24 //==========================================================================
25 //
26 //      ecos/support.c
27 //
28 //      eCos wrapper and support functions
29 //
30 //==========================================================================
31 //####BSDCOPYRIGHTBEGIN####
32 //
33 // -------------------------------------------
34 //
35 // Portions of this software may have been derived from OpenBSD or other sources,
36 // and are covered by the appropriate copyright disclaimers included herein.
37 //
38 // -------------------------------------------
39 //
40 //####BSDCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):    gthomas, hmt
45 // Contributors: gthomas, hmt, andrew.lunn@ascom.ch
46 // Date:         2000-01-10
47 // Purpose:      
48 // Description:  
49 //              
50 //
51 //####DESCRIPTIONEND####
52 //
53 //==========================================================================
54
55
56 // Support routines, etc., used by network code
57
58 #include <sys/param.h>
59 #include <sys/malloc.h>
60 #include <sys/mbuf.h>
61 #include <sys/domain.h>
62 #include <sys/protosw.h>
63 #include <sys/sockio.h>
64 #include <sys/socket.h>
65 #include <sys/socketvar.h>
66 #include <net/if.h>
67 #include <net/netisr.h>
68
69 #include <cyg/infra/diag.h>
70 #include <cyg/hal/hal_intr.h>
71 #include <cyg/kernel/kapi.h>
72 #include <cyg/hal/hal_if.h>
73 #include <cyg/infra/cyg_ass.h>
74
75 #ifdef CYGPKG_NET_INET6
76 #include <netinet/in.h>
77 #include <netinet6/in6_var.h>
78 #endif
79
80 #if !CYGPKG_NET_DRIVER_FRAMEWORK   // Interface
81 #error At least one network driver framework must be defined!
82 #else
83 #include <cyg/io/eth/netdev.h>
84
85 // Define table boundaries
86 CYG_HAL_TABLE_BEGIN( __NETDEVTAB__, netdev );
87 CYG_HAL_TABLE_END( __NETDEVTAB_END__, netdev );
88 CYG_HAL_TABLE_BEGIN( __NET_INIT_TAB__, _Net_inits );
89 CYG_HAL_TABLE_END( __NET_INIT_TAB_END__, _Net_inits );
90 extern struct init_tab_entry __NET_INIT_TAB__[], __NET_INIT_TAB_END__;
91
92 // Used for system-wide "ticks per second"
93 #undef ticks
94 int hz = 100;
95 int tick = 10000;  // usec per "tick"
96 volatile struct timeval ktime;
97 int proc = 0;  // unused
98 struct proc * proc0 = 0;  // unused
99
100 volatile struct timeval mono_time;
101
102 // Low-level network debugging & logging
103 #ifdef CYGPKG_NET_FREEBSD_LOGGING
104 int cyg_net_log_mask = CYGPKG_NET_FREEBSD_LOGGING;
105 #endif
106
107 #define STACK_SIZE CYGNUM_NET_THREAD_STACKSIZE
108
109 static char netint_stack[STACK_SIZE];
110 static cyg_thread netint_thread_data;
111 static cyg_handle_t netint_thread_handle;
112
113 cyg_flag_t netint_flags;  
114 #define NETISR_ANY 0xFFFFFFFF  // Any possible bit...
115
116 extern void cyg_test_exit(void);  // TEMP
117 void
118 cyg_panic(const char *msg, ...)
119 {
120     cyg_uint32 old_ints;
121     CYG_FAIL( msg );
122     HAL_DISABLE_INTERRUPTS(old_ints);
123     diag_printf("PANIC: %s\n", msg);
124     cyg_test_exit();  // FIXME
125 }
126
127 #define NET_MEMPOOL_SIZE  roundup(CYGPKG_NET_MEMPOOL_SIZE,MSIZE)
128 #define NET_MBUFS_SIZE    roundup(CYGPKG_NET_MBUFS_SIZE,MSIZE)
129 #define NET_CLUSTERS_SIZE roundup(CYGPKG_NET_CLUSTERS_SIZE,MCLBYTES)
130
131 static unsigned char net_mempool_area[NET_MEMPOOL_SIZE];
132 static cyg_mempool_var net_mem_pool;
133 static cyg_handle_t    net_mem;
134 static unsigned char net_mbufs_area[NET_MBUFS_SIZE];
135 static cyg_mempool_fix net_mbufs_pool;
136 static cyg_handle_t    net_mbufs;
137 static unsigned char net_clusters_area[NET_CLUSTERS_SIZE];
138 static cyg_mempool_fix net_clusters_pool;
139 static cyg_handle_t    net_clusters;
140 static char            net_clusters_refcnt[(NET_CLUSTERS_SIZE/MCLBYTES)+1];
141 int nmbclusters = (NET_CLUSTERS_SIZE/MCLBYTES);
142
143 #ifdef CYGDBG_NET_TIMING_STATS
144 static struct net_stats  stats_malloc, stats_free, 
145     stats_memcpy, stats_memset,
146     stats_mbuf_alloc, stats_mbuf_free, stats_cluster_alloc;
147
148 // Display a number of ticks as microseconds
149 // Note: for improved calculation significance, values are kept in ticks*1000
150 static long rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION;
151 static long ns_per_system_clock;
152
153 static void
154 show_ticks_in_us(cyg_uint32 ticks)
155 {
156     long long ns;
157     ns_per_system_clock = 1000000/rtc_resolution[1];
158     ns = (ns_per_system_clock * ((long long)ticks * 1000)) / 
159         CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
160     ns += 5;  // for rounding to .01us
161     diag_printf("%7d.%02d", (int)(ns/1000), (int)((ns%1000)/10));
162 }
163
164 void
165 show_net_stats(struct net_stats *stats, const char *title)
166 {
167     int ave;
168     ave = stats->total_time / stats->count;
169     diag_printf("%s:\n", title);
170     diag_printf("  count: %6d", stats->count);
171     diag_printf(", min: ");
172     show_ticks_in_us(stats->min_time);
173     diag_printf(", max: ");
174     show_ticks_in_us(stats->max_time);
175     diag_printf(", total: ");
176     show_ticks_in_us(stats->total_time);
177     diag_printf(", ave: ");
178     show_ticks_in_us(ave);
179     diag_printf("\n");
180     // Reset stats
181     memset(stats, 0, sizeof(*stats));
182 }
183
184 void
185 show_net_times(void)
186 {
187     show_net_stats(&stats_malloc,        "Net malloc");
188     show_net_stats(&stats_free,          "Net free");
189     show_net_stats(&stats_mbuf_alloc,    "Mbuf alloc");
190     show_net_stats(&stats_mbuf_free,     "Mbuf free");
191     show_net_stats(&stats_cluster_alloc, "Cluster alloc");
192     show_net_stats(&stats_memcpy,        "Net memcpy");
193     show_net_stats(&stats_memset,        "Net memset");
194 }
195 #endif /* CYGDBG_NET_TIMING_STATS */ 
196
197 void *
198 cyg_net_malloc(u_long size, int type, int flags)
199 {
200     void *res;
201
202     START_STATS();
203     log(LOG_MDEBUG, "Net malloc[%ld] = ", size);
204     if (flags & M_NOWAIT) {
205         res = cyg_mempool_var_try_alloc(net_mem, size);
206     } else {
207         res = cyg_mempool_var_alloc(net_mem, size);
208     }
209     if ((flags & M_ZERO) && res) {
210       memset(res,0,size);
211     }
212     FINISH_STATS(stats_malloc);
213     log(LOG_MDEBUG, "%p\n", res);
214     return (res);
215 }
216
217 void 
218 cyg_net_free(caddr_t addr, int type)
219 {
220     START_STATS();
221     cyg_mempool_var_free(net_mem, addr);
222     FINISH_STATS(stats_free);
223 }
224
225 #ifdef CYGDBG_NET_SHOW_MBUFS
226
227 struct mbuf *mbinfo[300];
228
229 void cyg_net_show_mbufs(void)
230 {
231     int i;
232     diag_printf(" MBUF   : TYPE FLGS     DATA[LEN]   NEXT    NEXTPKT\n");
233     for( i = 0; i < 300; i++ )
234     {
235         struct mbuf *m = mbinfo[i];
236         char *type;
237         if( m == 0 ) continue;
238
239         switch( m->m_hdr.mh_type )
240         {
241         case MT_FREE: type="FREE"; break;
242         case MT_DATA: type="DATA"; break;
243         case MT_HEADER: type="HEADER"; break;
244         case MT_SONAME: type="SONAME"; break;
245         case MT_FTABLE: type="FTABLE"; break;
246         case MT_CONTROL: type="CONTROL"; break;
247         case MT_OOBDATA: type="OOBDATA"; break;
248         default: type="UNKNOWN"; break;
249         }
250
251         diag_printf("%p: %s %04x %p[%03d] %p %p\n",
252                     m, type,
253                     m->m_hdr.mh_flags,
254                     m->m_hdr.mh_data,
255                     m->m_hdr.mh_len,
256                     m->m_hdr.mh_next,
257                     m->m_hdr.mh_nextpkt);
258     }
259     diag_printf(" MBUF   : TYPE FLGS     DATA[LEN]   NEXT    NEXTPKT\n");    
260 }
261
262 #endif
263
264 void *
265 cyg_net_mbuf_alloc(void)
266 {
267     void *res;    
268
269     START_STATS();
270     log(LOG_MDEBUG, "Alloc mbuf = ");
271     res = cyg_mempool_fix_try_alloc(net_mbufs);
272 FINISH_STATS(stats_mbuf_alloc);
273 #ifdef CYGDBG_NET_SHOW_MBUFS    
274     {
275         int i;
276         for( i = 0; i < (sizeof(mbinfo)/sizeof(mbinfo[0])); i++ )
277             if( mbinfo[i] == 0 )
278             {
279                 mbinfo[i] = (struct mbuf *)res;
280                 break;
281             }
282     }
283 #endif
284     // Check that this nastiness works OK
285     CYG_ASSERT( dtom(res) == res, "dtom failed, base of mbuf" );
286     CYG_ASSERT( dtom((char *)res + MSIZE/2) == res, "dtom failed, mid mbuf" );
287     log(LOG_MDEBUG, "%p\n", res);
288     return (res);
289 }
290
291 void *
292 cyg_net_cluster_alloc(void)
293 {
294     void *res;
295
296     START_STATS();
297     log(LOG_MDEBUG, "Allocate cluster = ");
298     res = cyg_mempool_fix_try_alloc(net_clusters);
299     FINISH_STATS(stats_cluster_alloc);
300     log(LOG_MDEBUG, "%p\n", res);
301     return res;
302 }
303
304 static struct vm_zone *vm_zones = (struct vm_zone *)NULL;
305
306 vm_zone_t 
307 zinit(char *name, int size, int nentries, int flags, int zalloc)
308 {
309     void *res;
310     vm_zone_t zone = (vm_zone_t)0;
311     elem *p;
312
313     log(LOG_MDEBUG, "zinit '%s', size: %d, num: %d, flags: %d, alloc: %d\n", 
314         name, size, nentries, flags, zalloc);
315     res = cyg_mempool_var_try_alloc(net_mem, sizeof(struct vm_zone));
316     if (res) {
317         zone = (vm_zone_t)res;
318         res = cyg_mempool_var_try_alloc(net_mem, size*nentries);
319     }
320     if (!res) {
321         log(LOG_MDEBUG, "Can't allocate memory for %s\n", name);
322         panic("zinit: Out of memory\n");
323     }
324     p = (elem *)res;
325     zone->pool = (elem *)0;
326     zone->elem_size = size;
327     zone->name = name;
328     zone->free = zone->total = nentries;
329     zone->next = vm_zones;
330     zone->alloc_tries = zone->alloc_fails = zone->alloc_frees = 0;
331     vm_zones = zone;
332     while (nentries-- > 0) {
333         p->next = zone->pool;
334         zone->pool = p;
335         p = (elem *)((char *)p + size);
336     }
337     p = zone->pool;
338 #if 0
339     while (p) {
340         log(LOG_MDEBUG, "p: %p, next: %p\n", p, p->next);
341         p = p->next;
342     }
343 #endif
344     return zone;
345 }
346
347 void *    
348 zalloci(vm_zone_t zone)
349 {
350     elem *p;
351
352     p = zone->pool;
353     zone->alloc_tries++;
354     if (p) {
355         zone->pool = p->next;
356         zone->free--;        
357     } else {
358         zone->alloc_fails++;
359     }
360     log(LOG_MDEBUG, "zalloci from %s => %p\n", zone->name, p);
361     return (void *)p;
362 }
363
364 void      
365 zfreei(vm_zone_t zone, void *item)
366 {
367     elem *p = (elem *)item;
368
369     log(LOG_MDEBUG, "zfreei to %s <= %p\n", zone->name, p);
370     p->next = zone->pool;
371     zone->pool = p;
372     zone->free++;
373     zone->alloc_frees++;
374 }
375
376 static void
377 cyg_kmem_init(void)
378 {
379     unsigned char *p;
380 #ifdef CYGPKG_NET_DEBUG
381     diag_printf("Network stack using %d bytes for misc space\n", NET_MEMPOOL_SIZE);
382     diag_printf("                    %d bytes for mbufs\n", NET_MBUFS_SIZE);
383     diag_printf("                    %d bytes for mbuf clusters\n", NET_CLUSTERS_SIZE);
384 #endif
385     cyg_mempool_var_create(&net_mempool_area,
386                            NET_MEMPOOL_SIZE,
387                            &net_mem,
388                            &net_mem_pool);
389     // Align the mbufs on MSIZE boudaries so that dtom() can work.
390     p = (unsigned char *)(((long)(&net_mbufs_area) + MSIZE - 1) & ~(MSIZE-1));
391     cyg_mempool_fix_create(p,
392                            ((&(net_mbufs_area[NET_MBUFS_SIZE])) - p) & ~(MSIZE-1),
393                            MSIZE,
394                            &net_mbufs,
395                            &net_mbufs_pool);
396     cyg_mempool_fix_create(&net_clusters_area,
397                            NET_CLUSTERS_SIZE,
398                            MCLBYTES,
399                            &net_clusters,
400                            &net_clusters_pool);
401     mbutl = (struct mbuf *)&net_clusters_area;
402     mclrefcnt = net_clusters_refcnt;
403 }
404
405 void cyg_kmem_print_stats( void )
406 {
407     cyg_mempool_info info;
408     struct vm_zone *zone;
409
410     diag_printf( "Network stack mbuf stats:\n" );
411     diag_printf( "   mbufs %ld, clusters %ld, free clusters %ld\n",
412                  mbstat.m_mbufs,        /* mbufs obtained from page pool */
413                  mbstat.m_clusters,     /* clusters obtained from page pool */
414                  /* mbstat.m_spare, */  /* spare field */
415                  mbstat.m_clfree        /* free clusters */
416         );
417     diag_printf( "   Failed to get %ld times\n"
418                  "   Waited to get %ld times\n"
419                  "   Drained queues to get %ld times\n",
420                  mbstat.m_drops,        /* times failed to find space */
421                  mbstat.m_wait,         /* times waited for space */
422                  mbstat.m_drain         /* times drained protocols for space */
423                  /* mbstat.m_mtypes[256]; type specific mbuf allocations */
424         );
425
426     zone = vm_zones;
427     while (zone) {
428         diag_printf("VM zone '%s':\n", zone->name);
429         diag_printf("  Total: %d, Free: %d, Allocs: %d, Frees: %d, Fails: %d\n",
430                     zone->total, zone->free,
431                     zone->alloc_tries, zone->alloc_frees, zone->alloc_fails);
432         zone = zone->next;
433     }
434
435     cyg_mempool_var_get_info( net_mem, &info );
436     diag_printf( "Misc mpool: total %7d, free %7d, max free block %d\n",
437                  info.totalmem,
438                  info.freemem,
439                  info.maxfree
440         );
441
442     cyg_mempool_fix_get_info( net_mbufs, &info );
443     diag_printf( "Mbufs pool: total %7d, free %7d, blocksize %4d\n",
444                  info.totalmem,
445                  info.freemem,
446                  info.blocksize
447         );
448
449
450     cyg_mempool_fix_get_info( net_clusters, &info );
451     diag_printf( "Clust pool: total %7d, free %7d, blocksize %4d\n",
452                  info.totalmem,
453                  info.freemem,
454                  info.blocksize
455         );
456 }
457
458 // This API is for our own automated network tests.  It's not in any header
459 // files because it's not at all supported.
460 int cyg_net_get_mem_stats( int which, cyg_mempool_info *p )
461 {
462     CYG_CHECK_DATA_PTR( p, "Bad pointer to mempool_info" );
463     CYG_ASSERT( 0 <= which, "Mempool selector underflow" );
464     CYG_ASSERT( 2 >=which, "Mempool selector overflow" );
465     
466     if ( p )
467         switch ( which ) {
468         case 0:
469             cyg_mempool_var_get_info( net_mem, p );
470             break;
471         case 1:
472             cyg_mempool_fix_get_info( net_mbufs, p );
473             break;
474         case 2:
475             cyg_mempool_fix_get_info( net_clusters, p );
476             break;
477         default:
478             return 0;
479         }
480     return (int)p;
481 }
482
483 int
484 cyg_mtocl(u_long x)
485 {
486     int res;
487     res = (((u_long)(x) - (u_long)mbutl) >> MCLSHIFT);
488     return res;
489 }
490
491 struct mbuf *
492 cyg_cltom(u_long x)
493 {
494     struct mbuf *res;
495     res = (struct mbuf *)((caddr_t)((u_long)mbutl + ((u_long)(x) << MCLSHIFT)));
496     return res;
497 }
498
499 externC void 
500 net_memcpy(void *d, void *s, int n)
501 {
502     START_STATS();
503     memcpy(d, s, n);
504     FINISH_STATS(stats_memcpy);
505 }
506
507 externC void 
508 net_memset(void *s, int v, int n)
509 {
510     START_STATS();
511     memset(s, v, n);
512     FINISH_STATS(stats_memset);
513 }
514
515 // Rather than bring in the whole BSD 'random' code...
516 int
517 arc4random(void)
518 {
519     cyg_uint32 res;
520     static unsigned long seed = 0xDEADB00B;
521     HAL_CLOCK_READ(&res);  // Not so bad... (but often 0..N where N is small)
522     seed = ((seed & 0x007F00FF) << 7) ^
523         ((seed & 0x0F80FF00) >> 8) ^ // be sure to stir those low bits
524         (res << 13) ^ (res >> 9);    // using the clock too!
525     return (int)seed;
526 }
527
528 void 
529 get_random_bytes(void *buf, size_t len)
530 {
531     unsigned long ranbuf, *lp;
532     lp = (unsigned long *)buf;
533     while (len > 0) {
534         ranbuf = arc4random();
535         *lp++ = ranbuf;
536         len -= sizeof(ranbuf);
537     }
538 }
539
540 int
541 read_random_unlimited(void *buf, size_t len)
542 {
543     get_random_bytes(buf, len);
544     return len;
545 }
546
547 void read_random(void *buf, size_t len) 
548 {
549     CYG_ASSERT(0 == (len & ~3), "Only multiple of words allowed");
550   
551     get_random_bytes(buf, len);
552 }
553
554 void 
555 microtime(struct timeval *tp)
556 {
557     *tp = ktime;
558     log(LOG_DEBUG, "%s: = %ld.%ld\n", __FUNCTION__, tp->tv_sec, tp->tv_usec);
559     ktime.tv_usec++;  // In case clock isn't running yet
560 }
561
562 void 
563 getmicrotime(struct timeval *tp)
564 {
565     *tp = ktime;
566     log(LOG_DEBUG, "%s: = %ld.%ld\n", __FUNCTION__, tp->tv_sec, tp->tv_usec);
567     ktime.tv_usec++;  // In case clock isn't running yet
568 }
569
570 void 
571 getmicrouptime(struct timeval *tp)
572 {
573     *tp = ktime;
574     log(LOG_DEBUG, "%s: = %ld.%ld\n", __FUNCTION__, tp->tv_sec, tp->tv_usec);
575     ktime.tv_usec++;  // In case clock isn't running yet
576 }
577
578 // Taken from kern/kern_clock.c
579 /*
580  * Compute number of ticks in the specified amount of time.
581  */
582 #ifndef LONG_MAX
583 #define LONG_MAX 0x7FFFFFFF
584 #endif
585 int
586 tvtohz(struct timeval *tv)
587 {
588         register unsigned long ticks;
589         register long sec, usec;
590
591         /*
592          * If the number of usecs in the whole seconds part of the time
593          * difference fits in a long, then the total number of usecs will
594          * fit in an unsigned long.  Compute the total and convert it to
595          * ticks, rounding up and adding 1 to allow for the current tick
596          * to expire.  Rounding also depends on unsigned long arithmetic
597          * to avoid overflow.
598          *
599          * Otherwise, if the number of ticks in the whole seconds part of
600          * the time difference fits in a long, then convert the parts to
601          * ticks separately and add, using similar rounding methods and
602          * overflow avoidance.  This method would work in the previous
603          * case but it is slightly slower and assumes that hz is integral.
604          *
605          * Otherwise, round the time difference down to the maximum
606          * representable value.
607          *
608          * If ints have 32 bits, then the maximum value for any timeout in
609          * 10ms ticks is 248 days.
610          */
611         sec = tv->tv_sec;
612         usec = tv->tv_usec;
613         if (usec < 0) {
614                 sec--;
615                 usec += 1000000;
616         }
617         if (sec < 0) {
618 #ifdef DIAGNOSTIC
619                 if (usec > 0) {
620                         sec++;
621                         usec -= 1000000;
622                 }
623                 printf("tvotohz: negative time difference %ld sec %ld usec\n",
624                        sec, usec);
625 #endif
626                 ticks = 1;
627         } else if (sec <= LONG_MAX / 1000000)
628                 ticks = (sec * 1000000 + (unsigned long)usec + (tick - 1))
629                         / tick + 1;
630         else if (sec <= LONG_MAX / hz)
631                 ticks = sec * hz
632                         + ((unsigned long)usec + (tick - 1)) / tick + 1;
633         else
634                 ticks = LONG_MAX;
635         if (ticks > INT_MAX)
636                 ticks = INT_MAX;
637         return ((int)ticks);
638 }
639
640 void
641 get_mono_time(void)
642 {
643     panic("get_mono_time");
644 }
645
646 void 
647 csignal(pid_t pgid, int signum, uid_t uid, uid_t euid)
648 {
649     panic("csignal");
650 }
651
652 int
653 bcmp(const void *_p1, const void *_p2, size_t len)
654 {
655     int res = 0;
656     unsigned char *p1 = (unsigned char *)_p1;
657     unsigned char *p2 = (unsigned char *)_p2;
658     while (len-- > 0) {
659         res = *p1++ - *p2++;
660         if (res) break;
661     }
662     return res;
663 }
664
665 int
666 copyout(const void *s, void *d, size_t len)
667 {
668     memcpy(d, s, len);
669     return 0;
670 }
671
672 int
673 copyin(const void *s, void *d, size_t len)
674 {
675     memcpy(d, s, len);
676     return 0;
677 }
678
679 void
680 ovbcopy(const void *s, void *d, size_t len)
681 {
682     memmove(d, s, len);
683 }
684
685
686 // ------------------------------------------------------------------------
687 // THE NETWORK THREAD ITSELF
688 //
689 // Network software interrupt handler
690 //   This function is run as a separate thread to allow
691 // processing of network events (mostly incoming packets)
692 // at "user level" instead of at interrupt time.
693 //
694 // The actual handlers are 'registered' at system startup
695 //
696
697 // The set of handlers
698 static netisr_t *_netisr_handlers[NETISR_MAX+1];
699 struct ifqueue  ipintrq;
700 #ifdef INET6
701 struct ifqueue  ip6intrq;
702 #endif
703 char *hostname = "eCos_node";
704
705 // Register a 'netisr' handler for a given level
706 int 
707 register_netisr(int level, netisr_t *fun)
708 {
709     CYG_ASSERT(level <= NETISR_MAX, "invalid netisr level");
710     CYG_ASSERT(_netisr_handlers[level] == 0, "re-registered netisr");
711     _netisr_handlers[level] = fun;
712     return 0;  // ignored
713 }
714
715 //int unregister_netisr __P((int));
716
717 static void
718 cyg_netint(cyg_addrword_t param)
719 {
720     cyg_flag_value_t curisr;
721     int lvl, spl;
722
723     while (true) {
724         curisr = cyg_flag_wait(&netint_flags, NETISR_ANY, 
725                                CYG_FLAG_WAITMODE_OR|CYG_FLAG_WAITMODE_CLR);
726         spl = splsoftnet(); // Prevent any overlapping "stack" processing
727         for (lvl = NETISR_MIN;  lvl <= NETISR_MAX;  lvl++) {
728             if (curisr & (1<<lvl)) {
729                 if (NULL != _netisr_handlers[lvl])
730                     (*_netisr_handlers[lvl])();
731             }
732         }
733         splx(spl);
734     }
735 }
736
737
738 // This just sets one of the pseudo-ISR bits used above.
739 void
740 setsoftnet(void)
741 {
742     // This is called if we are out of MBUFs - it doesn't do anything, and
743     // that situation is handled OK, so don't bother with the diagnostic:
744
745     // diag_printf("setsoftnet\n");
746
747     // No need to do this because it is ignored anyway:
748     // schednetisr(NETISR_SOFTNET);
749 }
750
751
752 /* Update the kernel globel ktime. */
753 static void 
754 cyg_ktime_func(cyg_handle_t alarm,cyg_addrword_t data)
755 {
756     cyg_tick_count_t now = cyg_current_time();
757
758     ktime.tv_usec = (now % hz) * tick;
759     ktime.tv_sec = 1 + now / hz;
760 }
761
762 static void
763 cyg_ktime_init(void)
764 {
765     cyg_handle_t ktime_alarm_handle;
766     static cyg_alarm ktime_alarm;
767     cyg_handle_t counter;
768
769     // Do not start at 0 - net stack thinks 0 an invalid time;
770     // Have a valid time available from right now:
771     ktime.tv_usec = 0;
772     ktime.tv_sec = 1;
773
774     cyg_clock_to_counter(cyg_real_time_clock(),&counter);
775     cyg_alarm_create(counter,
776                      cyg_ktime_func,
777                      0,
778                      &ktime_alarm_handle,
779                      &ktime_alarm);
780
781     /* We want one alarm every 10ms. */
782     cyg_alarm_initialize(ktime_alarm_handle,cyg_current_time()+1,1);
783     cyg_alarm_enable(ktime_alarm_handle);
784 }
785
786 int
787 cyg_ticks(void)
788 {
789     cyg_tick_count_t now = cyg_current_time();
790     return (int)now;
791 }
792
793 //
794 // Network initialization
795 //   This function is called during system initialization to setup the whole
796 // networking environment.
797
798 // Linker magic to execute this function as 'init'
799 extern void cyg_do_net_init(void);
800
801 extern void ifinit(void);
802 extern void loopattach(int);
803 extern void bridgeattach(int);
804
805 // Internal init functions:
806 extern void cyg_alarm_timeout_init(void);
807 extern void cyg_tsleep_init(void);
808
809 static void
810 cyg_net_init_devs(void *ignored)
811 {
812     cyg_netdevtab_entry_t *t;
813     // Initialize all network devices
814     for (t = &__NETDEVTAB__[0]; t != &__NETDEVTAB_END__; t++) {
815         log(LOG_INIT, "Init device '%s'\n", t->name);
816         if (t->init(t)) {
817             t->status = CYG_NETDEVTAB_STATUS_AVAIL;
818         } else {
819             // What to do if device init fails?
820             t->status = 0;  // Device not [currently] available
821         }
822     }
823 #if 0  // Bridge code not available yet
824 #if NBRIDGE > 0
825     bridgeattach(0);
826 #endif
827 #endif
828 }
829 SYSINIT(devs, SI_SUB_DEVICES, SI_ORDER_FIRST, cyg_net_init_devs, NULL)
830
831 void
832 cyg_net_init(void)
833 {
834     static int _init = false;
835     struct init_tab_entry *init_entry;
836 #ifdef CYGPKG_NET_FORCE_SERIAL_CONSOLE
837     int orig_console =
838         CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
839 #endif
840
841     if (_init) return;
842
843 #ifdef CYGPKG_NET_FORCE_SERIAL_CONSOLE
844     // Force default serial console during system initialization
845     // This avoids problems with debug messages occurring while the
846     // networking subsystem is being setup.
847     CYGACC_CALL_IF_SET_CONSOLE_COMM(0);
848 #endif
849
850     cyg_do_net_init();  // Just forces linking in the initializer/constructor
851     // Initialize interrupt "flags"
852     cyg_flag_init(&netint_flags);
853     // Initialize timeouts and net service thread (pseudo-DSRs)
854     cyg_alarm_timeout_init();
855     // Initialize tsleep/wakeup support
856     cyg_tsleep_init();
857     // Initialize network memory system
858     cyg_kmem_init();
859     // Initialize network time
860     cyg_ktime_init();
861     // Create network background thread
862     cyg_thread_create(CYGPKG_NET_THREAD_PRIORITY, // Priority
863                       cyg_netint,               // entry
864                       0,                        // entry parameter
865                       "Network support",        // Name
866                       &netint_stack[0],         // Stack
867                       STACK_SIZE,               // Size
868                       &netint_thread_handle,    // Handle
869                       &netint_thread_data       // Thread data structure
870         );
871     cyg_thread_resume(netint_thread_handle);    // Start it
872
873     // Run through dynamic initializers
874     for (init_entry = __NET_INIT_TAB__; init_entry != &__NET_INIT_TAB_END__;  init_entry++) {
875         log(LOG_INIT, "[%s] Init: %s(%p)\n", __FUNCTION__, init_entry->name, init_entry->data);
876         (*init_entry->fun)(init_entry->data);
877     }
878     log(LOG_INIT, "[%s] Done\n", __FUNCTION__);
879
880     // Done
881     _init = true;
882
883 #ifdef CYGPKG_NET_FORCE_SERIAL_CONSOLE
884     // Revert to the original console, which might be a network connection
885     CYGACC_CALL_IF_SET_CONSOLE_COMM(orig_console);
886 #endif
887 }
888
889
890 #include <net/if.h>
891 #include <net/netdb.h>
892 #include <net/route.h>
893 externC void if_indextoname(int indx, char *buf, int len);
894
895 typedef void pr_fun(char *fmt, ...);
896
897 static void
898 _mask(struct sockaddr *sa, char *buf, int _len)
899 {
900     unsigned char *cp = ((unsigned char *)sa) + 4;
901     int len = sa->sa_len - 4;
902     int tot = 0;
903
904     while (len-- > 0) {
905         if (tot) *buf++ = '.';
906         buf += diag_sprintf(buf, "%u", *cp++);
907         tot++;
908     }
909
910     while (tot < 4) {
911         if (tot) *buf++ = '.';
912         buf += diag_sprintf(buf, "%d", 0);
913         tot++;
914     }
915 }
916
917 #ifdef CYGPKG_NET_INET6
918 static void
919 _mask6(struct sockaddr *sa, char *buf, int _len)
920 {
921   struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
922   int addrword = 0;
923   int bits = 0;
924   int index;
925
926   while (addrword < 4) {
927     if (sin6->sin6_addr.s6_addr32[addrword] == 0) {
928       break;
929     }
930     HAL_LSBIT_INDEX(index, sin6->sin6_addr.s6_addr32[addrword++]);
931     bits += (32-index);
932     if (index != 0) {
933       break;
934     }
935   }
936   diag_sprintf(buf, "%d", bits);
937 }
938 #endif
939 static void
940 _show_ifp(struct ifnet *ifp, pr_fun *pr)
941 {
942     struct ifaddr *ifa;
943     char name[64], addr[64], netmask[64], broadcast[64];
944
945     if_indextoname(ifp->if_index, name, 64);
946     TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
947         if (ifa->ifa_addr->sa_family != AF_LINK) {
948             (*pr)("%-8s", name);
949             getnameinfo (ifa->ifa_addr, ifa->ifa_addr->sa_len, addr, 
950                          sizeof(addr), 0, 0, NI_NUMERICHOST);
951             if (ifa->ifa_addr->sa_family == AF_INET) {
952               getnameinfo (ifa->ifa_dstaddr, ifa->ifa_dstaddr->sa_len, 
953                            broadcast, sizeof(broadcast), 
954                            0, 0, NI_NUMERICHOST);
955               _mask(ifa->ifa_netmask, netmask, 64);
956               (*pr)("IP: %s, Broadcast: %s, Netmask: %s\n", 
957                     addr, broadcast, netmask);
958             }
959 #ifdef CYGPKG_NET_INET6 
960             if (ifa->ifa_addr->sa_family == AF_INET6) {
961               struct in6_ifaddr * ifa6 = (struct in6_ifaddr *) ifa;
962               _mask6(ifa->ifa_netmask, netmask, 64);
963               (*pr)("IP: %s/%s   ", addr,netmask);
964               if (ifa6->ia6_flags & IN6_IFF_ANYCAST) (*pr) ("Anycast ");
965               if (ifa6->ia6_flags & IN6_IFF_TENTATIVE) (*pr) ("Tentative ");
966               if (ifa6->ia6_flags & IN6_IFF_DUPLICATED) (*pr) ("Duplicate ");
967               if (ifa6->ia6_flags & IN6_IFF_DETACHED) (*pr) ("Detached ");
968               if (ifa6->ia6_flags & IN6_IFF_DEPRECATED) (*pr) ("Deprecated ");
969               if (ifa6->ia6_flags & IN6_IFF_NODAD) (*pr) ("NoDAD ");
970               if (ifa6->ia6_flags & IN6_IFF_AUTOCONF) (*pr) ("AutoConf ");
971               if (ifa6->ia6_flags & IN6_IFF_TEMPORARY) (*pr) ("Tempory ");
972               if (ifa6->ia6_flags & IN6_IFF_HOME) (*pr) ("Home ");
973               (*pr) ("\n");
974             }
975 #endif
976             (*pr)("        ");
977             if ((ifp->if_flags & IFF_UP)) (*pr)("UP ");
978             if ((ifp->if_flags & IFF_BROADCAST)) (*pr)("BROADCAST ");
979             if ((ifp->if_flags & IFF_LOOPBACK)) (*pr)("LOOPBACK ");
980             if ((ifp->if_flags & IFF_RUNNING)) (*pr)("RUNNING ");
981             if ((ifp->if_flags & IFF_PROMISC)) (*pr)("PROMISC ");
982             if ((ifp->if_flags & IFF_MULTICAST)) (*pr)("MULTICAST ");
983             if ((ifp->if_flags & IFF_ALLMULTI)) (*pr)("ALLMULTI ");
984             (*pr)("MTU: %d, Metric: %d\n", ifp->if_mtu, ifp->if_metric);
985             (*pr)("        Rx - Packets: %d, Bytes: %d", 
986                   ifa->if_data.ifi_ipackets, ifa->if_data.ifi_ibytes);
987             (*pr)(", Tx - Packets: %d, Bytes: %d\n", 
988                   ifa->if_data.ifi_opackets, ifa->if_data.ifi_obytes);
989         }
990     }
991 }
992
993 static int
994 _dumpentry(struct radix_node *rn, void *vw)
995 {
996     struct rtentry *rt = (struct rtentry *)rn;
997     struct sockaddr *dst, *gate, *netmask, *genmask;
998     char addr[64], *cp;
999     pr_fun *pr = (pr_fun *)vw;
1000
1001     dst = rt_key(rt);
1002     gate = rt->rt_gateway;
1003     netmask = rt_mask(rt);
1004     genmask = rt->rt_genmask;
1005     if ((rt->rt_flags & (RTF_UP | RTF_WASCLONED)) == RTF_UP) {
1006         _inet_ntop(dst, addr, sizeof(addr));
1007         (*pr)("%-15s ", addr);
1008         if (gate != NULL) {
1009             _inet_ntop(gate, addr, sizeof(addr));
1010             (*pr)("%-15s ", addr);
1011         } else {
1012             (*pr)("%-15s ", " ");
1013         }
1014         if (netmask != NULL) {
1015             if (dst->sa_family == AF_INET) {
1016                 _mask(netmask, addr, sizeof(addr));
1017                 (*pr)("%-15s ", addr);
1018             } 
1019 #ifdef CYGPKG_NET_INET6
1020             if (dst->sa_family == AF_INET6) {
1021               _mask6(netmask, addr, sizeof(addr));
1022               (*pr)("/%-14s ", addr);
1023             }
1024 #endif
1025         } else {
1026             (*pr)("%-15s ", " ");
1027         }
1028         cp = addr;
1029         if ((rt->rt_flags & RTF_UP)) *cp++ = 'U';
1030         if ((rt->rt_flags & RTF_GATEWAY)) *cp++ = 'G';
1031         if ((rt->rt_flags & RTF_HOST)) *cp++ = 'H';
1032         if ((rt->rt_flags & RTF_REJECT)) *cp++ = '!';
1033         if ((rt->rt_flags & RTF_STATIC)) *cp++ = 'S';
1034         if ((rt->rt_flags & RTF_DYNAMIC)) *cp++ = 'D';
1035         if ((rt->rt_flags & RTF_MODIFIED)) *cp++ = 'M';
1036         *cp = '\0';
1037         (*pr)("%-8s ", addr);  // Flags
1038         if_indextoname(rt->rt_ifp->if_index, addr, 64);
1039         (*pr)("%-8s ", addr);
1040         (*pr)("\n");
1041     }
1042     return 0;
1043 }
1044
1045 void
1046 show_network_tables(pr_fun *pr)
1047 {
1048     int i, error;
1049     struct radix_node_head *rnh;
1050     struct ifnet *ifp;
1051
1052     cyg_scheduler_lock();
1053     (*pr)("Routing tables\n");
1054     (*pr)("Destination     Gateway         Mask            Flags    Interface\n");
1055     for (i = 1; i <= AF_MAX; i++) {
1056         if ((rnh = rt_tables[i]) != NULL) {
1057             error = rnh->rnh_walktree(rnh, _dumpentry, pr);
1058         }
1059     }
1060
1061     (*pr)("Interface statistics\n");
1062     for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
1063         _show_ifp(ifp, pr);
1064     }
1065     cyg_scheduler_unlock();
1066 }
1067
1068 #endif // CYGPKG_NET_DRIVER_FRAMEWORK
1069
1070 // EOF support.c
1071
1072
1073