source: rtems/cpukit/libnetworking/rtems/rtems_glue.c @ fa768df

4.104.114.84.95
Last change on this file since fa768df was fa768df, checked in by Ralf Corsepius <ralf.corsepius@…>, on 03/28/07 at 04:43:04

2007-03-28 Ralf Corsépius <ralf.corsepius@…>

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