source: rtems/cpukit/libnetworking/rtems/rtems_glue.c @ 8f96581

5
Last change on this file since 8f96581 was 8f96581, checked in by Sebastian Huber <sebastian.huber@…>, on 04/01/16 at 09:38:47

score: Rework MP thread queue callout support

The thread queue implementation was heavily reworked to support SMP.
This broke the multiprocessing support of the thread queues. This is
fixed by this patch.

A thread proxy is unblocked due to three reasons

1) timeout,
2) request satisfaction, and
3) extraction.

In case 1) no MPCI message must be sent. This is ensured via the
_Thread_queue_MP_callout_do_nothing() callout set during
_Thread_MP_Allocate_proxy().

In case 2) and 3) an MPCI message must be sent. In case we interrupt
the blocking operation during _Thread_queue_Enqueue_critical(), then
this message must be sent by the blocking thread. For this the new
fields Thread_Proxy_control::thread_queue_callout and
Thread_Proxy_control::thread_queue_id are used.

Delete the individual API MP callout types and use
Thread_queue_MP_callout throughout. This type is only defined in
multiprocessing configurations. Prefix the multiprocessing parameters
with mp_ to ease code review. Multiprocessing specific parameters are
optional due to use of a similar macro pattern. There is no overhead
for non-multiprocessing configurations.

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