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