source: rtems/cpukit/libnetworking/rtems/rtems_glue.c @ 36799d4

4.104.114.84.95
Last change on this file since 36799d4 was 36799d4, checked in by Joel Sherrill <joel.sherrill@…>, on Jan 3, 2003 at 6:09:57 PM

2002-11-26 Chris Johns <cjohns@…>

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