source: rtems/c/src/exec/libnetworking/rtems/rtems_glue.c @ 6f93bb4

4.104.114.84.95
Last change on this file since 6f93bb4 was 6f93bb4, checked in by Joel Sherrill <joel.sherrill@…>, on 06/14/00 at 17:18:18

Patch from Chris Johns <cjohns@…> to enhance network
initialization. This adds an interface which makes it easier to
control the BSD stack from user code. The BSD stack initialise uses
it. It is a sort of `function' interface for an ifconfig
command.

I also added support for attaching and removing interfaces. With hot
swap PCI comming online support for hot swap PCI will be an important
factor in "state of art" RTOS's. This is also part of a general move on
my part to allow RTEMS to be configured at runtime by calls rather than
table driven at initialisation.

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