source: rtems/cpukit/libnetworking/rtems/rtems_glue.c @ 631b3c8

5
Last change on this file since 631b3c8 was 631b3c8, checked in by Sebastian Huber <sebastian.huber@…>, on 05/23/16 at 09:40:18

score: Move thread queue MP callout to context

Drop the multiprocessing (MP) dependent callout parameter from the
thread queue extract, dequeue, flush and unblock methods. Merge this
parameter with the lock context into new structure Thread_queue_Context.
This helps to gets rid of the conditionally compiled method call
helpers.

  • 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.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        Thread_Control *executing;
376        if (!the_networkSemaphore)
377                rtems_panic ("rtems-net: network sema obtain: network not initialised\n");
378        _Thread_queue_Context_initialize(&queue_context, NULL);
379        _ISR_lock_ISR_disable(&queue_context.Lock_context);
380        executing = _Thread_Executing;
381        _CORE_mutex_Seize (
382                &the_networkSemaphore->Core_control.mutex,
383                executing,
384                1,              /* wait */
385                0,              /* forever */
386                &queue_context
387                );
388        if (executing->Wait.return_code)
389                rtems_panic ("rtems-net: can't obtain network sema: %d\n",
390                 executing->Wait.return_code);
391#else
392        rtems_status_code sc;
393
394        sc = rtems_semaphore_obtain (networkSemaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
395        if (sc != RTEMS_SUCCESSFUL)
396                rtems_panic ("rtems-net: can't obtain network semaphore: `%s'\n",
397                 rtems_status_text (sc));
398#endif
399}
400
401/*
402 * Release network mutex
403 */
404void
405rtems_bsdnet_semaphore_release (void)
406{
407#ifdef RTEMS_FAST_MUTEX
408        Thread_queue_Context queue_context;
409        CORE_mutex_Status status;
410
411        if (!the_networkSemaphore)
412                rtems_panic ("rtems-net: network sema obtain: network not initialised\n");
413        _Thread_queue_Context_initialize(&queue_context, NULL);
414        _ISR_lock_ISR_disable(&queue_context.Lock_context);
415        status = _CORE_mutex_Surrender (
416                &the_networkSemaphore->Core_control.mutex,
417                &queue_context
418                );
419        if (status != CORE_MUTEX_STATUS_SUCCESSFUL)
420                rtems_panic ("rtems-net: can't release network sema: %i\n");
421#else
422        rtems_status_code sc;
423
424        sc = rtems_semaphore_release (networkSemaphore);
425        if (sc != RTEMS_SUCCESSFUL)
426                rtems_panic ("rtems-net: can't release network semaphore: `%s'\n",
427                 rtems_status_text (sc));
428#endif
429}
430
431static int
432rtems_bsdnet_sleep(rtems_event_set in, rtems_interval ticks)
433{
434        rtems_status_code sc;
435        rtems_event_set out;
436        rtems_event_set out2;
437
438        in |= RTEMS_EVENT_SYSTEM_NETWORK_CLOSE;
439
440        /*
441         * Soak up any pending events.  The sleep/wakeup synchronization in the
442         * FreeBSD kernel has no memory.
443         */
444        rtems_event_system_receive(in, RTEMS_EVENT_ANY | RTEMS_NO_WAIT,
445            RTEMS_NO_TIMEOUT, &out);
446
447        /*
448         * Wait for the wakeup event.
449         */
450        sc = rtems_bsdnet_event_receive(in, RTEMS_EVENT_ANY | RTEMS_WAIT,
451            ticks, &out);
452
453        /*
454         * Get additional events that may have been received between the
455         * rtems_event_system_receive() and the rtems_bsdnet_semaphore_obtain().
456         */
457        rtems_event_system_receive(in, RTEMS_EVENT_ANY | RTEMS_NO_WAIT,
458            RTEMS_NO_TIMEOUT, &out2);
459        out |= out2;
460
461        if (out & RTEMS_EVENT_SYSTEM_NETWORK_CLOSE)
462                return (ENXIO);
463
464        if (sc == RTEMS_SUCCESSFUL)
465                return (0);
466
467        return (EWOULDBLOCK);
468}
469
470/*
471 * Wait for something to happen to a socket buffer
472 */
473int
474sbwait(struct sockbuf *sb)
475{
476        int error;
477
478        /*
479         * Set this task as the target of the wakeup operation.
480         */
481        sb->sb_sel.si_pid = rtems_task_self();
482
483        /*
484         * Show that socket is waiting
485         */
486        sb->sb_flags |= SB_WAIT;
487
488        error = rtems_bsdnet_sleep(SBWAIT_EVENT, sb->sb_timeo);
489        if (error != ENXIO)
490                sb->sb_flags &= ~SB_WAIT;
491
492        return (error);
493}
494
495
496/*
497 * Wake up the task waiting on a socket buffer.
498 */
499void
500sowakeup(
501        struct socket *so,
502        struct sockbuf *sb)
503{
504        if (sb->sb_flags & SB_WAIT) {
505                rtems_event_system_send (sb->sb_sel.si_pid, SBWAIT_EVENT);
506        }
507        if (sb->sb_wakeup) {
508                (*sb->sb_wakeup) (so, sb->sb_wakeuparg);
509        }
510}
511
512/*
513 * For now, a socket can be used by only one task at a time.
514 */
515int
516sb_lock(struct sockbuf *sb)
517{
518        rtems_panic ("Socket buffer is already in use.");
519        return 0;
520}
521void
522wakeup (void *p)
523{
524        rtems_panic ("Wakeup called");
525}
526
527/*
528 * Wait for a connection/disconnection event.
529 */
530int
531soconnsleep (struct socket *so)
532{
533        int error;
534
535        /*
536         * Set this task as the target of the wakeup operation.
537         */
538        if (so->so_pgid)
539                rtems_panic ("Another task is already sleeping on that socket");
540        so->so_pgid = rtems_task_self();
541
542        error = rtems_bsdnet_sleep(SOSLEEP_EVENT, so->so_rcv.sb_timeo);
543        if (error != ENXIO)
544                so->so_pgid = 0;
545
546        return (error);
547}
548
549/*
550 * Wake up a task waiting for a connection/disconnection to complete.
551 */
552void
553soconnwakeup (struct socket *so)
554{
555        if (so->so_pgid)
556                rtems_event_system_send (so->so_pgid, SOSLEEP_EVENT);
557}
558
559/*
560 * Send an event to the network daemon.
561 * This corresponds to sending a software interrupt in the BSD kernel.
562 */
563void
564rtems_bsdnet_schednetisr (int n)
565{
566        rtems_event_system_send (networkDaemonTid, 1 << n);
567}
568
569/*
570 * The network daemon
571 * This provides a context to run BSD software interrupts
572 */
573static void
574networkDaemon (void *task_argument)
575{
576        rtems_status_code sc;
577        rtems_event_set events;
578        rtems_interval now;
579        int ticksPassed;
580        uint32_t   timeout;
581        struct callout *c;
582
583        for (;;) {
584                c = calltodo.c_next;
585                if (c)
586                        timeout = c->c_time;
587                else
588                        timeout = RTEMS_NO_TIMEOUT;
589
590                sc = rtems_bsdnet_event_receive (NETISR_EVENTS,
591                                                RTEMS_EVENT_ANY | RTEMS_WAIT,
592                                                timeout,
593                                                &events);
594                if ( sc == RTEMS_SUCCESSFUL ) {
595                        if (events & NETISR_IP_EVENT)
596                                ipintr ();
597                        if (events & NETISR_ARP_EVENT)
598                                arpintr ();
599                }
600
601                now = rtems_clock_get_ticks_since_boot();
602                ticksPassed = now - ticksWhenCalloutsLastChecked;
603                if (ticksPassed != 0) {
604                        ticksWhenCalloutsLastChecked = now;
605
606                        c = calltodo.c_next;
607                        if (c) {
608                                c->c_time -= ticksPassed;
609                                while ((c = calltodo.c_next) != NULL && c->c_time <= 0) {
610                                        void *arg;
611                                        void (*func) (void *);
612
613                                        func = c->c_func;
614                                        arg = c->c_arg;
615                                        calltodo.c_next = c->c_next;
616                                        c->c_next = callfree;
617                                        callfree = c;
618                                        (*func)(arg);
619                                }
620                        }
621                }
622        }
623}
624
625/*
626 * Structure passed to task-start stub
627 */
628struct newtask {
629        void (*entry)(void *);
630        void *arg;
631};
632
633/*
634 * Task-start stub
635 */
636static void
637taskEntry (rtems_task_argument arg)
638{
639        struct newtask t;
640
641        /*
642         * Pick up task information and free
643         * the memory allocated to pass the
644         * information to this task.
645         */
646        t = *(struct newtask *)arg;
647        free ((struct newtask *)arg);
648
649        /*
650         * Enter the competition for the network semaphore
651         */
652        rtems_bsdnet_semaphore_obtain ();
653
654        /*
655         * Enter the task
656         */
657        (*t.entry)(t.arg);
658        rtems_panic ("Network task returned!\n");
659}
660
661
662/*
663 * Start a network task
664 */
665#ifdef RTEMS_SMP
666rtems_id
667rtems_bsdnet_newproc (char *name, int stacksize, void(*entry)(void *), void *arg)
668{
669        return rtems_bsdnet_newproc_affinity( name, stacksize, entry, arg,
670                networkDaemonCpuset, networkDaemonCpusetSize );
671}
672
673rtems_id
674rtems_bsdnet_newproc_affinity (char *name, int stacksize, void(*entry)(void *),
675    void *arg, const cpu_set_t *set, const size_t setsize)
676#else
677rtems_id
678rtems_bsdnet_newproc (char *name, int stacksize, void(*entry)(void *), void *arg)
679#endif
680{
681        struct newtask *t;
682        char nm[4];
683        rtems_id tid;
684        rtems_status_code sc;
685
686        strncpy (nm, name, 4);
687        sc = rtems_task_create (rtems_build_name(nm[0], nm[1], nm[2], nm[3]),
688                networkDaemonPriority,
689                stacksize,
690                RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0),
691#ifdef RTEMS_MULTIPROCESSING
692                RTEMS_SYSTEM_TASK |
693#endif
694                RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL,
695                &tid);
696        if (sc != RTEMS_SUCCESSFUL)
697                rtems_panic ("Can't create network daemon `%s': `%s'\n", name, rtems_status_text (sc));
698
699#ifdef RTEMS_SMP
700        /*
701         * Use the default affinity or use the user-provided CPU set
702         */
703        if ( set != 0 )
704                rtems_task_set_affinity( tid, setsize, set );
705#endif
706
707        /*
708         * Set up task arguments
709         */
710        t = malloc (sizeof *t);
711        t->entry = entry;
712        t->arg = arg;
713
714        /*
715         * Start the task
716         */
717        sc = rtems_task_start (tid, taskEntry, (rtems_task_argument)t);
718        if (sc != RTEMS_SUCCESSFUL)
719                rtems_panic ("Can't start network daemon `%s': `%s'\n", name, rtems_status_text (sc));
720
721        /*
722         * Let our caller know the i.d. of the new task
723         */
724        return tid;
725}
726
727rtems_status_code rtems_bsdnet_event_receive (
728  rtems_event_set  event_in,
729  rtems_option     option_set,
730  rtems_interval   ticks,
731  rtems_event_set *event_out)
732{
733        rtems_status_code sc;
734
735        rtems_bsdnet_semaphore_release ();
736        sc = rtems_event_system_receive (event_in, option_set, ticks, event_out);
737        rtems_bsdnet_semaphore_obtain ();
738        return sc;
739}
740
741/*
742 * Fake random number generator
743 */
744unsigned long
745rtems_bsdnet_random (void)
746{
747        rtems_interval now;
748
749        now = rtems_clock_get_ticks_since_boot();
750        return (now * 99991);
751}
752
753/*
754 * Callout list processing
755 */
756void
757rtems_bsdnet_timeout(void (*ftn)(void *), void *arg, int ticks)
758{
759        register struct callout *new, *p, *t;
760
761        if (ticks <= 0)
762                ticks = 1;
763
764        /* Fill in the next free callout structure. */
765        if (callfree == NULL) {
766                callfree = malloc (sizeof *callfree);
767                if (callfree == NULL)
768                        rtems_panic ("No memory for timeout table entry");
769                callfree->c_next = NULL;
770        }
771
772        new = callfree;
773        callfree = new->c_next;
774        new->c_arg = arg;
775        new->c_func = ftn;
776
777        /*
778         * The time for each event is stored as a difference from the time
779         * of the previous event on the queue.  Walk the queue, correcting
780         * the ticks argument for queue entries passed.  Correct the ticks
781         * value for the queue entry immediately after the insertion point
782         * as well.  Watch out for negative c_time values; these represent
783         * overdue events.
784         */
785        for (p = &calltodo;
786            (t = p->c_next) != NULL && ticks > t->c_time; p = t)
787                if (t->c_time > 0)
788                        ticks -= t->c_time;
789        new->c_time = ticks;
790        if (t != NULL)
791                t->c_time -= ticks;
792
793        /* Insert the new entry into the queue. */
794        p->c_next = new;
795        new->c_next = t;
796}
797
798/*
799 * Ticks till specified time
800 * XXX: This version worries only about seconds, but that's good
801 * enough for the way the network code uses this routine.
802 */
803int
804hzto(struct timeval *tv)
805{
806        long diff = tv->tv_sec - rtems_bsdnet_seconds_since_boot();
807
808        if (diff <= 0)
809                return 1;
810        return diff * rtems_bsdnet_ticks_per_second;
811}
812
813/*
814 * Kernel debugging
815 */
816int rtems_bsdnet_log_priority;
817void
818rtems_bsdnet_log (int priority, const char *fmt, ...)
819{
820        va_list args;
821
822        if (priority & rtems_bsdnet_log_priority) {
823                va_start (args, fmt);
824                vprintf (fmt, args);
825                va_end (args);
826        }
827}
828
829/*
830 * IP header checksum routine for processors which don't have an inline version
831 */
832
833u_int in_cksum_hdr(const struct ip *);
834
835u_int
836in_cksum_hdr (const struct ip *ip)
837{
838        uint32_t   sum;
839        const uint16_t   *sp;
840        int i;
841
842        sum = 0;
843        sp = (uint16_t   *)ip;
844        for (i = 0 ; i < 10 ; i++)
845                sum += *sp++;
846        while (sum > 0xFFFF)
847                sum = (sum & 0xffff) + (sum >> 16);
848        return ~sum & 0xFFFF;
849}
850
851/*
852 * Manipulate routing tables
853 */
854int rtems_bsdnet_rtrequest (
855    int req,
856    struct sockaddr *dst,
857    struct sockaddr *gateway,
858    struct sockaddr *netmask,
859    int flags,
860    struct rtentry **net_nrt)
861{
862        int error;
863
864        rtems_bsdnet_semaphore_obtain ();
865        error = rtrequest (req, dst, gateway, netmask, flags, net_nrt);
866        rtems_bsdnet_semaphore_release ();
867        if (error) {
868                errno = error;
869                return -1;
870        }
871        return 0;
872}
873
874static bool
875rtems_bsdnet_setup_interface(
876        const char *name,
877        const char *ip_address,
878        const char *ip_netmask
879)
880{
881        struct sockaddr_in address;
882        struct sockaddr_in netmask;
883        short flags;
884
885        /*
886         * Bring interface up
887         */
888        flags = IFF_UP;
889        if (rtems_bsdnet_ifconfig (name, SIOCSIFFLAGS, &flags) < 0) {
890                printf ("Can't bring %s up: %s\n", name, strerror (errno));
891                return false;
892        }
893
894        /*
895         * Set interface netmask
896         */
897        rtems_bsdnet_initialize_sockaddr_in(&netmask);
898        netmask.sin_addr.s_addr = inet_addr (ip_netmask);
899        if (rtems_bsdnet_ifconfig (name, SIOCSIFNETMASK, &netmask) < 0) {
900                printf ("Can't set %s netmask: %s\n", name, strerror (errno));
901                return false;
902        }
903
904        /*
905         * Set interface address
906         */
907        rtems_bsdnet_initialize_sockaddr_in(&address);
908        address.sin_addr.s_addr = inet_addr (ip_address);
909        if (rtems_bsdnet_ifconfig (name, SIOCSIFADDR, &address) < 0) {
910                printf ("Can't set %s address: %s\n", name, strerror (errno));
911                return false;
912        }
913
914        /*
915         * Set interface broadcast address if the interface has the
916         * broadcast flag set.
917         */
918        if (rtems_bsdnet_ifconfig (name, SIOCGIFFLAGS, &flags) < 0) {
919                printf ("Can't read %s flags: %s\n", name, strerror (errno));
920                return false;
921        }
922
923        if (flags & IFF_BROADCAST) {
924                struct sockaddr_in broadcast;
925
926                rtems_bsdnet_initialize_sockaddr_in(&broadcast);
927                broadcast.sin_addr.s_addr =
928                                address.sin_addr.s_addr | ~netmask.sin_addr.s_addr;
929                if (rtems_bsdnet_ifconfig (name, SIOCSIFBRDADDR, &broadcast) < 0) {
930                        struct in_addr  in_addr;
931                        char                    buf[20];
932                        in_addr.s_addr = broadcast.sin_addr.s_addr;
933                        if (!inet_ntop(AF_INET, &in_addr, buf, sizeof(buf)))
934                                        strcpy(buf,"?.?.?.?");
935                        printf ("Can't set %s broadcast address %s: %s\n",
936                                name, buf, strerror (errno));
937                }
938        }
939
940        return true;
941}
942
943static int
944rtems_bsdnet_setup (void)
945{
946        struct rtems_bsdnet_ifconfig *ifp;
947        int i;
948        bool any_if_configured = false;
949
950        /*
951         * Set local parameters
952         */
953        if (rtems_bsdnet_config.hostname)
954                sethostname (rtems_bsdnet_config.hostname,
955                                        strlen (rtems_bsdnet_config.hostname));
956        if (rtems_bsdnet_config.domainname)
957                rtems_bsdnet_domain_name =
958                                        strdup (rtems_bsdnet_config.domainname);
959        if (rtems_bsdnet_config.log_host)
960                rtems_bsdnet_log_host_address.s_addr =
961                                inet_addr (rtems_bsdnet_config.log_host);
962        for (i = 0 ; i < sizeof rtems_bsdnet_config.name_server /
963                        sizeof rtems_bsdnet_config.name_server[0] ; i++) {
964                if (!rtems_bsdnet_config.name_server[i])
965                        break;
966                rtems_bsdnet_nameserver[rtems_bsdnet_nameserver_count++].s_addr
967                        = inet_addr (rtems_bsdnet_config.name_server[i]);
968        }
969        for (i = 0 ; i < sizeof rtems_bsdnet_config.ntp_server /
970                        sizeof rtems_bsdnet_config.ntp_server[0] ; i++) {
971                if (!rtems_bsdnet_config.ntp_server[i])
972                        break;
973                rtems_bsdnet_ntpserver[rtems_bsdnet_ntpserver_count++].s_addr
974                        = inet_addr (rtems_bsdnet_config.ntp_server[i]);
975        }
976
977        /*
978         * Configure interfaces
979         */
980        any_if_configured |= rtems_bsdnet_setup_interface(
981                "lo0",
982                "127.0.0.1",
983                "255.0.0.0"
984        );
985        for (ifp = rtems_bsdnet_config.ifconfig ; ifp ; ifp = ifp->next) {
986                if (ifp->ip_address == NULL)
987                        continue;
988
989                any_if_configured |= rtems_bsdnet_setup_interface(
990                        ifp->name,
991                        ifp->ip_address,
992                        ifp->ip_netmask
993                );
994        }
995
996        /*
997         * Set default route
998         */
999        if (rtems_bsdnet_config.gateway && any_if_configured) {
1000                struct sockaddr_in address;
1001                struct sockaddr_in netmask;
1002                struct sockaddr_in gateway;
1003
1004                rtems_bsdnet_initialize_sockaddr_in(&address);
1005                rtems_bsdnet_initialize_sockaddr_in(&netmask);
1006                rtems_bsdnet_initialize_sockaddr_in(&gateway);
1007
1008                gateway.sin_addr.s_addr = inet_addr (rtems_bsdnet_config.gateway);
1009
1010                if (rtems_bsdnet_rtrequest (
1011                                RTM_ADD,
1012                                (struct sockaddr *)&address,
1013                                (struct sockaddr *)&gateway,
1014                                (struct sockaddr *)&netmask,
1015                                (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL) < 0) {
1016                        printf ("Can't set default route: %s\n", strerror (errno));
1017                        return -1;
1018                }
1019        }
1020        return 0;
1021}
1022
1023/*
1024 * Initialize the network
1025 */
1026int
1027rtems_bsdnet_initialize_network(void)
1028{
1029        struct rtems_bsdnet_ifconfig *ifp;
1030
1031        /*
1032         * Start network tasks.
1033         * Initialize BSD network data structures.
1034         */
1035        if (rtems_bsdnet_initialize () < 0)
1036                return -1;
1037
1038        /*
1039         * Attach interfaces
1040         */
1041        for (ifp = rtems_bsdnet_config.ifconfig ; ifp ; ifp = ifp->next) {
1042                rtems_bsdnet_attach (ifp);
1043        }
1044
1045        /*
1046         * Bring up the network
1047         */
1048        if (rtems_bsdnet_setup () < 0)
1049                return -1;
1050        if (rtems_bsdnet_config.bootp)
1051                (*rtems_bsdnet_config.bootp)();
1052        return 0;
1053}
1054
1055/*
1056 * Attach a network interface.
1057 */
1058void rtems_bsdnet_attach(struct rtems_bsdnet_ifconfig *ifp)
1059{
1060        if (ifp) {
1061                rtems_bsdnet_semaphore_obtain ();
1062                (ifp->attach)(ifp, 1);
1063                rtems_bsdnet_semaphore_release ();
1064        }
1065}
1066
1067/*
1068 * Detach a network interface.
1069 */
1070void rtems_bsdnet_detach (struct rtems_bsdnet_ifconfig *ifp)
1071{
1072        if (ifp) {
1073                rtems_bsdnet_semaphore_obtain ();
1074                (ifp->attach)(ifp, 0);
1075                rtems_bsdnet_semaphore_release ();
1076        }
1077}
1078
1079/*
1080 * Interface Configuration.
1081 */
1082int rtems_bsdnet_ifconfig(const char *ifname, uint32_t cmd, void *param)
1083{
1084        int s, r = 0;
1085        struct ifreq ifreq;
1086
1087        /*
1088         * Configure interfaces
1089         */
1090        s = socket (AF_INET, SOCK_DGRAM, 0);
1091        if (s < 0)
1092                return -1;
1093
1094        strncpy (ifreq.ifr_name, ifname, IFNAMSIZ);
1095
1096        rtems_bsdnet_semaphore_obtain ();
1097
1098        switch (cmd) {
1099                case SIOCSIFADDR:
1100                case SIOCSIFNETMASK:
1101                        memcpy (&ifreq.ifr_addr, param, sizeof (struct sockaddr));
1102                        r = ioctl (s, cmd, &ifreq);
1103                        break;
1104
1105                case OSIOCGIFADDR:
1106                case SIOCGIFADDR:
1107                case OSIOCGIFNETMASK:
1108                case SIOCGIFNETMASK:
1109                        if ((r = ioctl (s, cmd, &ifreq)) < 0)
1110                                break;
1111                        memcpy (param, &ifreq.ifr_addr, sizeof (struct sockaddr));
1112                        break;
1113
1114                case SIOCGIFFLAGS:
1115                case SIOCSIFFLAGS:
1116                        if ((r = ioctl (s, SIOCGIFFLAGS, &ifreq)) < 0)
1117                                break;
1118                        if (cmd == SIOCGIFFLAGS) {
1119                                *((short*) param) = ifreq.ifr_flags;
1120                                break;
1121                        }
1122                        ifreq.ifr_flags |= *((short*) param);
1123                        if ( (*((short*) param) & IFF_UP ) == 0 ) {
1124                            /* set the interface down */
1125                            ifreq.ifr_flags &= ~(IFF_UP);
1126                        }
1127                        r = ioctl (s, SIOCSIFFLAGS, &ifreq);
1128                        break;
1129
1130                case SIOCSIFDSTADDR:
1131                        memcpy (&ifreq.ifr_dstaddr, param, sizeof (struct sockaddr));
1132                        r = ioctl (s, cmd, &ifreq);
1133                        break;
1134
1135                case OSIOCGIFDSTADDR:
1136                case SIOCGIFDSTADDR:
1137                        if ((r = ioctl (s, cmd, &ifreq)) < 0)
1138                                break;
1139                        memcpy (param, &ifreq.ifr_dstaddr, sizeof (struct sockaddr));
1140                        break;
1141
1142                case SIOCSIFBRDADDR:
1143                        memcpy (&ifreq.ifr_broadaddr, param, sizeof (struct sockaddr));
1144                        r = ioctl (s, cmd, &ifreq);
1145                        break;
1146
1147                case OSIOCGIFBRDADDR:
1148                case SIOCGIFBRDADDR:
1149                        if ((r = ioctl (s, cmd, &ifreq)) < 0)
1150                                break;
1151                        memcpy (param, &ifreq.ifr_broadaddr, sizeof (struct sockaddr));
1152                        break;
1153
1154                case SIOCSIFMETRIC:
1155                        ifreq.ifr_metric = *((int*) param);
1156                        r = ioctl (s, cmd, &ifreq);
1157                        break;
1158
1159                case SIOCGIFMETRIC:
1160                        if ((r = ioctl (s, cmd, &ifreq)) < 0)
1161                                break;
1162                        *((int*) param) = ifreq.ifr_metric;
1163                        break;
1164
1165                case SIOCSIFMTU:
1166                        ifreq.ifr_mtu = *((int*) param);
1167                        r = ioctl (s, cmd, &ifreq);
1168                        break;
1169
1170                case SIOCGIFMTU:
1171                        if ((r = ioctl (s, cmd, &ifreq)) < 0)
1172                                break;
1173                        *((int*) param) = ifreq.ifr_mtu;
1174                        break;
1175
1176                case SIOCSIFPHYS:
1177                        ifreq.ifr_phys = *((int*) param);
1178                        r = ioctl (s, cmd, &ifreq);
1179                        break;
1180
1181                case SIOCGIFPHYS:
1182                        if ((r = ioctl (s, cmd, &ifreq)) < 0)
1183                                break;
1184                        *((int*) param) = ifreq.ifr_phys;
1185                        break;
1186
1187                case SIOCSIFMEDIA:
1188                        ifreq.ifr_media = *((int*) param);
1189                        r = ioctl (s, cmd, &ifreq);
1190                        break;
1191
1192                case SIOCGIFMEDIA:
1193                        /* 'param' passes the phy index they want to
1194                         * look at...
1195                         */
1196                        ifreq.ifr_media = *((int*) param);
1197                        if ((r = ioctl (s, cmd, &ifreq)) < 0)
1198                                break;
1199                        *((int*) param) = ifreq.ifr_media;
1200                        break;
1201
1202                case SIOCAIFADDR:
1203                case SIOCDIFADDR:
1204                        r = ioctl(s, cmd, (struct ifreq *) param);
1205                        break;
1206
1207                default:
1208                        errno = EOPNOTSUPP;
1209                        r = -1;
1210                        break;
1211        }
1212
1213        rtems_bsdnet_semaphore_release ();
1214
1215        close (s);
1216        return r;
1217}
1218
1219/**
1220 * @brief Splits a network interface name with interface configuration @a
1221 * config into the unit name and number parts.
1222 *
1223 * Memory for the unit name will be allocated from the heap and copied to @a
1224 * namep.  If @a namep is NULL nothing will be allocated and copied.
1225 *
1226 * Returns the unit number or -1 on error.
1227 */
1228int
1229rtems_bsdnet_parse_driver_name (const struct rtems_bsdnet_ifconfig *config, char **namep)
1230{
1231        const char *cp = config->name;
1232        char c;
1233        int unitNumber = 0;
1234
1235        if (cp == NULL) {
1236                printf ("No network driver name.\n");
1237                return -1;
1238        }
1239        while ((c = *cp++) != '\0') {
1240                if ((c >= '0') && (c <= '9')) {
1241                        int len = cp - config->name;
1242                        if ((len < 2) || (len > 50))
1243                                break;
1244                        for (;;) {
1245                                unitNumber = (unitNumber * 10) + (c - '0');
1246                                c = *cp++;
1247                                if (c == '\0') {
1248                                        if (namep != NULL) {
1249                                                char *unitName = malloc (len);
1250                                                if (unitName == NULL) {
1251                                                        printf ("No memory.\n");
1252                                                        return -1;
1253                                                }
1254                                                strncpy (unitName, config->name, len - 1);
1255                                                unitName[len-1] = '\0';
1256                                                *namep = unitName;
1257                                        }
1258                                        return unitNumber;
1259                                }
1260                                if ((c < '0') || (c > '9'))
1261                                        break;
1262                        }
1263                        break;
1264                }
1265        }
1266        printf ("Bad network driver name `%s'.\n", config->name);
1267        return -1;
1268}
1269
1270/*
1271 * Handle requests for more network memory
1272 * XXX: Another possibility would be to use a semaphore here with
1273 *      a release in the mbuf free macro.  I have chosen this `polling'
1274 *      approach because:
1275 *      1) It is simpler.
1276 *      2) It adds no complexity to the free macro.
1277 *      3) Running out of mbufs should be a rare
1278 *         condition -- predeployment testing of
1279 *         an application should indicate the
1280 *         required mbuf pool size.
1281 * XXX: Should there be a panic if a task is stuck in the loop for
1282 *      more than a minute or so?
1283 */
1284int
1285m_mballoc(int nmb, int nowait)
1286{
1287        if (nowait)
1288                return 0;
1289        m_reclaim ();
1290        if (mmbfree == NULL) {
1291                int try = 0;
1292                int print_limit = 30 * rtems_bsdnet_ticks_per_second;
1293
1294                mbstat.m_wait++;
1295                for (;;) {
1296                        uint32_t nest_count = rtems_bsdnet_semaphore_release_recursive ();
1297                        rtems_task_wake_after (1);
1298                        rtems_bsdnet_semaphore_obtain_recursive (nest_count);
1299                        if (mmbfree)
1300                                break;
1301                        if (++try >= print_limit) {
1302                                printf ("Still waiting for mbuf.\n");
1303                                try = 0;
1304                        }
1305                }
1306        }
1307        else {
1308                mbstat.m_drops++;
1309        }
1310        return 1;
1311}
1312
1313int
1314m_clalloc(int ncl, int nowait)
1315{
1316        if (nowait)
1317                return 0;
1318        m_reclaim ();
1319        if (mclfree == NULL) {
1320                int try = 0;
1321                int print_limit = 30 * rtems_bsdnet_ticks_per_second;
1322
1323                mbstat.m_wait++;
1324                for (;;) {
1325                        uint32_t nest_count = rtems_bsdnet_semaphore_release_recursive ();
1326                        rtems_task_wake_after (1);
1327                        rtems_bsdnet_semaphore_obtain_recursive (nest_count);
1328                        if (mclfree)
1329                                break;
1330                        if (++try >= print_limit) {
1331                                printf ("Still waiting for mbuf cluster.\n");
1332                                try = 0;
1333                        }
1334                }
1335        }
1336        else {
1337                mbstat.m_drops++;
1338        }
1339        return 1;
1340}
1341
Note: See TracBrowser for help on using the repository browser.