source: rtems/cpukit/libnetworking/rtems/rtems_glue.c @ 593616a8

Last change on this file since 593616a8 was 593616a8, checked in by Joel Sherrill <joel.sherrill@…>, on Mar 25, 2003 at 7:00:23 PM

2002-03-25 Eric Norum <norume@…>

PR 374/networking

  • Makefile.am, rtems/rtems_bsdnet.h, rtems/rtems_glue.c: The patch sent as part of PR270 got applied to the wrong place. The effect was that (1) startup was no faster than before and (2) malloc starvation messages came way too quickly. The attached patch fixes both these problems and also provides a mechanism for applications to handle malloc starvation conditions as they see fit.
  • rtems/rtems_bsdnet_malloc_starvation.c: New file.
  • 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                        rtems_bsdnet_malloc_starvation();
121                        try = 0;
122                }
123        rtems_task_wake_after (rtems_bsdnet_ticks_per_second);
124                rtems_bsdnet_semaphore_obtain ();
125        }
126}
127
128/*
129 * Free FreeBSD memory
130 * FIXME: This should be modified to keep memory allocation statistics.
131 */
132void
133rtems_bsdnet_free (void *addr, int type)
134{
135        free (addr);
136}
137
138/*
139 * Do the initializations required by the BSD code
140 */
141static int
142bsd_init (void)
143{
144        int i;
145        char *p;
146
147        /*
148         * Set up mbuf cluster data strutures
149         */
150        p = malloc ((nmbclusters*MCLBYTES)+MCLBYTES-1);
151        if (p == NULL) {
152                printf ("Can't get network cluster memory.\n");
153                return -1;
154        }
155        p = (char *)(((unsigned long)p + (MCLBYTES-1)) & ~(MCLBYTES-1));
156        mbutl = (struct mbuf *)p;
157        for (i = 0; i < nmbclusters; i++) {
158                ((union mcluster *)p)->mcl_next = mclfree;
159                mclfree = (union mcluster *)p;
160                p += MCLBYTES;
161                mbstat.m_clfree++;
162        }
163        mbstat.m_clusters = nmbclusters;
164        mclrefcnt = malloc (nmbclusters);
165        if (mclrefcnt == NULL) {
166                printf ("Can't get mbuf cluster reference counts memory.\n");
167                return -1;
168        }
169        memset (mclrefcnt, '\0', nmbclusters);
170
171        /*
172         * Set up mbuf data structures
173         */
174
175        p = malloc(nmbuf * MSIZE + MSIZE - 1);
176        p = (char *)(((unsigned int)p + MSIZE - 1) & ~(MSIZE - 1));
177        if (p == NULL) {
178                printf ("Can't get network memory.\n");
179                return -1;
180        }
181        for (i = 0; i < nmbuf; i++) {
182                ((struct mbuf *)p)->m_next = mmbfree;
183                mmbfree = (struct mbuf *)p;
184                p += MSIZE;
185        }
186        mbstat.m_mbufs = nmbuf;
187        mbstat.m_mtypes[MT_FREE] = nmbuf;
188
189        /*
190         * Set up domains
191         */
192        {
193        extern struct domain routedomain;
194        extern struct domain inetdomain;
195
196        routedomain.dom_next = domains;
197        domains = &routedomain;
198        inetdomain.dom_next = domains;
199        domains = &inetdomain;
200        domaininit (NULL);
201        }
202
203  /*
204   * Setup the sysctl, normally done by a SYSINIT call.
205   */
206  sysctl_register_all(0);
207   
208        /*
209         * Set up interfaces
210         */
211        ifinit (NULL);
212        return 0;
213}
214
215/*
216 * Initialize and start network operations
217 */
218static int
219rtems_bsdnet_initialize (void)
220{
221        rtems_status_code sc;
222
223        /*
224         * Set the priority of all network tasks
225         */
226        if (rtems_bsdnet_config.network_task_priority == 0)
227                networkDaemonPriority = 100;
228        else
229                networkDaemonPriority = rtems_bsdnet_config.network_task_priority;
230
231        /*
232         * Set the memory allocation limits
233         */
234        if (rtems_bsdnet_config.mbuf_bytecount)
235                nmbuf = rtems_bsdnet_config.mbuf_bytecount / MSIZE;
236        if (rtems_bsdnet_config.mbuf_cluster_bytecount)
237                nmbclusters = rtems_bsdnet_config.mbuf_cluster_bytecount / MCLBYTES;
238
239        /*
240         * Create the task-synchronization semaphore
241         */
242        sc = rtems_semaphore_create (rtems_build_name('B', 'S', 'D', 'n'),
243                                        0,
244                                        RTEMS_PRIORITY |
245                                                RTEMS_BINARY_SEMAPHORE |
246                                                RTEMS_INHERIT_PRIORITY |
247                                                RTEMS_NO_PRIORITY_CEILING |
248                                                RTEMS_LOCAL,
249                                        0,
250                                        &networkSemaphore);
251        if (sc != RTEMS_SUCCESSFUL) {
252                printf ("Can't create network seamphore: `%s'\n", rtems_status_text (sc));
253                return -1;
254        }
255#ifdef RTEMS_FAST_MUTEX
256        {
257        Objects_Locations location;
258        the_networkSemaphore = _Semaphore_Get( networkSemaphore, &location );
259        _Thread_Enable_dispatch();
260        }
261#endif
262
263        /*
264         * Compute clock tick conversion factors
265         */
266        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &rtems_bsdnet_ticks_per_second);
267        if (rtems_bsdnet_ticks_per_second <= 0)
268                rtems_bsdnet_ticks_per_second = 1;
269        rtems_bsdnet_microseconds_per_tick = 1000000 / rtems_bsdnet_ticks_per_second;
270
271        /*
272         * Ensure that `seconds' is greater than 0
273         */
274    while (rtems_bsdnet_seconds_since_boot() == 0)
275        rtems_task_wake_after(1);
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.