source: rtems/cpukit/libnetworking/rtems/rtems_glue.c @ 02aaec7

4.104.114.95
Last change on this file since 02aaec7 was 02aaec7, checked in by Joel Sherrill <joel.sherrill@…>, on 08/18/08 at 21:42:41

2008-08-18 Joel Sherrill <joel.sherrill@…>

  • libnetworking/lib/ftpfs.c, libnetworking/libc/inet_ntoa.c, libnetworking/libc/rcmd.c, libnetworking/nfs/bootp_subr.c, libnetworking/rtems/rtems_glue.c, libnetworking/rtems/rtems_malloc_mbuf.c, libnetworking/rtems/rtems_showicmpstat.c, libnetworking/sys/malloc.h: Fix some warnings.
  • Property mode set to 100644
File size: 27.1 KB
Line 
1/*
2 *  $Id$
3 */
4
5#if HAVE_CONFIG_H
6#include "config.h"
7#endif
8
9#define RTEMS_FAST_MUTEX
10
11#ifdef RTEMS_FAST_MUTEX
12#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1
13#endif
14
15#include <string.h>
16#include <stdarg.h>
17#include <stdio.h>
18#include <errno.h>
19
20#include <rtems.h>
21#include <rtems/libio.h>
22#include <rtems/error.h>
23#include <rtems/rtems_bsdnet.h>
24#include <sys/types.h>
25#include <sys/param.h>
26#include <sys/domain.h>
27#include <sys/mbuf.h>
28#include <sys/socketvar.h>
29#include <sys/socket.h>
30#include <sys/sockio.h>
31#include <sys/callout.h>
32#include <sys/proc.h>
33#include <sys/ioctl.h>
34#include <net/if.h>
35#include <net/route.h>
36#include <netinet/in.h>
37#include <vm/vm.h>
38#include <arpa/inet.h>
39
40#include <net/netisr.h>
41#include <net/route.h>
42
43/*
44 * Sysctl init all.
45 */
46void sysctl_register_all(void *arg);
47
48/*
49 * Memory allocation
50 */
51static uint32_t nmbuf       = (64L * 1024L) / MSIZE;
52       uint32_t nmbclusters = (128L * 1024L) / MCLBYTES;
53
54/*
55 * Network task synchronization
56 */
57static rtems_id networkSemaphore;
58#ifdef RTEMS_FAST_MUTEX
59Semaphore_Control   *the_networkSemaphore;
60#endif
61static rtems_id networkDaemonTid;
62static uint32_t   networkDaemonPriority;
63static void networkDaemon (void *task_argument);
64
65/*
66 * Network timing
67 */
68int                     rtems_bsdnet_ticks_per_second;
69int                     rtems_bsdnet_microseconds_per_tick;
70
71/*
72 * Callout processing
73 */
74static rtems_interval   ticksWhenCalloutsLastChecked;
75struct callout *callfree = NULL;
76struct callout calltodo;
77
78/*
79 * FreeBSD variables
80 */
81int nfs_diskless_valid;
82
83/*
84 * BOOTP values
85 */
86struct in_addr rtems_bsdnet_log_host_address = {0};
87struct in_addr rtems_bsdnet_bootp_server_address = {0};
88char *rtems_bsdnet_bootp_boot_file_name = 0;
89char *rtems_bsdnet_bootp_server_name = 0;
90char *rtems_bsdnet_domain_name = 0;
91char *rtems_bsdnet_bootp_cmdline = 0;
92static struct in_addr _rtems_bsdnet_nameserver[sizeof rtems_bsdnet_config.name_server /
93                        sizeof rtems_bsdnet_config.name_server[0]];
94struct in_addr *rtems_bsdnet_nameserver = _rtems_bsdnet_nameserver;
95int rtems_bsdnet_nameserver_count = 0;
96static struct in_addr _rtems_bsdnet_ntpserver[sizeof rtems_bsdnet_config.ntp_server /
97                        sizeof rtems_bsdnet_config.ntp_server[0]];
98struct in_addr *rtems_bsdnet_ntpserver = _rtems_bsdnet_ntpserver;
99int rtems_bsdnet_ntpserver_count = 0;
100int32_t rtems_bsdnet_timeoffset = 0;
101
102/*
103 * Perform FreeBSD memory allocation.
104 * FIXME: This should be modified to keep memory allocation statistics.
105 */
106#undef malloc
107#undef free
108extern void *malloc (size_t);
109extern void free (void *);
110void *
111rtems_bsdnet_malloc (size_t size, int type, int flags)
112{
113        void *p;
114        int try = 0;
115
116        for (;;) {
117                p = malloc (size);
118                if (p || (flags & M_NOWAIT))
119                        return p;
120                rtems_bsdnet_semaphore_release ();
121                if (++try >= 30) {
122                        rtems_bsdnet_malloc_starvation();
123                        try = 0;
124                }
125        rtems_task_wake_after (rtems_bsdnet_ticks_per_second);
126                rtems_bsdnet_semaphore_obtain ();
127        }
128}
129
130/*
131 * Free FreeBSD memory
132 * FIXME: This should be modified to keep memory allocation statistics.
133 */
134void
135rtems_bsdnet_free (void *addr, int type)
136{
137        free (addr);
138}
139
140/*
141 * Externs for BSD data we have to access during initialization
142 */
143extern struct domain routedomain;
144extern struct domain inetdomain;
145
146/*
147 * Do the initializations required by the BSD code
148 */
149static int
150bsd_init (void)
151{
152        int i;
153        char *p;
154
155        /*
156         * Set up mbuf cluster data strutures
157         */
158        p = rtems_bsdnet_malloc_mbuf ((nmbclusters*MCLBYTES)+MCLBYTES-1, MBUF_MALLOC_NMBCLUSTERS);
159        if (p == NULL) {
160                printf ("Can't get network cluster memory.\n");
161                return -1;
162        }
163        p = (char *)(((intptr_t)p + (MCLBYTES-1)) & ~(MCLBYTES-1));
164        mbutl = (struct mbuf *)p;
165        for (i = 0; i < nmbclusters; i++) {
166                ((union mcluster *)p)->mcl_next = mclfree;
167                mclfree = (union mcluster *)p;
168                p += MCLBYTES;
169                mbstat.m_clfree++;
170        }
171        mbstat.m_clusters = nmbclusters;
172        mclrefcnt = rtems_bsdnet_malloc_mbuf (nmbclusters, MBUF_MALLOC_MCLREFCNT);
173        if (mclrefcnt == NULL) {
174                printf ("Can't get mbuf cluster reference counts memory.\n");
175                return -1;
176        }
177        memset (mclrefcnt, '\0', nmbclusters);
178
179        /*
180         * Set up mbuf data structures
181         */
182
183        p = rtems_bsdnet_malloc_mbuf(nmbuf * MSIZE + MSIZE - 1,MBUF_MALLOC_MBUF);
184        p = (char *)(((uintptr_t)p + MSIZE - 1) & ~(MSIZE - 1));
185        if (p == NULL) {
186                printf ("Can't get network memory.\n");
187                return -1;
188        }
189        for (i = 0; i < nmbuf; i++) {
190                ((struct mbuf *)p)->m_next = mmbfree;
191                mmbfree = (struct mbuf *)p;
192                p += MSIZE;
193        }
194        mbstat.m_mbufs = nmbuf;
195        mbstat.m_mtypes[MT_FREE] = nmbuf;
196
197        /*
198         * Set up domains
199         */
200        {
201
202        routedomain.dom_next = domains;
203        domains = &routedomain;
204        inetdomain.dom_next = domains;
205        domains = &inetdomain;
206        domaininit (NULL);
207        }
208
209  /*
210   * Setup the sysctl, normally done by a SYSINIT call.
211   */
212  sysctl_register_all(0);
213
214        /*
215         * Set up interfaces
216         */
217        ifinit (NULL);
218        return 0;
219}
220
221/*
222 * RTEMS Specific Helper Routines
223 */
224extern void rtems_set_udp_buffer_sizes( u_long, u_long );
225extern void rtems_set_tcp_buffer_sizes( u_long, u_long );
226extern void rtems_set_sb_efficiency( u_long );
227
228/*
229 * Initialize and start network operations
230 */
231static int
232rtems_bsdnet_initialize (void)
233{
234        rtems_status_code sc;
235
236        /*
237         * Set the priority of all network tasks
238         */
239        if (rtems_bsdnet_config.network_task_priority == 0)
240                networkDaemonPriority = 100;
241        else
242                networkDaemonPriority = rtems_bsdnet_config.network_task_priority;
243
244        /*
245         * Set the memory allocation limits
246         */
247        if (rtems_bsdnet_config.mbuf_bytecount)
248                nmbuf = rtems_bsdnet_config.mbuf_bytecount / MSIZE;
249        if (rtems_bsdnet_config.mbuf_cluster_bytecount)
250                nmbclusters = rtems_bsdnet_config.mbuf_cluster_bytecount / MCLBYTES;
251
252        rtems_set_udp_buffer_sizes(
253          rtems_bsdnet_config.udp_tx_buf_size,
254          rtems_bsdnet_config.udp_rx_buf_size
255        );
256
257        rtems_set_tcp_buffer_sizes(
258          rtems_bsdnet_config.tcp_tx_buf_size,
259          rtems_bsdnet_config.tcp_rx_buf_size
260        );
261
262        rtems_set_sb_efficiency( rtems_bsdnet_config.sb_efficiency );
263
264        /*
265         * Create the task-synchronization semaphore
266         */
267        sc = rtems_semaphore_create (rtems_build_name('B', 'S', 'D', 'n'),
268                                        0,
269                                        RTEMS_PRIORITY |
270                                                RTEMS_BINARY_SEMAPHORE |
271                                                RTEMS_INHERIT_PRIORITY |
272                                                RTEMS_NO_PRIORITY_CEILING |
273                                                RTEMS_LOCAL,
274                                        0,
275                                        &networkSemaphore);
276        if (sc != RTEMS_SUCCESSFUL) {
277                printf ("Can't create network seamphore: `%s'\n", rtems_status_text (sc));
278                return -1;
279        }
280#ifdef RTEMS_FAST_MUTEX
281        {
282        Objects_Locations location;
283        the_networkSemaphore = _Semaphore_Get( networkSemaphore, &location );
284        _Thread_Enable_dispatch();
285        }
286#endif
287
288        /*
289         * Compute clock tick conversion factors
290         */
291        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &rtems_bsdnet_ticks_per_second);
292        if (rtems_bsdnet_ticks_per_second <= 0)
293                rtems_bsdnet_ticks_per_second = 1;
294        rtems_bsdnet_microseconds_per_tick = 1000000 / rtems_bsdnet_ticks_per_second;
295
296        /*
297         * Ensure that `seconds' is greater than 0
298         */
299    while (rtems_bsdnet_seconds_since_boot() == 0)
300        rtems_task_wake_after(1);
301
302        /*
303         * Set up BSD-style sockets
304         */
305        if (bsd_init () < 0)
306                return -1;
307
308        /*
309         * Start network daemon
310         */
311        networkDaemonTid = rtems_bsdnet_newproc ("ntwk", 4096, networkDaemon, NULL);
312
313        /*
314         * Let other network tasks begin
315         */
316        rtems_bsdnet_semaphore_release ();
317        return 0;
318}
319
320/*
321 * Obtain network mutex
322 */
323void
324rtems_bsdnet_semaphore_obtain (void)
325{
326#ifdef RTEMS_FAST_MUTEX
327        ISR_Level level;
328        _ISR_Disable (level);
329        _CORE_mutex_Seize (
330                &the_networkSemaphore->Core_control.mutex,
331                networkSemaphore,
332                1,              /* wait */
333                0,              /* forever */
334                level
335                );
336        if (_Thread_Executing->Wait.return_code)
337                rtems_panic ("rtems-net: can't obtain network sema: %d\n",
338                 _Thread_Executing->Wait.return_code);
339#else
340        rtems_status_code sc;
341
342        sc = rtems_semaphore_obtain (networkSemaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
343        if (sc != RTEMS_SUCCESSFUL)
344                rtems_panic ("rtems-net: can't obtain network semaphore: `%s'\n",
345                 rtems_status_text (sc));
346#endif
347}
348
349/*
350 * Release network mutex
351 */
352void
353rtems_bsdnet_semaphore_release (void)
354{
355#ifdef RTEMS_FAST_MUTEX
356        int i;
357
358        _Thread_Disable_dispatch();
359        i = _CORE_mutex_Surrender (
360                &the_networkSemaphore->Core_control.mutex,
361                networkSemaphore,
362                NULL
363                );
364        _Thread_Enable_dispatch();
365        if (i)
366                rtems_panic ("rtems-net: can't release network sema: %i\n");
367#else
368        rtems_status_code sc;
369
370        sc = rtems_semaphore_release (networkSemaphore);
371        if (sc != RTEMS_SUCCESSFUL)
372                rtems_panic ("rtems-net: can't release network semaphore: `%s'\n",
373                 rtems_status_text (sc));
374#endif
375}
376
377/*
378 * Wait for something to happen to a socket buffer
379 */
380int
381sbwait(sb)
382        struct sockbuf *sb;
383{
384        rtems_event_set events;
385        rtems_id tid;
386        rtems_status_code sc;
387
388        /*
389         * Soak up any pending events.
390         * The sleep/wakeup synchronization in the FreeBSD
391         * kernel has no memory.
392         */
393        rtems_event_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events);
394
395        /*
396         * Set this task as the target of the wakeup operation.
397         */
398        rtems_task_ident (RTEMS_SELF, 0, &tid);
399        sb->sb_sel.si_pid = tid;
400
401        /*
402         * Show that socket is waiting
403         */
404        sb->sb_flags |= SB_WAIT;
405
406        /*
407         * Release the network semaphore.
408         */
409        rtems_bsdnet_semaphore_release ();
410
411        /*
412         * Wait for the wakeup event.
413         */
414        sc = rtems_event_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, sb->sb_timeo, &events);
415
416        /*
417         * Reobtain the network semaphore.
418         */
419        rtems_bsdnet_semaphore_obtain ();
420
421        /*
422         * Return the status of the wait.
423         */
424        switch (sc) {
425        case RTEMS_SUCCESSFUL:  return 0;
426        case RTEMS_TIMEOUT:     return EWOULDBLOCK;
427        default:                return ENXIO;
428        }
429}
430
431
432/*
433 * Wake up the task waiting on a socket buffer.
434 */
435void
436sowakeup(so, sb)
437        register struct socket *so;
438        register struct sockbuf *sb;
439{
440        if (sb->sb_flags & SB_WAIT) {
441                sb->sb_flags &= ~SB_WAIT;
442                rtems_event_send (sb->sb_sel.si_pid, SBWAIT_EVENT);
443        }
444        if (sb->sb_wakeup) {
445                (*sb->sb_wakeup) (so, sb->sb_wakeuparg);
446        }
447}
448
449/*
450 * For now, a socket can be used by only one task at a time.
451 */
452int
453sb_lock(sb)
454        register struct sockbuf *sb;
455{
456        rtems_panic ("Socket buffer is already in use.");
457        return 0;
458}
459void
460wakeup (void *p)
461{
462        rtems_panic ("Wakeup called");
463}
464
465/*
466 * Wait for a connection/disconnection event.
467 */
468int
469soconnsleep (struct socket *so)
470{
471        rtems_event_set events;
472        rtems_id tid;
473        rtems_status_code sc;
474
475        /*
476         * Soak up any pending events.
477         * The sleep/wakeup synchronization in the FreeBSD
478         * kernel has no memory.
479         */
480        rtems_event_receive (SOSLEEP_EVENT, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events);
481
482        /*
483         * Set this task as the target of the wakeup operation.
484         */
485        if (so->so_pgid)
486                rtems_panic ("Another task is already sleeping on that socket");
487        rtems_task_ident (RTEMS_SELF, 0, &tid);
488        so->so_pgid = tid;
489
490        /*
491         * Wait for the wakeup event.
492         */
493        sc = rtems_bsdnet_event_receive (SOSLEEP_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, so->so_rcv.sb_timeo, &events);
494
495        /*
496         * Relinquish ownership of the socket.
497         */
498        so->so_pgid = 0;
499
500        switch (sc) {
501        case RTEMS_SUCCESSFUL:  return 0;
502        case RTEMS_TIMEOUT:     return EWOULDBLOCK;
503        default:                return ENXIO;
504        }
505}
506
507/*
508 * Wake up a task waiting for a connection/disconnection to complete.
509 */
510void
511soconnwakeup (struct socket *so)
512{
513        if (so->so_pgid)
514                rtems_event_send (so->so_pgid, SOSLEEP_EVENT);
515}
516
517/*
518 * Send an event to the network daemon.
519 * This corresponds to sending a software interrupt in the BSD kernel.
520 */
521void
522rtems_bsdnet_schednetisr (int n)
523{
524        rtems_event_send (networkDaemonTid, 1 << n);
525}
526
527/*
528 * The network daemon
529 * This provides a context to run BSD software interrupts
530 */
531static void
532networkDaemon (void *task_argument)
533{
534        rtems_status_code sc;
535        rtems_event_set events;
536        rtems_interval now;
537        int ticksPassed;
538        uint32_t   timeout;
539        struct callout *c;
540
541        for (;;) {
542                c = calltodo.c_next;
543                if (c)
544                        timeout = c->c_time;
545                else
546                        timeout = RTEMS_NO_TIMEOUT;
547
548                sc = rtems_bsdnet_event_receive (NETISR_EVENTS,
549                                                RTEMS_EVENT_ANY | RTEMS_WAIT,
550                                                timeout,
551                                                &events);
552                if ( sc == RTEMS_SUCCESSFUL ) {
553                        if (events & NETISR_IP_EVENT)
554                                ipintr ();
555                        if (events & NETISR_ARP_EVENT)
556                                arpintr ();
557                }
558
559                rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
560                ticksPassed = now - ticksWhenCalloutsLastChecked;
561                if (ticksPassed != 0) {
562                        ticksWhenCalloutsLastChecked = now;
563
564                        c = calltodo.c_next;
565                        if (c) {
566                                c->c_time -= ticksPassed;
567                                while ((c = calltodo.c_next) != NULL && c->c_time <= 0) {
568                                        void *arg;
569                                        void (*func) (void *);
570
571                                        func = c->c_func;
572                                        arg = c->c_arg;
573                                        calltodo.c_next = c->c_next;
574                                        c->c_next = callfree;
575                                        callfree = c;
576                                        (*func)(arg);
577                                }
578                        }
579                }
580        }
581}
582
583/*
584 * Structure passed to task-start stub
585 */
586struct newtask {
587        void (*entry)(void *);
588        void *arg;
589};
590
591/*
592 * Task-start stub
593 */
594static void
595taskEntry (rtems_task_argument arg)
596{
597        struct newtask t;
598
599        /*
600         * Pick up task information and free
601         * the memory allocated to pass the
602         * information to this task.
603         */
604        t = *(struct newtask *)arg;
605        free ((struct newtask *)arg);
606
607        /*
608         * Enter the competition for the network semaphore
609         */
610        rtems_bsdnet_semaphore_obtain ();
611
612        /*
613         * Enter the task
614         */
615        (*t.entry)(t.arg);
616        rtems_panic ("Network task returned!\n");
617}
618
619/*
620 * Start a network task
621 */
622rtems_id
623rtems_bsdnet_newproc (char *name, int stacksize, void(*entry)(void *), void *arg)
624{
625        struct newtask *t;
626        char nm[4];
627        rtems_id tid;
628        rtems_status_code sc;
629
630        strncpy (nm, name, 4);
631        sc = rtems_task_create (rtems_build_name(nm[0], nm[1], nm[2], nm[3]),
632                networkDaemonPriority,
633                stacksize,
634                RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0),
635                RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL,
636                &tid);
637        if (sc != RTEMS_SUCCESSFUL)
638                rtems_panic ("Can't create network daemon `%s': `%s'\n", name, rtems_status_text (sc));
639
640        /*
641         * Set up task arguments
642         */
643        t = malloc (sizeof *t);
644        t->entry = entry;
645        t->arg = arg;
646
647        /*
648         * Start the task
649         */
650        sc = rtems_task_start (tid, taskEntry, (rtems_task_argument)t);
651        if (sc != RTEMS_SUCCESSFUL)
652                rtems_panic ("Can't start network daemon `%s': `%s'\n", name, rtems_status_text (sc));
653
654        /*
655         * Let our caller know the i.d. of the new task
656         */
657        return tid;
658}
659
660rtems_status_code rtems_bsdnet_event_receive (
661  rtems_event_set  event_in,
662  rtems_option     option_set,
663  rtems_interval   ticks,
664  rtems_event_set *event_out)
665{
666        rtems_status_code sc;
667
668        rtems_bsdnet_semaphore_release ();
669        sc = rtems_event_receive (event_in, option_set, ticks, event_out);
670        rtems_bsdnet_semaphore_obtain ();
671        return sc;
672}
673
674/*
675 * Return time since startup
676 */
677void
678microtime (struct timeval *t)
679{
680        rtems_interval now;
681
682        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
683        t->tv_sec = now / rtems_bsdnet_ticks_per_second;
684        t->tv_usec = (now % rtems_bsdnet_ticks_per_second) * rtems_bsdnet_microseconds_per_tick;
685}
686
687unsigned long
688rtems_bsdnet_seconds_since_boot (void)
689{
690        rtems_interval now;
691
692        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
693        return now / rtems_bsdnet_ticks_per_second;
694}
695
696/*
697 * Fake random number generator
698 */
699unsigned long
700rtems_bsdnet_random (void)
701{
702        rtems_interval now;
703
704        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
705        return (now * 99991);
706}
707
708/*
709 * Callout list processing
710 */
711void
712rtems_bsdnet_timeout(void (*ftn)(void *), void *arg, int ticks)
713{
714        register struct callout *new, *p, *t;
715
716        if (ticks <= 0)
717                ticks = 1;
718
719        /* Fill in the next free callout structure. */
720        if (callfree == NULL) {
721                callfree = malloc (sizeof *callfree);
722                if (callfree == NULL)
723                        rtems_panic ("No memory for timeout table entry");
724                callfree->c_next = NULL;
725        }
726
727        new = callfree;
728        callfree = new->c_next;
729        new->c_arg = arg;
730        new->c_func = ftn;
731
732        /*
733         * The time for each event is stored as a difference from the time
734         * of the previous event on the queue.  Walk the queue, correcting
735         * the ticks argument for queue entries passed.  Correct the ticks
736         * value for the queue entry immediately after the insertion point
737         * as well.  Watch out for negative c_time values; these represent
738         * overdue events.
739         */
740        for (p = &calltodo;
741            (t = p->c_next) != NULL && ticks > t->c_time; p = t)
742                if (t->c_time > 0)
743                        ticks -= t->c_time;
744        new->c_time = ticks;
745        if (t != NULL)
746                t->c_time -= ticks;
747
748        /* Insert the new entry into the queue. */
749        p->c_next = new;
750        new->c_next = t;
751}
752
753/*
754 * Ticks till specified time
755 * XXX: This version worries only about seconds, but that's good
756 * enough for the way the network code uses this routine.
757 */
758int
759hzto(struct timeval *tv)
760{
761        long diff = tv->tv_sec - rtems_bsdnet_seconds_since_boot();
762
763        if (diff <= 0)
764                return 1;
765        return diff * rtems_bsdnet_ticks_per_second;
766}
767
768/*
769 * Kernel debugging
770 */
771int rtems_bsdnet_log_priority;
772void
773rtems_bsdnet_log (int priority, const char *fmt, ...)
774{
775        va_list args;
776
777        if (priority & rtems_bsdnet_log_priority) {
778                va_start (args, fmt);
779                vprintf (fmt, args);
780                va_end (args);
781        }
782}
783
784/*
785 * IP header checksum routine for processors which don't have an inline version
786 */
787u_int
788in_cksum_hdr (const void *ip)
789{
790        uint32_t   sum;
791        const uint16_t   *sp;
792        int i;
793
794        sum = 0;
795        sp = (uint16_t   *)ip;
796        for (i = 0 ; i < 10 ; i++)
797                sum += *sp++;
798        while (sum > 0xFFFF)
799                sum = (sum & 0xffff) + (sum >> 16);
800        return ~sum & 0xFFFF;
801}
802
803/*
804 * Manipulate routing tables
805 */
806int rtems_bsdnet_rtrequest (
807    int req,
808    struct sockaddr *dst,
809    struct sockaddr *gateway,
810    struct sockaddr *netmask,
811    int flags,
812    struct rtentry **net_nrt)
813{
814        int error;
815
816        rtems_bsdnet_semaphore_obtain ();
817        error = rtrequest (req, dst, gateway, netmask, flags, net_nrt);
818        rtems_bsdnet_semaphore_release ();
819        if (error) {
820                errno = error;
821                return -1;
822        }
823        return 0;
824}
825
826static int
827rtems_bsdnet_setup (void)
828{
829        struct rtems_bsdnet_ifconfig *ifp;
830        short flags;
831        struct sockaddr_in address;
832        struct sockaddr_in netmask;
833        struct sockaddr_in broadcast;
834        struct sockaddr_in gateway;
835        int i;
836        int any_if_configured = 0;
837
838        /*
839         * Set local parameters
840         */
841        if (rtems_bsdnet_config.hostname)
842                sethostname (rtems_bsdnet_config.hostname,
843                                        strlen (rtems_bsdnet_config.hostname));
844        if (rtems_bsdnet_config.domainname)
845                rtems_bsdnet_domain_name =
846                                        strdup (rtems_bsdnet_config.domainname);
847        if (rtems_bsdnet_config.log_host)
848                rtems_bsdnet_log_host_address.s_addr =
849                                inet_addr (rtems_bsdnet_config.log_host);
850        for (i = 0 ; i < sizeof rtems_bsdnet_config.name_server /
851                        sizeof rtems_bsdnet_config.name_server[0] ; i++) {
852                if (!rtems_bsdnet_config.name_server[i])
853                        break;
854                rtems_bsdnet_nameserver[rtems_bsdnet_nameserver_count++].s_addr
855                        = inet_addr (rtems_bsdnet_config.name_server[i]);
856        }
857        for (i = 0 ; i < sizeof rtems_bsdnet_config.ntp_server /
858                        sizeof rtems_bsdnet_config.ntp_server[0] ; i++) {
859                if (!rtems_bsdnet_config.ntp_server[i])
860                        break;
861                rtems_bsdnet_ntpserver[rtems_bsdnet_ntpserver_count++].s_addr
862                        = inet_addr (rtems_bsdnet_config.ntp_server[i]);
863        }
864
865        /*
866         * Configure interfaces
867         */
868        for (ifp = rtems_bsdnet_config.ifconfig ; ifp ; ifp = ifp->next) {
869                if (ifp->ip_address == NULL)
870                        continue;
871
872                /*
873                 * Bring interface up
874                 */
875                flags = IFF_UP;
876                if (rtems_bsdnet_ifconfig (ifp->name, SIOCSIFFLAGS, &flags) < 0) {
877                        printf ("Can't bring %s up: %s\n", ifp->name, strerror (errno));
878                        continue;
879                }
880
881                /*
882                 * Set interface netmask
883                 */
884                memset (&netmask, '\0', sizeof netmask);
885                netmask.sin_len = sizeof netmask;
886                netmask.sin_family = AF_INET;
887                netmask.sin_addr.s_addr = inet_addr (ifp->ip_netmask);
888                if (rtems_bsdnet_ifconfig (ifp->name, SIOCSIFNETMASK, &netmask) < 0) {
889                        printf ("Can't set %s netmask: %s\n", ifp->name, strerror (errno));
890                        continue;
891                }
892
893                /*
894                 * Set interface address
895                 */
896                memset (&address, '\0', sizeof address);
897                address.sin_len = sizeof address;
898                address.sin_family = AF_INET;
899                address.sin_addr.s_addr = inet_addr (ifp->ip_address);
900                if (rtems_bsdnet_ifconfig (ifp->name, SIOCSIFADDR, &address) < 0) {
901                        printf ("Can't set %s address: %s\n", ifp->name, strerror (errno));
902                        continue;
903                }
904
905                /*
906                 * Set interface broadcast address if the interface has the
907                 * broadcast flag set.
908                 */
909                if (rtems_bsdnet_ifconfig (ifp->name, SIOCGIFFLAGS, &flags) < 0) {
910                        printf ("Can't read %s flags: %s\n", ifp->name, strerror (errno));
911                        continue;
912                }
913
914                any_if_configured = 1;
915
916                if (flags & IFF_BROADCAST) {
917                        memset (&broadcast, '\0', sizeof broadcast);
918                        broadcast.sin_len = sizeof broadcast;
919                        broadcast.sin_family = AF_INET;
920                        broadcast.sin_addr.s_addr =
921                                        address.sin_addr.s_addr | ~netmask.sin_addr.s_addr;
922                        if (rtems_bsdnet_ifconfig (ifp->name, SIOCSIFBRDADDR, &broadcast) < 0) {
923                                struct in_addr  in_addr;
924                                char                    buf[20];
925                                in_addr.s_addr = broadcast.sin_addr.s_addr;
926                                if (!inet_ntop(AF_INET, &in_addr, buf, sizeof(buf)))
927                                                strcpy(buf,"?.?.?.?");
928                                printf ("Can't set %s broadcast address %s: %s\n",
929                                        ifp->name, buf, strerror (errno));
930                        }
931                }
932        }
933
934        /*
935         * Set default route
936         */
937        if (rtems_bsdnet_config.gateway && any_if_configured) {
938                address.sin_addr.s_addr = INADDR_ANY;
939                netmask.sin_addr.s_addr = INADDR_ANY;
940                memset (&gateway, '\0', sizeof gateway);
941                gateway.sin_len = sizeof gateway;
942                gateway.sin_family = AF_INET;
943                gateway.sin_addr.s_addr = inet_addr (rtems_bsdnet_config.gateway);
944                if (rtems_bsdnet_rtrequest (
945                                RTM_ADD,
946                                (struct sockaddr *)&address,
947                                (struct sockaddr *)&gateway,
948                                (struct sockaddr *)&netmask,
949                                (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL) < 0) {
950                        printf ("Can't set default route: %s\n", strerror (errno));
951                        return -1;
952                }
953        }
954        return 0;
955}
956
957/*
958 * Initialize the network
959 */
960int
961rtems_bsdnet_initialize_network (void)
962{
963        struct rtems_bsdnet_ifconfig *ifp;
964
965        /*
966         * Start network tasks.
967         * Initialize BSD network data structures.
968         */
969        if (rtems_bsdnet_initialize () < 0)
970                return -1;
971
972        /*
973         * Attach interfaces
974         */
975        for (ifp = rtems_bsdnet_config.ifconfig ; ifp ; ifp = ifp->next) {
976                rtems_bsdnet_attach (ifp);
977        }
978
979        /*
980         * Bring up the network
981         */
982        if (rtems_bsdnet_setup () < 0)
983                return -1;
984        if (rtems_bsdnet_config.bootp)
985                (*rtems_bsdnet_config.bootp)();
986        return 0;
987}
988
989/*
990 * Attach a network interface.
991 */
992void rtems_bsdnet_attach (struct rtems_bsdnet_ifconfig *ifp)
993{
994        if (ifp) {
995                rtems_bsdnet_semaphore_obtain ();
996                (ifp->attach)(ifp, 1);
997                rtems_bsdnet_semaphore_release ();
998        }
999}
1000
1001/*
1002 * Detach a network interface.
1003 */
1004void rtems_bsdnet_detach (struct rtems_bsdnet_ifconfig *ifp)
1005{
1006        if (ifp) {
1007                rtems_bsdnet_semaphore_obtain ();
1008                (ifp->attach)(ifp, 0);
1009                rtems_bsdnet_semaphore_release ();
1010        }
1011}
1012
1013/*
1014 * Interface Configuration.
1015 */
1016int rtems_bsdnet_ifconfig (const char *ifname, uint32_t   cmd, void *param)
1017{
1018        int s, r = 0;
1019        struct ifreq ifreq;
1020
1021        /*
1022         * Configure interfaces
1023         */
1024        s = socket (AF_INET, SOCK_DGRAM, 0);
1025        if (s < 0)
1026                return -1;
1027
1028        strncpy (ifreq.ifr_name, ifname, IFNAMSIZ);
1029
1030        rtems_bsdnet_semaphore_obtain ();
1031
1032        switch (cmd) {
1033                case SIOCSIFADDR:
1034                case SIOCSIFNETMASK:
1035                        memcpy (&ifreq.ifr_addr, param, sizeof (struct sockaddr));
1036                        r = ioctl (s, cmd, &ifreq);
1037                        break;
1038
1039                case OSIOCGIFADDR:
1040                case SIOCGIFADDR:
1041                case OSIOCGIFNETMASK:
1042                case SIOCGIFNETMASK:
1043                        if ((r = ioctl (s, cmd, &ifreq)) < 0)
1044                                break;
1045                        memcpy (param, &ifreq.ifr_addr, sizeof (struct sockaddr));
1046                        break;
1047
1048                case SIOCGIFFLAGS:
1049                case SIOCSIFFLAGS:
1050                        if ((r = ioctl (s, SIOCGIFFLAGS, &ifreq)) < 0)
1051                                break;
1052                        if (cmd == SIOCGIFFLAGS) {
1053                                *((short*) param) = ifreq.ifr_flags;
1054                                break;
1055                        }
1056                        ifreq.ifr_flags |= *((short*) param);
1057                        if ( (*((short*) param) & IFF_UP ) == 0 ) {
1058                            /* set the interface down */
1059                            ifreq.ifr_flags &= ~(IFF_UP);
1060                        }
1061                        r = ioctl (s, SIOCSIFFLAGS, &ifreq);
1062                        break;
1063
1064                case SIOCSIFDSTADDR:
1065                        memcpy (&ifreq.ifr_dstaddr, param, sizeof (struct sockaddr));
1066                        r = ioctl (s, cmd, &ifreq);
1067                        break;
1068
1069                case OSIOCGIFDSTADDR:
1070                case SIOCGIFDSTADDR:
1071                        if ((r = ioctl (s, cmd, &ifreq)) < 0)
1072                                break;
1073                        memcpy (param, &ifreq.ifr_dstaddr, sizeof (struct sockaddr));
1074                        break;
1075
1076                case SIOCSIFBRDADDR:
1077                        memcpy (&ifreq.ifr_broadaddr, param, sizeof (struct sockaddr));
1078                        r = ioctl (s, cmd, &ifreq);
1079                        break;
1080
1081                case OSIOCGIFBRDADDR:
1082                case SIOCGIFBRDADDR:
1083                        if ((r = ioctl (s, cmd, &ifreq)) < 0)
1084                                break;
1085                        memcpy (param, &ifreq.ifr_broadaddr, sizeof (struct sockaddr));
1086                        break;
1087
1088                case SIOCSIFMETRIC:
1089                        ifreq.ifr_metric = *((int*) param);
1090                        r = ioctl (s, cmd, &ifreq);
1091                        break;
1092
1093                case SIOCGIFMETRIC:
1094                        if ((r = ioctl (s, cmd, &ifreq)) < 0)
1095                                break;
1096                        *((int*) param) = ifreq.ifr_metric;
1097                        break;
1098
1099                case SIOCSIFMTU:
1100                        ifreq.ifr_mtu = *((int*) param);
1101                        r = ioctl (s, cmd, &ifreq);
1102                        break;
1103
1104                case SIOCGIFMTU:
1105                        if ((r = ioctl (s, cmd, &ifreq)) < 0)
1106                                break;
1107                        *((int*) param) = ifreq.ifr_mtu;
1108                        break;
1109
1110                case SIOCSIFPHYS:
1111                        ifreq.ifr_phys = *((int*) param);
1112                        r = ioctl (s, cmd, &ifreq);
1113                        break;
1114
1115                case SIOCGIFPHYS:
1116                        if ((r = ioctl (s, cmd, &ifreq)) < 0)
1117                                break;
1118                        *((int*) param) = ifreq.ifr_phys;
1119                        break;
1120
1121                case SIOCSIFMEDIA:
1122                        ifreq.ifr_media = *((int*) param);
1123                        r = ioctl (s, cmd, &ifreq);
1124                        break;
1125
1126                case SIOCGIFMEDIA:
1127                        /* 'param' passes the phy index they want to
1128                         * look at...
1129                         */
1130                        ifreq.ifr_media = *((int*) param);
1131                        if ((r = ioctl (s, cmd, &ifreq)) < 0)
1132                                break;
1133                        *((int*) param) = ifreq.ifr_media;
1134                        break;
1135
1136                case SIOCAIFADDR:
1137                case SIOCDIFADDR:
1138                        r = ioctl(s, cmd, (struct ifreq *) param);
1139                        break;
1140
1141                default:
1142                        errno = EOPNOTSUPP;
1143                        r = -1;
1144                        break;
1145        }
1146
1147        rtems_bsdnet_semaphore_release ();
1148
1149        close (s);
1150        return r;
1151}
1152
1153/*
1154 * Parse a network driver name into a name and a unit number
1155 */
1156int
1157rtems_bsdnet_parse_driver_name (const struct rtems_bsdnet_ifconfig *config, char **namep)
1158{
1159        const char *cp = config->name;
1160        char c;
1161        int unitNumber = 0;
1162
1163        if (cp == NULL) {
1164                printf ("No network driver name.\n");
1165                return -1;
1166        }
1167        while ((c = *cp++) != '\0') {
1168                if ((c >= '0') && (c <= '9')) {
1169                        int len = cp - config->name;
1170                        if ((len < 2) || (len > 50))
1171                                break;
1172                        for (;;) {
1173                                unitNumber = (unitNumber * 10) + (c - '0');
1174                                c = *cp++;
1175                                if (c == '\0') {
1176                                        char *unitName = malloc (len);
1177                                        if (unitName == NULL) {
1178                                                printf ("No memory.\n");
1179                                                return -1;
1180                                        }
1181                                        strncpy (unitName, config->name, len - 1);
1182                                        unitName[len-1] = '\0';
1183                                        *namep = unitName;
1184                                        return unitNumber;
1185                                }
1186                                if ((c < '0') || (c > '9'))
1187                                        break;
1188                        }
1189                        break;
1190                }
1191        }
1192        printf ("Bad network driver name `%s'.\n", config->name);
1193        return -1;
1194}
1195
1196/*
1197 * Handle requests for more network memory
1198 * XXX: Another possibility would be to use a semaphore here with
1199 *      a release in the mbuf free macro.  I have chosen this `polling'
1200 *      approach because:
1201 *      1) It is simpler.
1202 *      2) It adds no complexity to the free macro.
1203 *      3) Running out of mbufs should be a rare
1204 *         condition -- predeployment testing of
1205 *         an application should indicate the
1206 *         required mbuf pool size.
1207 * XXX: Should there be a panic if a task is stuck in the loop for
1208 *      more than a minute or so?
1209 */
1210int
1211m_mballoc (int nmb, int nowait)
1212{
1213        if (nowait)
1214                return 0;
1215        m_reclaim ();
1216        if (mmbfree == NULL) {
1217                int try = 0;
1218                int print_limit = 30 * rtems_bsdnet_ticks_per_second;
1219
1220                mbstat.m_wait++;
1221                for (;;) {
1222                        rtems_bsdnet_semaphore_release ();
1223                        rtems_task_wake_after (1);
1224                        rtems_bsdnet_semaphore_obtain ();
1225                        if (mmbfree)
1226                                break;
1227                        if (++try >= print_limit) {
1228                                printf ("Still waiting for mbuf.\n");
1229                                try = 0;
1230                        }
1231                }
1232        }
1233        else {
1234                mbstat.m_drops++;
1235        }
1236        return 1;
1237}
1238
1239int
1240m_clalloc(ncl, nowait)
1241{
1242        if (nowait)
1243                return 0;
1244        m_reclaim ();
1245        if (mclfree == NULL) {
1246                int try = 0;
1247                int print_limit = 30 * rtems_bsdnet_ticks_per_second;
1248
1249                mbstat.m_wait++;
1250                for (;;) {
1251                        rtems_bsdnet_semaphore_release ();
1252                        rtems_task_wake_after (1);
1253                        rtems_bsdnet_semaphore_obtain ();
1254                        if (mclfree)
1255                                break;
1256                        if (++try >= print_limit) {
1257                                printf ("Still waiting for mbuf cluster.\n");
1258                                try = 0;
1259                        }
1260                }
1261        }
1262        else {
1263                mbstat.m_drops++;
1264        }
1265        return 1;
1266}
Note: See TracBrowser for help on using the repository browser.