source: rtems/cpukit/libnetworking/rtems/rtems_glue.c @ 4438ac25

4.115
Last change on this file since 4438ac25 was 4438ac25, checked in by Sebastian Huber <sebastian.huber@…>, on 05/02/15 at 12:27:24

score: Fine grained locking for mutexes

Update #2273.

  • Property mode set to 100644
File size: 28.9 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        else
288                networkDaemonPriority = rtems_bsdnet_config.network_task_priority;
289
290        /*
291         * Default network task CPU affinity
292         */
293#ifdef RTEMS_SMP
294        networkDaemonCpuset = rtems_bsdnet_config.network_task_cpuset;
295        networkDaemonCpusetSize = rtems_bsdnet_config.network_task_cpuset_size;
296#endif
297
298        /*
299         * Set the memory allocation limits
300         */
301        if (rtems_bsdnet_config.mbuf_bytecount)
302                nmbuf = rtems_bsdnet_config.mbuf_bytecount / MSIZE;
303        if (rtems_bsdnet_config.mbuf_cluster_bytecount)
304                nmbclusters = rtems_bsdnet_config.mbuf_cluster_bytecount / MCLBYTES;
305
306        rtems_set_udp_buffer_sizes(
307          rtems_bsdnet_config.udp_tx_buf_size,
308          rtems_bsdnet_config.udp_rx_buf_size
309        );
310
311        rtems_set_tcp_buffer_sizes(
312          rtems_bsdnet_config.tcp_tx_buf_size,
313          rtems_bsdnet_config.tcp_rx_buf_size
314        );
315
316        rtems_set_sb_efficiency( rtems_bsdnet_config.sb_efficiency );
317
318        /*
319         * Create the task-synchronization semaphore
320         */
321        sc = rtems_semaphore_create (rtems_build_name('B', 'S', 'D', 'n'),
322                                        0,
323                                        RTEMS_PRIORITY |
324                                                RTEMS_BINARY_SEMAPHORE |
325                                                RTEMS_INHERIT_PRIORITY |
326                                                RTEMS_NO_PRIORITY_CEILING |
327                                                RTEMS_LOCAL,
328                                        0,
329                                        &networkSemaphore);
330        if (sc != RTEMS_SUCCESSFUL) {
331                printf ("Can't create network seamphore: `%s'\n", rtems_status_text (sc));
332                return -1;
333        }
334#ifdef RTEMS_FAST_MUTEX
335        {
336        Objects_Locations location;
337        the_networkSemaphore = _Semaphore_Get( networkSemaphore, &location );
338        _Thread_Enable_dispatch();
339        }
340#endif
341
342        /*
343         * Compute clock tick conversion factors
344         */
345        rtems_bsdnet_ticks_per_second = rtems_clock_get_ticks_per_second();
346        if (rtems_bsdnet_ticks_per_second <= 0)
347                rtems_bsdnet_ticks_per_second = 1;
348        rtems_bsdnet_microseconds_per_tick =
349                1000000 / rtems_bsdnet_ticks_per_second;
350
351        /*
352         * Set up BSD-style sockets
353         */
354        if (bsd_init () < 0)
355                return -1;
356
357        /*
358         * Start network daemon
359         */
360        networkDaemonTid = rtems_bsdnet_newproc ("ntwk", 4096, networkDaemon, NULL);
361
362        /*
363         * Let other network tasks begin
364         */
365        rtems_bsdnet_semaphore_release ();
366
367        rtems_bsdnet_initialize_loop();
368
369        return 0;
370}
371
372/*
373 * Obtain network mutex
374 */
375void
376rtems_bsdnet_semaphore_obtain (void)
377{
378#ifdef RTEMS_FAST_MUTEX
379        ISR_lock_Context lock_context;
380        Thread_Control *executing;
381        _ISR_lock_ISR_disable(&lock_context);
382        if (!the_networkSemaphore)
383                rtems_panic ("rtems-net: network sema obtain: network not initialised\n");
384        executing = _Thread_Executing;
385        _CORE_mutex_Seize (
386                &the_networkSemaphore->Core_control.mutex,
387                executing,
388                networkSemaphore,
389                1,              /* wait */
390                0,              /* forever */
391                &lock_context
392                );
393        if (executing->Wait.return_code)
394                rtems_panic ("rtems-net: can't obtain network sema: %d\n",
395                 executing->Wait.return_code);
396#else
397        rtems_status_code sc;
398
399        sc = rtems_semaphore_obtain (networkSemaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
400        if (sc != RTEMS_SUCCESSFUL)
401                rtems_panic ("rtems-net: can't obtain network semaphore: `%s'\n",
402                 rtems_status_text (sc));
403#endif
404}
405
406/*
407 * Release network mutex
408 */
409void
410rtems_bsdnet_semaphore_release (void)
411{
412#ifdef RTEMS_FAST_MUTEX
413        ISR_lock_Context lock_context;
414        CORE_mutex_Status status;
415
416        if (!the_networkSemaphore)
417                rtems_panic ("rtems-net: network sema obtain: network not initialised\n");
418        _ISR_lock_ISR_disable(&lock_context);
419        status = _CORE_mutex_Surrender (
420                &the_networkSemaphore->Core_control.mutex,
421                networkSemaphore,
422                NULL,
423                &lock_context
424                );
425        if (status != CORE_MUTEX_STATUS_SUCCESSFUL)
426                rtems_panic ("rtems-net: can't release network sema: %i\n");
427#else
428        rtems_status_code sc;
429
430        sc = rtems_semaphore_release (networkSemaphore);
431        if (sc != RTEMS_SUCCESSFUL)
432                rtems_panic ("rtems-net: can't release network semaphore: `%s'\n",
433                 rtems_status_text (sc));
434#endif
435}
436
437static int
438rtems_bsdnet_sleep(rtems_event_set in, rtems_interval ticks)
439{
440        rtems_status_code sc;
441        rtems_event_set out;
442        rtems_event_set out2;
443
444        in |= RTEMS_EVENT_SYSTEM_NETWORK_CLOSE;
445
446        /*
447         * Soak up any pending events.  The sleep/wakeup synchronization in the
448         * FreeBSD kernel has no memory.
449         */
450        rtems_event_system_receive(in, RTEMS_EVENT_ANY | RTEMS_NO_WAIT,
451            RTEMS_NO_TIMEOUT, &out);
452
453        /*
454         * Wait for the wakeup event.
455         */
456        sc = rtems_bsdnet_event_receive(in, RTEMS_EVENT_ANY | RTEMS_WAIT,
457            ticks, &out);
458
459        /*
460         * Get additional events that may have been received between the
461         * rtems_event_system_receive() and the rtems_bsdnet_semaphore_obtain().
462         */
463        rtems_event_system_receive(in, RTEMS_EVENT_ANY | RTEMS_NO_WAIT,
464            RTEMS_NO_TIMEOUT, &out2);
465        out |= out2;
466
467        if (out & RTEMS_EVENT_SYSTEM_NETWORK_CLOSE)
468                return (ENXIO);
469
470        if (sc == RTEMS_SUCCESSFUL)
471                return (0);
472
473        return (EWOULDBLOCK);
474}
475
476/*
477 * Wait for something to happen to a socket buffer
478 */
479int
480sbwait(struct sockbuf *sb)
481{
482        int error;
483
484        /*
485         * Set this task as the target of the wakeup operation.
486         */
487        sb->sb_sel.si_pid = rtems_task_self();
488
489        /*
490         * Show that socket is waiting
491         */
492        sb->sb_flags |= SB_WAIT;
493
494        error = rtems_bsdnet_sleep(SBWAIT_EVENT, sb->sb_timeo);
495        if (error != ENXIO)
496                sb->sb_flags &= ~SB_WAIT;
497
498        return (error);
499}
500
501
502/*
503 * Wake up the task waiting on a socket buffer.
504 */
505void
506sowakeup(
507        struct socket *so,
508        struct sockbuf *sb)
509{
510        if (sb->sb_flags & SB_WAIT) {
511                rtems_event_system_send (sb->sb_sel.si_pid, SBWAIT_EVENT);
512        }
513        if (sb->sb_wakeup) {
514                (*sb->sb_wakeup) (so, sb->sb_wakeuparg);
515        }
516}
517
518/*
519 * For now, a socket can be used by only one task at a time.
520 */
521int
522sb_lock(struct sockbuf *sb)
523{
524        rtems_panic ("Socket buffer is already in use.");
525        return 0;
526}
527void
528wakeup (void *p)
529{
530        rtems_panic ("Wakeup called");
531}
532
533/*
534 * Wait for a connection/disconnection event.
535 */
536int
537soconnsleep (struct socket *so)
538{
539        int error;
540
541        /*
542         * Set this task as the target of the wakeup operation.
543         */
544        if (so->so_pgid)
545                rtems_panic ("Another task is already sleeping on that socket");
546        so->so_pgid = rtems_task_self();
547
548        error = rtems_bsdnet_sleep(SOSLEEP_EVENT, so->so_rcv.sb_timeo);
549        if (error != ENXIO)
550                so->so_pgid = 0;
551
552        return (error);
553}
554
555/*
556 * Wake up a task waiting for a connection/disconnection to complete.
557 */
558void
559soconnwakeup (struct socket *so)
560{
561        if (so->so_pgid)
562                rtems_event_system_send (so->so_pgid, SOSLEEP_EVENT);
563}
564
565/*
566 * Send an event to the network daemon.
567 * This corresponds to sending a software interrupt in the BSD kernel.
568 */
569void
570rtems_bsdnet_schednetisr (int n)
571{
572        rtems_event_system_send (networkDaemonTid, 1 << n);
573}
574
575/*
576 * The network daemon
577 * This provides a context to run BSD software interrupts
578 */
579static void
580networkDaemon (void *task_argument)
581{
582        rtems_status_code sc;
583        rtems_event_set events;
584        rtems_interval now;
585        int ticksPassed;
586        uint32_t   timeout;
587        struct callout *c;
588
589        for (;;) {
590                c = calltodo.c_next;
591                if (c)
592                        timeout = c->c_time;
593                else
594                        timeout = RTEMS_NO_TIMEOUT;
595
596                sc = rtems_bsdnet_event_receive (NETISR_EVENTS,
597                                                RTEMS_EVENT_ANY | RTEMS_WAIT,
598                                                timeout,
599                                                &events);
600                if ( sc == RTEMS_SUCCESSFUL ) {
601                        if (events & NETISR_IP_EVENT)
602                                ipintr ();
603                        if (events & NETISR_ARP_EVENT)
604                                arpintr ();
605                }
606
607                now = rtems_clock_get_ticks_since_boot();
608                ticksPassed = now - ticksWhenCalloutsLastChecked;
609                if (ticksPassed != 0) {
610                        ticksWhenCalloutsLastChecked = now;
611
612                        c = calltodo.c_next;
613                        if (c) {
614                                c->c_time -= ticksPassed;
615                                while ((c = calltodo.c_next) != NULL && c->c_time <= 0) {
616                                        void *arg;
617                                        void (*func) (void *);
618
619                                        func = c->c_func;
620                                        arg = c->c_arg;
621                                        calltodo.c_next = c->c_next;
622                                        c->c_next = callfree;
623                                        callfree = c;
624                                        (*func)(arg);
625                                }
626                        }
627                }
628        }
629}
630
631/*
632 * Structure passed to task-start stub
633 */
634struct newtask {
635        void (*entry)(void *);
636        void *arg;
637};
638
639/*
640 * Task-start stub
641 */
642static void
643taskEntry (rtems_task_argument arg)
644{
645        struct newtask t;
646
647        /*
648         * Pick up task information and free
649         * the memory allocated to pass the
650         * information to this task.
651         */
652        t = *(struct newtask *)arg;
653        free ((struct newtask *)arg);
654
655        /*
656         * Enter the competition for the network semaphore
657         */
658        rtems_bsdnet_semaphore_obtain ();
659
660        /*
661         * Enter the task
662         */
663        (*t.entry)(t.arg);
664        rtems_panic ("Network task returned!\n");
665}
666
667
668/*
669 * Start a network task
670 */
671#ifdef RTEMS_SMP
672rtems_id
673rtems_bsdnet_newproc (char *name, int stacksize, void(*entry)(void *), void *arg)
674{
675        return rtems_bsdnet_newproc_affinity( name, stacksize, entry, arg,
676                networkDaemonCpuset, networkDaemonCpusetSize );
677}
678
679rtems_id
680rtems_bsdnet_newproc_affinity (char *name, int stacksize, void(*entry)(void *),
681    void *arg, const cpu_set_t *set, const size_t setsize)
682#else
683rtems_id
684rtems_bsdnet_newproc (char *name, int stacksize, void(*entry)(void *), void *arg)
685#endif
686{
687        struct newtask *t;
688        char nm[4];
689        rtems_id tid;
690        rtems_status_code sc;
691
692        strncpy (nm, name, 4);
693        sc = rtems_task_create (rtems_build_name(nm[0], nm[1], nm[2], nm[3]),
694                networkDaemonPriority,
695                stacksize,
696                RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0),
697                RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL,
698                &tid);
699        if (sc != RTEMS_SUCCESSFUL)
700                rtems_panic ("Can't create network daemon `%s': `%s'\n", name, rtems_status_text (sc));
701
702#ifdef RTEMS_SMP
703        /*
704         * Use the default affinity or use the user-provided CPU set
705         */
706        if ( set != 0 )
707                rtems_task_set_affinity( tid, setsize, set );
708#endif
709
710        /*
711         * Set up task arguments
712         */
713        t = malloc (sizeof *t);
714        t->entry = entry;
715        t->arg = arg;
716
717        /*
718         * Start the task
719         */
720        sc = rtems_task_start (tid, taskEntry, (rtems_task_argument)t);
721        if (sc != RTEMS_SUCCESSFUL)
722                rtems_panic ("Can't start network daemon `%s': `%s'\n", name, rtems_status_text (sc));
723
724        /*
725         * Let our caller know the i.d. of the new task
726         */
727        return tid;
728}
729
730rtems_status_code rtems_bsdnet_event_receive (
731  rtems_event_set  event_in,
732  rtems_option     option_set,
733  rtems_interval   ticks,
734  rtems_event_set *event_out)
735{
736        rtems_status_code sc;
737
738        rtems_bsdnet_semaphore_release ();
739        sc = rtems_event_system_receive (event_in, option_set, ticks, event_out);
740        rtems_bsdnet_semaphore_obtain ();
741        return sc;
742}
743
744/*
745 * Fake random number generator
746 */
747unsigned long
748rtems_bsdnet_random (void)
749{
750        rtems_interval now;
751
752        now = rtems_clock_get_ticks_since_boot();
753        return (now * 99991);
754}
755
756/*
757 * Callout list processing
758 */
759void
760rtems_bsdnet_timeout(void (*ftn)(void *), void *arg, int ticks)
761{
762        register struct callout *new, *p, *t;
763
764        if (ticks <= 0)
765                ticks = 1;
766
767        /* Fill in the next free callout structure. */
768        if (callfree == NULL) {
769                callfree = malloc (sizeof *callfree);
770                if (callfree == NULL)
771                        rtems_panic ("No memory for timeout table entry");
772                callfree->c_next = NULL;
773        }
774
775        new = callfree;
776        callfree = new->c_next;
777        new->c_arg = arg;
778        new->c_func = ftn;
779
780        /*
781         * The time for each event is stored as a difference from the time
782         * of the previous event on the queue.  Walk the queue, correcting
783         * the ticks argument for queue entries passed.  Correct the ticks
784         * value for the queue entry immediately after the insertion point
785         * as well.  Watch out for negative c_time values; these represent
786         * overdue events.
787         */
788        for (p = &calltodo;
789            (t = p->c_next) != NULL && ticks > t->c_time; p = t)
790                if (t->c_time > 0)
791                        ticks -= t->c_time;
792        new->c_time = ticks;
793        if (t != NULL)
794                t->c_time -= ticks;
795
796        /* Insert the new entry into the queue. */
797        p->c_next = new;
798        new->c_next = t;
799}
800
801/*
802 * Ticks till specified time
803 * XXX: This version worries only about seconds, but that's good
804 * enough for the way the network code uses this routine.
805 */
806int
807hzto(struct timeval *tv)
808{
809        long diff = tv->tv_sec - rtems_bsdnet_seconds_since_boot();
810
811        if (diff <= 0)
812                return 1;
813        return diff * rtems_bsdnet_ticks_per_second;
814}
815
816/*
817 * Kernel debugging
818 */
819int rtems_bsdnet_log_priority;
820void
821rtems_bsdnet_log (int priority, const char *fmt, ...)
822{
823        va_list args;
824
825        if (priority & rtems_bsdnet_log_priority) {
826                va_start (args, fmt);
827                vprintf (fmt, args);
828                va_end (args);
829        }
830}
831
832/*
833 * IP header checksum routine for processors which don't have an inline version
834 */
835u_int
836in_cksum_hdr (const void *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
1342void microtime(struct timeval *tv)
1343{
1344        rtems_clock_get_uptime_timeval(tv);
1345}
Note: See TracBrowser for help on using the repository browser.