source: rtems/cpukit/libnetworking/rtems/rtems_glue.c @ 787f51f

5
Last change on this file since 787f51f was 787f51f, checked in by Sebastian Huber <sebastian.huber@…>, on 06/06/17 at 09:08:16

Do not include <sys/ioctl.h> in kernel-space

Update #2833.

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