source: rtems/cpukit/libnetworking/rtems/rtems_glue.c @ 51b6226

4.104.114.84.95
Last change on this file since 51b6226 was 51b6226, checked in by Joel Sherrill <joel.sherrill@…>, on 08/01/07 at 00:44:05

2007-07-31 Joel Sherrill <joel.sherrill@…>

PR 1248/networking

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