source: rtems/cpukit/libnetworking/rtems/rtems_glue.c @ 5a598ac

5
Last change on this file since 5a598ac was 5a598ac, checked in by Sebastian Huber <sebastian.huber@…>, on 05/27/16 at 06:02:03

score: Add CORE mutex variants

Add CORE_recursive_mutex_Control and CORE_ceiling_mutex_Control to avoid
the run-time evaluation of attributes to figure out how a particular
mutex methods should behave. Start with the no protocol variants. This
eliminates the CORE_MUTEX_DISCIPLINES_FIFO and
CORE_MUTEX_DISCIPLINES_PRIORITY disciplines.

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