source: rtems/cpukit/libnetworking/rtems/rtems_glue.c @ da10694

4.115
Last change on this file since da10694 was 69e3f27, checked in by Daniel Cederman <cederman@…>, on 11/14/14 at 07:58:00

net: Add network task affinity config

This patch adds a default network tasks CPU affinity configuration
option. The network drivers have the option to create their own
daemon tasks with a custom CPU affinity set, or rely on the
default set.

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