source: rtems/cpukit/libnetworking/rtems/rtems_glue.c @ 83e36d6b

4.104.114.84.95
Last change on this file since 83e36d6b was 83e36d6b, checked in by Joel Sherrill <joel.sherrill@…>, on Feb 11, 2003 at 10:58:08 PM

2003-02-11 Mike Siers <mikes@…>

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