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

4.115
Last change on this file since ae75429 was ae75429, checked in by Sebastian Huber <sebastian.huber@…>, on Aug 6, 2013 at 2:10:26 PM

PR766: Delete RTEMS_VIOLATE_KERNEL_VISIBILITY

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