source: rtems/cpukit/libnetworking/rtems/rtems_glue.c @ 4aa8a23

4.104.114.84.95
Last change on this file since 4aa8a23 was 4aa8a23, checked in by Ralf Corsepius <ralf.corsepius@…>, on Feb 2, 2005 at 3:06:41 AM

Include config.h.

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