1 //==========================================================================
5 // eCos wrapper and support functions
7 //==========================================================================
8 //####BSDCOPYRIGHTBEGIN####
10 // -------------------------------------------
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.
15 // -------------------------------------------
17 //####BSDCOPYRIGHTEND####
18 //==========================================================================
19 //#####DESCRIPTIONBEGIN####
21 // Author(s): gthomas, hmt
22 // Contributors: gthomas, hmt
28 //####DESCRIPTIONEND####
30 //==========================================================================
33 // Support routines, etc., used by network code
35 #include <sys/param.h>
36 #include <sys/malloc.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>
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>
51 #include <machine/cpu.h>
53 #include <pkgconf/net.h>
55 #include <cyg/infra/diag.h>
56 #include <cyg/hal/hal_intr.h>
57 #include <cyg/kernel/kapi.h>
59 #include <cyg/infra/cyg_ass.h>
61 #if !CYGPKG_NET_DRIVER_FRAMEWORK // Interface
62 #error At least one network driver framework must be defined!
64 #include <cyg/io/eth/netdev.h>
66 // Define table boundaries
67 CYG_HAL_TABLE_BEGIN( __NETDEVTAB__, netdev );
68 CYG_HAL_TABLE_END( __NETDEVTAB_END__, netdev );
70 // Used for system-wide "ticks per second"
72 int tick = 10000; // usec per "tick"
74 volatile struct timeval mono_time;
75 volatile struct timeval ktime;
77 // Low-level network debugging
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;
85 cyg_flag_t netint_flags;
86 #define NETISR_ANY 0xFFFFFFFF // Any possible bit...
88 extern void cyg_test_exit(void); // TEMP
90 cyg_panic(const char *msg, ...)
94 HAL_DISABLE_INTERRUPTS(old_ints);
95 diag_printf("PANIC: %s\n", msg);
96 cyg_test_exit(); // FIXME
100 // Round a number 'n' up to a multiple of 'm'
101 #define round(n,m) ((((n)+((m)-1))/(m))*(m))
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)
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];
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;
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;
130 show_ticks_in_us(cyg_uint32 ticks)
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));
141 show_net_stats(struct net_stats *stats, const char *title)
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);
157 memset(stats, 0, sizeof(*stats));
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");
172 #endif /* CYGDBG_NET_TIMING_STATS */
175 cyg_net_malloc(u_long size, int type, int flags)
179 if (flags & M_NOWAIT) {
180 res = cyg_mempool_var_try_alloc(net_mem, size);
182 res = cyg_mempool_var_alloc(net_mem, size);
184 FINISH_STATS(stats_malloc);
189 cyg_net_free(caddr_t addr, int type)
192 cyg_mempool_var_free(net_mem, addr);
193 FINISH_STATS(stats_free);
197 cyg_net_mbuf_alloc(int type, int flags)
202 if (flags & M_NOWAIT) {
203 res = cyg_mempool_fix_try_alloc(net_mbufs);
205 res = cyg_mempool_fix_alloc(net_mbufs);
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" );
215 cyg_net_mbuf_free(caddr_t addr, int type)
219 cyg_mempool_fix_free(net_mbufs, addr);
220 FINISH_STATS(stats_mbuf_free);
224 cyg_net_cluster_alloc(void)
228 res = cyg_mempool_fix_try_alloc(net_clusters);
229 FINISH_STATS(stats_cluster_alloc);
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);
242 cyg_mempool_var_create(&net_mempool_area,
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),
253 cyg_mempool_fix_create(&net_clusters_area,
258 mbutl = (struct mbuf *)&net_clusters_area;
259 mclrefcnt = net_clusters_refcnt;
262 void cyg_kmem_print_stats( void )
264 cyg_mempool_info info;
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 */
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 */
282 cyg_mempool_var_get_info( net_mem, &info );
283 diag_printf( "Misc mpool: total %7d, free %7d, max free block %d\n",
289 cyg_mempool_fix_get_info( net_mbufs, &info );
290 diag_printf( "Mbufs pool: total %7d, free %7d, blocksize %4d\n",
297 cyg_mempool_fix_get_info( net_clusters, &info );
298 diag_printf( "Clust pool: total %7d, free %7d, blocksize %4d\n",
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 )
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" );
316 cyg_mempool_var_get_info( net_mem, p );
319 cyg_mempool_fix_get_info( net_mbufs, p );
322 cyg_mempool_fix_get_info( net_clusters, p );
334 res = (((u_long)(x) - (u_long)mbutl) >> MCLSHIFT);
342 res = (struct mbuf *)((caddr_t)((u_long)mbutl + ((u_long)(x) << MCLSHIFT)));
347 net_memcpy(void *d, void *s, int n)
351 FINISH_STATS(stats_memcpy);
355 net_memset(void *s, int v, int n)
359 FINISH_STATS(stats_memset);
362 // Rather than bring in the whole BSD 'random' code...
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!
376 get_random_bytes(void *buf, size_t len)
378 unsigned long ranbuf, *lp;
379 lp = (unsigned long *)buf;
381 ranbuf = arc4random();
383 len -= sizeof(ranbuf);
388 microtime(struct timeval *tp)
396 panic("get_mono_time");
400 csignal(pid_t pgid, int signum, uid_t uid, uid_t euid)
406 bcmp(const void *_p1, const void *_p2, size_t len)
409 unsigned char *p1 = (unsigned char *)_p1;
410 unsigned char *p2 = (unsigned char *)_p2;
419 copyout(const void *s, void *d, size_t len)
426 copyin(const void *s, void *d, size_t len)
433 ovbcopy(const void *s, void *d, size_t len)
438 // ------------------------------------------------------------------------
439 // THE NETWORK THREAD ITSELF
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.
447 cyg_netint(cyg_addrword_t param)
449 cyg_flag_value_t curisr;
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
456 if (curisr & (1 << NETISR_ARP)) {
457 // Pending ARP requests
460 if (curisr & (1 << NETISR_IP)) {
461 // Pending IPv4 input
466 if (curisr & (1 << NETISR_IPV6)) {
467 // Pending IPv6 input
472 if (curisr & (1 << NETISR_BRIDGE)) {
473 // Pending bridge input
482 // This just sets one of the pseudo-ISR bits used above.
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:
489 // diag_printf("setsoftnet\n");
491 // No need to do this because it is ignored anyway:
492 // schednetisr(NETISR_SOFTNET);
496 /* Update the kernel globel ktime. */
498 cyg_ktime_func(cyg_handle_t alarm,cyg_addrword_t data)
500 cyg_tick_count_t now = cyg_current_time();
502 ktime.tv_usec = (now % hz) * tick;
503 ktime.tv_sec = 1 + now / hz;
509 cyg_handle_t ktime_alarm_handle;
510 static cyg_alarm ktime_alarm;
511 cyg_handle_t counter;
513 // Do not start at 0 - net stack thinks 0 an invalid time;
514 // Have a valid time available from right now:
518 cyg_clock_to_counter(cyg_real_time_clock(),&counter);
519 cyg_alarm_create(counter,
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);
531 // Network initialization
532 // This function is called during system initialization to setup the whole
533 // networking environment.
535 // Linker magic to execute this function as 'init'
536 extern void cyg_do_net_init(void);
538 extern void ifinit(void);
539 extern void loopattach(int);
540 extern void bridgeattach(int);
542 // Internal init functions:
543 extern void cyg_alarm_timeout_init(void);
544 extern void cyg_tsleep_init(void);
549 static int _init = false;
550 cyg_netdevtab_entry_t *t;
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
561 // Initialize network memory system
566 // Create network background thread
567 cyg_thread_create(CYGPKG_NET_THREAD_PRIORITY, // Priority
569 0, // entry parameter
570 "Network support", // Name
571 &netint_stack[0], // Stack
573 &netint_thread_handle, // Handle
574 &netint_thread_data // Thread data structure
576 cyg_thread_resume(netint_thread_handle); // Start it
578 // Initialize all network devices
579 for (t = &__NETDEVTAB__[0]; t != &__NETDEVTAB_END__; t++) {
580 // diag_printf("Init device '%s'\n", t->name);
582 t->status = CYG_NETDEVTAB_STATUS_AVAIL;
584 // What to do if device init fails?
585 t->status = 0; // Device not [currently] available
588 // And attach the loopback interface
589 #ifdef CYGPKG_NET_NLOOP
590 #if 0 < CYGPKG_NET_NLOOP
597 // Start up the network processing
605 // Copyright (C) 2002 Gary Thomas
608 #include <net/route.h>
609 #include <net/netdb.h>
610 externC void if_indextoname(int indx, char *buf, int len);
612 typedef void pr_fun(char *fmt, ...);
615 _mask(struct sockaddr *sa, char *buf, int _len)
617 char *cp = ((char *)sa) + 4;
618 int len = sa->sa_len - 4;
622 if (tot) *buf++ = '.';
623 buf += diag_sprintf(buf, "%d", *cp++);
628 if (tot) *buf++ = '.';
629 buf += diag_sprintf(buf, "%d", 0);
635 _show_ifp(struct ifnet *ifp, pr_fun *pr)
638 char addr[64], netmask[64], broadcast[64];
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);
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);
663 _dumpentry(struct radix_node *rn, void *vw)
665 struct rtentry *rt = (struct rtentry *)rn;
666 struct sockaddr *dst, *gate, *netmask, *genmask;
668 pr_fun *pr = (pr_fun *)vw;
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) {
678 _inet_ntop(dst, addr, sizeof(addr));
679 (*pr)("%-15s ", addr);
681 _inet_ntop(gate, addr, sizeof(addr));
682 (*pr)("%-15s ", addr);
684 (*pr)("%-15s ", " ");
686 if (netmask != NULL) {
687 _mask(netmask, addr, sizeof(addr));
688 (*pr)("%-15s ", addr);
690 (*pr)("%-15s ", " ");
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';
698 (*pr)("%-8s ", addr); // Flags
699 if_indextoname(rt->rt_ifp->if_index, addr, 64);
700 (*pr)("%-8s ", addr);
707 show_network_tables(pr_fun *pr)
710 struct radix_node_head *rnh;
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);
722 (*pr)("Interface statistics\n");
723 for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next) {
726 cyg_scheduler_unlock();
729 #endif // CYGPKG_NET_DRIVER_FRAMEWORK