source: rtems/cpukit/libnetworking/rtems/rtems_glue.c @ 41d2eaca

4.104.114.84.95
Last change on this file since 41d2eaca was a0af97d, checked in by Joel Sherrill <joel.sherrill@…>, on 11/09/99 at 03:43:47

Patch from Eric Norum <eric@…> to add NTP BOOTP support because
EPICS needs a synchronized time-of-day clock. This patch is the changes
needed to get NTP server information from a BOOTP server.

This patch also adds NTP server information to the network configuration
structure, too.

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