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

4.104.114.84.95
Last change on this file since a6f3cff was a6f3cff, checked in by Joel Sherrill <joel.sherrill@…>, on Jun 11, 1999 at 2:11:44 PM

Patch from Ian Lance Taylor <ian@…>:

The select function is not particularly efficient when dealing with a
large number of sockets. The application has to build a big set of
bits and pass it in. RTEMS has to look through all those bits and see
what is ready. Then the application has to look through all the bits
again.

On the other hand, when using RTEMS, the select function is needed
exactly when you have a large number of sockets, because that is when
it becomes prohibitive to use a separate thread for each socket.

I think it would make more sense for RTEMS to support callback
functions which could be invoked when there is data available to read
from a socket, or when there is space available to write to a socket.

Accordingly, I implemented them.

This patch adds two new SOL_SOCKET options to setsockopt and
getsockopt: SO_SNDWAKEUP and SO_RCVWAKEUP. They take arguments of
type struct sockwakeup:

struct sockwakeup {

void (*sw_pfn) P((struct socket *, caddr_t));
caddr_t sw_arg;

};

They are used to add or remove a function which will be called when
something happens for the socket. Getting a callback doesn't imply
that a read or write will succeed, but it does imply that it is worth
trying.

This adds functionality to RTEMS which is somewhat like interrupt
driven socket I/O on Unix.

After the patch to RTEMS, I have appended a patch to
netdemos-19990407/select/test.c to test the new functionality and
demonstrate one way it might be used. To run the new test instead of
the select test, change doSocket to call echoServer2 instead of
echoServer.

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