source: rtems/cpukit/libnetworking/rtems/rtems_glue.c @ 06c3530

4.104.115
Last change on this file since 06c3530 was 06c3530, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 10/10/08 at 15:56:32

libnetworking/rtems/rtems_glue.c: Copy nothing if rtems_bsdnet_parse_driver_name() if namep is NULL.

include/rtems/status-checks.h: Added prefix "RTEMS" for all macros. Doxygen style comments. Cleanup.

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