source: rtems/cpukit/libnetworking/rtems/rtems_glue.c @ 845f170a

4.104.114.84.95
Last change on this file since 845f170a was 845f170a, checked in by Joel Sherrill <joel.sherrill@…>, on 08/20/02 at 15:53:52

2002-08-20 Eric Norum <eric.norum@…>

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