]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/net/ppp/v2_0/src/sys-ecos.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / net / ppp / v2_0 / src / sys-ecos.c
1 //==========================================================================
2 //
3 //      src/sys-ecos.c
4 //
5 //==========================================================================
6 //####ECOSGPLCOPYRIGHTBEGIN####
7 // -------------------------------------------
8 // This file is part of eCos, the Embedded Configurable Operating System.
9 // Portions created by Nick Garnett are
10 // Copyright (C) 2003, 2004 eCosCentric Ltd.
11 //
12 // eCos is free software; you can redistribute it and/or modify it under
13 // the terms of the GNU General Public License as published by the Free
14 // Software Foundation; either version 2 or (at your option) any later version.
15 //
16 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
17 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19 // for more details.
20 //
21 // You should have received a copy of the GNU General Public License along
22 // with eCos; if not, write to the Free Software Foundation, Inc.,
23 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
24 //
25 // As a special exception, if other files instantiate templates or use macros
26 // or inline functions from this file, or you compile this file and link it
27 // with other works to produce a work based on this file, this file does not
28 // by itself cause the resulting work to be covered by the GNU General Public
29 // License. However the source code for this file must still be made available
30 // in accordance with section (3) of the GNU General Public License.
31 //
32 // This exception does not invalidate any other reasons why a work based on
33 // this file might be covered by the GNU General Public License.
34 //
35 // -------------------------------------------
36 //####ECOSGPLCOPYRIGHTEND####
37 //####BSDCOPYRIGHTBEGIN####
38 //
39 // -------------------------------------------
40 //
41 // Portions of this software may have been derived from OpenBSD, 
42 // FreeBSD or other sources, and are covered by the appropriate
43 // copyright disclaimers included herein.
44 //
45 // -------------------------------------------
46 //
47 //####BSDCOPYRIGHTEND####
48 //==========================================================================
49
50 /*
51  * sys-bsd.c - System-dependent procedures for setting up
52  * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.)
53  *
54  * Copyright (c) 1989 Carnegie Mellon University.
55  * Copyright (c) 1995 The Australian National University.
56  * All rights reserved.
57  *
58  * Redistribution and use in source and binary forms are permitted
59  * provided that the above copyright notice and this paragraph are
60  * duplicated in all such forms and that any documentation,
61  * advertising materials, and other materials related to such
62  * distribution and use acknowledge that the software was developed
63  * by Carnegie Mellon University and The Australian National University.
64  * The names of the Universities may not be used to endorse or promote
65  * products derived from this software without specific prior written
66  * permission.
67  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
68  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
69  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
70  */
71
72 #ifndef lint
73 //static char rcsid[] = "$FreeBSD: src/usr.sbin/pppd/sys-bsd.c,v 1.17 1999/08/28 01:19:08 peter Exp $";
74 #endif
75 /*      $NetBSD: sys-bsd.c,v 1.1.1.3 1997/09/26 18:53:04 christos Exp $ */
76
77 /*
78  * TODO:
79  */
80
81 //==========================================================================
82
83 #include <pkgconf/system.h>
84 #include <pkgconf/net.h>
85 #include <pkgconf/ppp.h>
86
87 #include <stdio.h>
88 #include <string.h>
89 #include <stdlib.h>
90 #include <unistd.h>
91 #include <errno.h>
92 #include <fcntl.h>
93 #include <termios.h>
94 #include <signal.h>
95 #define _KERNEL 1
96 #include <sys/param.h>
97 #undef _KERNEL
98 #include <sys/ioctl.h>
99 #include <sys/types.h>
100 #include <sys/socket.h>
101 #include <sys/time.h>
102 #include <sys/stat.h>
103 #ifdef NetBSD1_2
104 #include <util.h>
105 #endif
106 #ifdef PPP_FILTER
107 #include <net/bpf.h>
108 #endif
109
110 #include <cyg/ppp/syslog.h>
111
112 #include <net/if.h>
113 #include <cyg/ppp/net/ppp_defs.h>
114 #include <cyg/ppp/net/if_ppp.h>
115 #include <net/route.h>
116 #include <net/if_dl.h>
117 #include <netinet/in.h>
118
119 #ifdef IPX_CHANGE
120 #include <netipx/ipx.h>
121 #endif
122
123 #if RTM_VERSION >= 3
124 #include <sys/param.h>
125 #if defined(NetBSD) && (NetBSD >= 199703)
126 #include <netinet/if_inarp.h>
127 #else   /* NetBSD 1.2D or later */
128 #include <netinet/if_ether.h>
129 #endif
130 #endif
131
132 #include "cyg/ppp/pppd.h"
133 #include "cyg/ppp/fsm.h"
134 #include "cyg/ppp/ipcp.h"
135
136 #include "cyg/ppp/ppp_io.h"
137
138 #include <cyg/ppp/ppp.h>
139
140 //==========================================================================
141
142 static int rtm_seq;
143
144 static cyg_io_handle_t ppp_handle; /* IO subsystem handle to PPP stream */
145 struct tty ppp_tty;             /* dummy TTY structure */
146
147 static cyg_handle_t ppp_rtc;
148 static cyg_resolution_t ppp_rtc_resolution;
149
150 static int loop_slave = -1;
151 static int loop_master;
152
153 static unsigned char inbuf[PPP_MTU + PPP_HDRLEN + 100]; /* buffer for chars read from input */
154
155 static int sockfd = -1;         /* socket for doing interface ioctls */
156
157 static int if_is_up;            /* the interface is currently up */
158 static u_int32_t ifaddrs[2];    /* local and remote addresses we set */
159 static u_int32_t default_route_gateway; /* gateway addr for default route */
160 static u_int32_t proxy_arp_addr;        /* remote addr for proxy arp */
161
162 /* Prototypes for procedures local to this file. */
163 static int dodefaultroute __P((u_int32_t, int));
164 static int get_ether_addr __P((u_int32_t, struct sockaddr_dl *));
165
166 static void wait_input_alarm(cyg_handle_t alarm, cyg_addrword_t data);
167 #ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
168 void cyg_ppp_serial_callback( cyg_serial_line_status_t *s,
169                                      CYG_ADDRWORD priv );
170 #endif
171
172 extern u_int32_t netmask;       /* IP netmask to set on interface */
173
174 //==========================================================================
175 /*
176  * sys_init - System-dependent initialization.
177  */
178 void
179 sys_init()
180 {
181     if( sockfd == -1 )
182     {
183         /* Get an internet socket for doing socket ioctl's on. */
184         if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
185             syslog(LOG_ERR, "Couldn't create IP socket: %d",errno);
186             die(1);
187         }
188     }
189
190     ppp_tty.pppd_wakeup = 0;
191     ppp_tty.pppd_thread_running = true;
192     
193     ppp_rtc = cyg_real_time_clock();
194     ppp_rtc_resolution = cyg_clock_get_resolution( ppp_rtc );
195
196     cyg_alarm_create( ppp_rtc,
197                       wait_input_alarm,
198                       (cyg_addrword_t)&ppp_tty,
199                       &ppp_tty.alarm,
200                       &ppp_tty.alarm_obj);
201 }
202
203 //==========================================================================
204 /*
205  * sys_cleanup - restore any system state we modified before exiting:
206  * mark the interface down, delete default route and/or proxy arp entry.
207  * This should call die() because it's called from die().
208  */
209 void
210 sys_cleanup()
211 {
212     struct ifreq ifr;
213
214 db_printf("%s called\n", __PRETTY_FUNCTION__);
215     if (if_is_up) {
216         strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
217         if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) >= 0
218             && ((ifr.ifr_flags & IFF_UP) != 0)) {
219             ifr.ifr_flags &= ~IFF_UP;
220             ioctl(sockfd, SIOCSIFFLAGS, &ifr);
221         }
222     }
223     if (ifaddrs[0] != 0)
224         cifaddr(0, ifaddrs[0], ifaddrs[1]);
225     if (default_route_gateway)
226         cifdefaultroute(0, 0, default_route_gateway);
227     if (proxy_arp_addr)
228         cifproxyarp(0, proxy_arp_addr);
229
230     if( sockfd != -1 )
231     {
232         close(sockfd);
233         sockfd = -1;
234     }
235 }
236
237 //==========================================================================
238
239 #ifdef __ECOS
240
241 void
242 sys_exit(void)
243 {
244 db_printf("%s called\n", __PRETTY_FUNCTION__);    
245     phase = PHASE_DEAD;
246     while( ppp_tty.tx_thread_running )
247     {
248         db_printf("kick tx thread\n");        
249         cyg_semaphore_post( &ppp_tty.tx_sem );
250         cyg_thread_delay(100);
251     }
252     ppp_tty.pppd_thread_running = false;
253     cyg_thread_exit();
254 }
255 #endif
256
257 //==========================================================================
258 /*
259  * sys_close - Clean up in a child process before execing.
260  */
261 void
262 sys_close()
263 {
264 db_printf("%s called\n", __PRETTY_FUNCTION__);
265     if (loop_slave >= 0) {
266         close(loop_slave);
267         close(loop_master);
268     }
269 }
270
271 //==========================================================================
272 /*
273  * sys_check_options - check the options that the user specified
274  */
275 void
276 sys_check_options()
277 {
278 //db_printf("%s called\n", __PRETTY_FUNCTION__);
279 }
280
281 //==========================================================================
282 /*
283  * ppp_available - check whether the system has any ppp interfaces
284  * (in fact we check whether we can do an ioctl on ppp0).
285  */
286 int
287 ppp_available()
288 {
289     int s, ok;
290     struct ifreq ifr;
291     extern char *no_ppp_msg;
292
293     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
294         return 1;               /* can't tell */
295
296     strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
297     ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
298     close(s);
299
300     no_ppp_msg = "\
301 This system lacks kernel support for PPP.  To include PPP support\n\
302 in the kernel, please follow the steps detailed in the README.bsd\n\
303 file in the ppp-2.2 distribution.\n";
304     return ok;
305 }
306
307 //==========================================================================
308 /*
309  * establish_ppp - Turn the serial port into a ppp interface.
310  */
311 void
312 establish_ppp(cyg_io_handle_t handle)
313 {
314     int s;
315     int x;
316     int err;
317     
318 //db_printf("%s called\n", __PRETTY_FUNCTION__);
319
320     ppp_handle = ppp_tty.t_handle = handle;
321     ppp_tty.t_sc = NULL;
322
323     s = splsoftnet();
324
325     err = cyg_ppp_pppopen( &ppp_tty );
326     
327     if( err != 0 )
328         syslog( LOG_ERR, "Couldn't establish PPP interface: %d", err );
329
330     /*
331      * Enable debug in the driver if requested.
332      */
333     if (kdebugflag) {
334         if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCGFLAGS, (caddr_t) &x, 0)) < 0) {
335             syslog(LOG_WARNING, "ioctl (PPPIOCGFLAGS): %d",err);
336         } else {
337             x |= (kdebugflag & 0xFF) * SC_DEBUG;
338             if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSFLAGS, (caddr_t) &x, 0)) < 0)
339                 syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %d",err);
340         }
341     }
342
343     splx(s);
344 }
345
346 //==========================================================================
347 /*
348  * restore_loop - reattach the ppp unit to the loopback.
349  */
350 void
351 restore_loop()
352 {
353 db_printf("%s called\n", __PRETTY_FUNCTION__);
354 }
355
356
357 //==========================================================================
358 /*
359  * disestablish_ppp - Restore the serial port to normal operation.
360  * This shouldn't call die() because it's called from die().
361  */
362 void
363 disestablish_ppp(cyg_io_handle_t handle)
364 {
365     db_printf("%s called\n", __PRETTY_FUNCTION__);
366 }
367
368 //==========================================================================
369 /*
370  * Check whether the link seems not to be 8-bit clean.
371  */
372 void
373 clean_check()
374 {
375 db_printf("%s called\n", __PRETTY_FUNCTION__);
376 }
377
378 //==========================================================================
379 /*
380  * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
381  * at the requested speed, etc.  If `local' is true, set CLOCAL
382  * regardless of whether the modem option was specified.
383  *
384  * For *BSD, we assume that speed_t values numerically equal bits/second.
385  */
386 void
387 set_up_tty(cyg_io_handle_t handle, int local)
388 {
389     cyg_serial_info_t   cfg;
390     int                 err;
391     cyg_uint32          len = sizeof(cfg);
392
393     err = cyg_io_get_config( handle,
394                              CYG_IO_GET_CONFIG_SERIAL_INFO,
395                              &cfg,
396                              &len);
397
398     if( err != 0 ) {
399         syslog(LOG_ERR, "cyg_io_get_config: %d",err);
400         die(1);
401     }
402
403     switch ( flowctl )
404     {
405     case CYG_PPP_FLOWCTL_DEFAULT:
406         break;
407         
408     case CYG_PPP_FLOWCTL_NONE:
409         cfg.flags &= ~(CYGNUM_SERIAL_FLOW_RTSCTS_RX|CYGNUM_SERIAL_FLOW_RTSCTS_TX|
410                        CYGNUM_SERIAL_FLOW_XONXOFF_RX|CYGNUM_SERIAL_FLOW_XONXOFF_TX);
411         break;
412         
413     case CYG_PPP_FLOWCTL_HARDWARE:
414         cfg.flags &= ~(CYGNUM_SERIAL_FLOW_XONXOFF_RX|CYGNUM_SERIAL_FLOW_XONXOFF_TX);
415         cfg.flags |= CYGNUM_SERIAL_FLOW_RTSCTS_RX|CYGNUM_SERIAL_FLOW_RTSCTS_TX;
416         break;
417         
418     case CYG_PPP_FLOWCTL_SOFTWARE:
419         cfg.flags &= ~(CYGNUM_SERIAL_FLOW_RTSCTS_RX|CYGNUM_SERIAL_FLOW_RTSCTS_TX);
420         cfg.flags |= CYGNUM_SERIAL_FLOW_XONXOFF_RX|CYGNUM_SERIAL_FLOW_XONXOFF_TX;
421         break;
422     }
423
424     if( inspeed != 0 )
425         cfg.baud = inspeed;
426     
427     err = cyg_io_set_config( handle,
428                              CYG_IO_SET_CONFIG_SERIAL_INFO,
429                              &cfg,
430                              &len);
431
432     if( err != 0 ) {
433         syslog(LOG_ERR, "cyg_io_set_config: %d",err);
434         die(1);
435     }
436 }
437
438 //==========================================================================
439 /*
440  * restore_tty - restore the terminal to the saved settings.
441  */
442 void
443 restore_tty(cyg_io_handle_t handle)
444 {
445 #ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
446     if( modem )
447     {
448         // Restore callback handler if it was set.
449         
450         Cyg_ErrNo err;
451         cyg_uint32 len = sizeof(ppp_tty.serial_callbacks);
452
453         db_printf("%s called\n", __PRETTY_FUNCTION__);
454                 
455         err = cyg_io_set_config( handle,
456                                  CYG_IO_SET_CONFIG_SERIAL_STATUS_CALLBACK,
457                                  &ppp_tty.serial_callbacks,
458                                  &len);
459
460         if( err != 0 ) {
461             syslog(LOG_ERR, "cyg_io_set_config(restore serial callbacks): %d",err);
462             die(1);
463         }
464     }
465 #endif
466 }
467
468 //==========================================================================
469 /*
470  * setdtr - control the DTR line on the serial port.
471  * This is called from die(), so it shouldn't call die().
472  */
473 void
474 setdtr(fd, on)
475 int fd, on;
476 {
477 db_printf("%s called\n", __PRETTY_FUNCTION__);
478 }
479
480 //==========================================================================
481 /*
482  * output - Output PPP packet.
483  */
484 void
485 output(unit, p, len)
486     int unit;
487     u_char *p;
488     int len;
489 {
490     Cyg_ErrNo err;
491     struct uio uio;
492     struct iovec iov;
493     int s;
494     
495     if (debug)
496         log_packet(p, len, "sent ", LOG_DEBUG);
497
498
499     iov.iov_base    = p;
500     iov.iov_len     = len;
501     uio.uio_iov     = &iov;
502     uio.uio_iovcnt  = 1;
503     uio.uio_resid   = len;
504     uio.uio_segflg  = UIO_USERSPACE;
505     uio.uio_rw      = UIO_WRITE;
506
507     s = splsoftnet();
508     
509     err = cyg_ppp_pppwrite( &ppp_tty, &uio, 0 );
510
511     splx(s);
512     
513     if( err != 0 )
514         syslog(LOG_ERR, "write: %d",err);
515
516 }
517
518 //==========================================================================
519
520 #ifdef __ECOS
521
522 static void wait_input_alarm(cyg_handle_t alarm, cyg_addrword_t data)
523 {
524     cyg_thread_release( ppp_tty.pppd_thread );
525     ppp_tty.pppd_wakeup = 1;
526 }
527
528 #ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
529 void cyg_ppp_serial_callback( cyg_serial_line_status_t *s,
530                                      CYG_ADDRWORD priv )
531 {
532     externC int kill_link;
533
534 //    db_printf("serial callback %d %x\n",s->which, s->value );
535
536     if( s->which == CYGNUM_SERIAL_STATUS_CARRIERDETECT )
537     {
538         if( s->value == 0 )
539         {
540             // CD lost
541             ppp_tty.carrier_detected = 0;
542             kill_link = 1;
543             cyg_thread_release( ppp_tty.pppd_thread );
544             ppp_tty.pppd_wakeup = 1;
545         }
546         else
547         {
548             // CD up
549             ppp_tty.carrier_detected = 1;
550         }
551     }
552 }
553 #endif
554
555 static void cyg_ppp_tx_thread(CYG_ADDRWORD arg)
556 {
557     ppp_tty.tx_thread_running = true;
558
559     // Wait for the PPPD thread to get going and start the PPP
560     // initialization phase.
561     while(phase == PHASE_DEAD)
562         cyg_thread_delay(100);
563
564     // Now loop until the link goes back down.
565     while( phase != PHASE_DEAD )
566     {
567         cyg_semaphore_wait( &ppp_tty.tx_sem );
568
569         if( phase == PHASE_DEAD )
570             break;
571         
572         // Call into PPP driver to get transmissions going. This is
573         // only called if some other thread has failed to transmit all
574         // of a packet due to a full buffer, or flow control.
575
576         cyg_ppp_pppstart( &ppp_tty );
577     }
578
579 db_printf("%s exiting\n", __PRETTY_FUNCTION__);        
580     ppp_tty.tx_thread_running = false;
581     cyg_thread_exit();
582 }
583
584 #endif
585
586
587 //==========================================================================
588 /*
589  * wait_input - wait until there is data available on ttyfd,
590  * for the length of time specified by *timo (indefinite
591  * if timo is NULL).
592  */
593 void
594 wait_input(timo)
595     struct timeval *timo;
596 {
597     // If there are any packets still waiting on the input queue then
598     // return immediately to let the PPPD handle them.
599     if (cyg_ppp_pppcheck(&ppp_tty) != 0)
600         return;
601
602     if( timo != NULL )
603     {
604         cyg_tick_count_t trigger = timo->tv_sec*ppp_rtc_resolution.divisor;
605
606         // If the timeval has a microseconds value, just add another
607         // second on to the trigger time. These are after all just
608         // timeouts, not accurate timings, so a bit of imprecision
609         // will not hurt.
610         if( timo->tv_usec != 0 )
611             trigger += ppp_rtc_resolution.divisor;            
612
613         trigger += cyg_current_time();
614
615         // We set the alarm to retrigger after a second. This is in
616         // case it catches cyg_io_read() at an uninterruptible
617         // point. The alarm is disabled as soon as the read returns,
618         // so the retrigger will usually not happen.
619         cyg_alarm_initialize( ppp_tty.alarm,
620                               trigger,
621                               ppp_rtc_resolution.divisor );
622     }
623     
624     for(;;)
625     {
626         int s;
627         cyg_uint32 len = 1;
628         Cyg_ErrNo err;
629         cyg_serial_buf_info_t info;
630         cyg_uint32 ilen = sizeof(info);
631
632 #if 1
633         // Work out how many bytes are waiting in the serial device
634         // buffer and read them all at once. If there are none, we
635         // just wait for a single character to arrive.
636        
637         if( cyg_io_get_config( ppp_tty.t_handle, CYG_IO_GET_CONFIG_SERIAL_BUFFER_INFO,
638                                &info, &ilen ) == 0 && info.rx_count > 1 )
639         {
640             len = info.rx_count-1;
641             if( len > sizeof(inbuf) )
642                 len = sizeof(inbuf);
643         }
644 #endif
645         
646         if( timo != NULL )
647             cyg_alarm_enable( ppp_tty.alarm );
648
649         err = cyg_io_read( ppp_handle, &inbuf, &len );
650
651         if( timo != NULL )
652             cyg_alarm_disable( ppp_tty.alarm );
653         
654 //        db_printf("read: err %d len %d byte %02x\n",err,len,inbuf[0]);
655         
656         if( err == 0 )
657         {
658             int i;
659             
660             // Pass all input data to PPP driver for analysis. If this
661             // turns out to be for the PPPD, it will call
662             // pppasyncctlp() which in turn will set
663             // ppp_tty.pppd_wakeup. We detect that on return from
664             // pppinput() and return to the caller to do pppd
665             // processing.
666
667             s = splsoftnet();
668             
669             for( i = 0; i < len; i++ )
670             {
671                 err = cyg_ppp_pppinput( inbuf[i], &ppp_tty );
672                 
673                 if( err != 0 )
674                     syslog( LOG_ERR, "pppinput error: %d", err);
675
676             }
677
678             splx(s);
679             
680         }
681         else if( err != -EINTR )
682             syslog( LOG_ERR, "Read error: %d",err);
683
684         if( ppp_tty.pppd_wakeup )
685         {
686             ppp_tty.pppd_wakeup = 0;
687             break;
688         }
689     }
690 }
691
692 //==========================================================================
693 /*
694  * wait_time - wait for a given length of time or until a
695  * signal is received.
696  */
697 void
698 wait_time(timo)
699     struct timeval *timo;
700 {
701 db_printf("%s called\n", __PRETTY_FUNCTION__);
702 }
703
704
705 //==========================================================================
706 /*
707  * read_packet - get a PPP packet from the serial device.
708  */
709 int
710 read_packet(buf)
711     u_char *buf;
712 {
713     int err;
714     struct uio uio;
715     struct iovec iov;
716     int len = PPP_MTU + PPP_HDRLEN;
717     int s;
718     
719 //db_printf("%s called\n", __PRETTY_FUNCTION__);
720     
721     iov.iov_base        = buf;
722     iov.iov_len         = len;
723     uio.uio_iov         = &iov;
724     uio.uio_iovcnt      = 1;
725     uio.uio_resid       = len;
726     uio.uio_segflg      = UIO_USERSPACE;
727     uio.uio_rw          = UIO_READ;
728
729     s = splsoftnet();
730     
731     err = cyg_ppp_pppread( &ppp_tty, &uio, 0 );
732
733     splx(s);
734     
735     if( err == EWOULDBLOCK )
736         return -1;
737     
738     if( err != 0 )
739     {
740         syslog(LOG_ERR, "pppread: %d",err);
741         die(1);
742     }
743
744     len -= uio.uio_resid;
745
746     return len;
747 }
748
749 //==========================================================================
750 /*
751  * ppp_send_config - configure the transmit characteristics of
752  * the ppp interface.
753  */
754 void
755 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
756     int unit, mtu;
757     u_int32_t asyncmap;
758     int pcomp, accomp;
759 {
760     u_int x;
761     struct ifreq ifr;
762     int err;
763     int s;
764     
765 //    db_printf("%s: unit %d mtu %d asyncmap %08x pcomp %08x accomp %08x\n", __PRETTY_FUNCTION__,
766 //              unit,mtu,asyncmap,pcomp,accomp);
767     
768     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
769     ifr.ifr_mtu = mtu;
770     if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
771         syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %d",errno);
772         quit();
773     }
774
775
776     s = splsoftnet();
777     
778     if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSASYNCMAP, (caddr_t) &asyncmap, 0)) < 0) {
779         syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %d",err);
780     }
781
782     if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCGFLAGS, (caddr_t) &x, 0)) < 0) {
783         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %d",err);
784     }
785     x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
786     x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
787     if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSFLAGS, (caddr_t) &x, 0)) < 0) {
788         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %d",err);
789     }
790
791     splx(s);
792 }
793
794
795 //==========================================================================
796 /*
797  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
798  */
799 void
800 ppp_set_xaccm(unit, accm)
801     int unit;
802     ext_accm accm;
803 {
804     int error;
805     int s;
806     
807 //db_printf("%s called\n", __PRETTY_FUNCTION__);
808
809     s = splsoftnet();
810         
811     error = cyg_ppp_ppptioctl( &ppp_tty, PPPIOCSXASYNCMAP, (caddr_t)accm, 0 );
812
813     splx(s);
814     
815     if( error != 0 )
816         syslog(LOG_WARNING, "ioctl(set extended ACCM): %d",error);
817 }
818
819
820 //==========================================================================
821 /*
822  * ppp_recv_config - configure the receive-side characteristics of
823  * the ppp interface.
824  */
825 void
826 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
827     int unit, mru;
828     u_int32_t asyncmap;
829     int pcomp, accomp;
830 {
831     int x;
832     int err;
833     int s;
834
835     s = splsoftnet();
836     
837     if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSMRU, (caddr_t) &mru, 0)) < 0) {
838         syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %d",err);
839     }
840     if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap, 0)) < 0) {
841         syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %d",err);
842     }
843     if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCGFLAGS, (caddr_t) &x, 0)) < 0) {
844         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %d",err);
845     }
846     x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
847     if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSFLAGS, (caddr_t) &x, 0)) < 0) {
848         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %d",err);
849     }
850
851     splx(s);
852 }
853
854 //==========================================================================
855 /*
856  * ccp_test - ask kernel whether a given compression method
857  * is acceptable for use.  Returns 1 if the method and parameters
858  * are OK, 0 if the method is known but the parameters are not OK
859  * (e.g. code size should be reduced), or -1 if the method is unknown.
860  */
861 int
862 ccp_test(unit, opt_ptr, opt_len, for_transmit)
863     int unit, opt_len, for_transmit;
864     u_char *opt_ptr;
865 {
866     struct ppp_option_data data;
867     int s;
868     
869     data.ptr = opt_ptr;
870     data.length = opt_len;
871     data.transmit = for_transmit;
872 //db_printf("%s called\n", __PRETTY_FUNCTION__);
873
874     s = splsoftnet();
875         
876     errno = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSCOMPRESS, (caddr_t) &data, 0 );
877
878     splx(s);
879     
880     if (errno == 0)        
881         return 1;
882     else return (errno == ENOBUFS)? 0: -1;
883     
884 }
885
886 //==========================================================================
887 /*
888  * ccp_flags_set - inform kernel about the current state of CCP.
889  */
890 void
891 ccp_flags_set(unit, isopen, isup)
892     int unit, isopen, isup;
893 {
894     int x;
895
896     int err;
897 //db_printf("%s called\n", __PRETTY_FUNCTION__);
898     if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCGFLAGS, (caddr_t) &x, 0)) != 0) {
899         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %d",err);
900         return;
901     }
902     x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN;
903     x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP;
904     if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSFLAGS, (caddr_t) &x,0)) != 0)
905         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %d",err);
906 }
907
908 //==========================================================================
909 /*
910  * ccp_fatal_error - returns 1 if decompression was disabled as a
911  * result of an error detected after decompression of a packet,
912  * 0 otherwise.  This is necessary because of patent nonsense.
913  */
914 int
915 ccp_fatal_error(unit)
916     int unit;
917 {
918     int x;
919     int err;
920     
921 db_printf("%s called\n", __PRETTY_FUNCTION__);
922     if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCGFLAGS, (caddr_t) &x, 0)) != 0) {
923         syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %d",err);
924         return 0;
925     }
926     return x & SC_DC_FERROR;
927 }
928
929 //==========================================================================
930 /*
931  * get_idle_time - return how long the link has been idle.
932  */
933 int
934 get_idle_time(u, ip)
935     int u;
936     struct ppp_idle *ip;
937 {
938     return cyg_ppp_ppptioctl(&ppp_tty, PPPIOCGIDLE, (caddr_t)ip, 0) == 0;
939 }
940
941
942 //==========================================================================
943
944 #ifdef PPP_FILTER
945 /*
946  * set_filters - transfer the pass and active filters to the kernel.
947  */
948 int
949 set_filters(pass, active)
950     struct bpf_program *pass, *active;
951 {
952     int ret = 1;
953
954 db_printf("%s called\n", __PRETTY_FUNCTION__);
955     if (pass->bf_len > 0) {
956         if (ioctl(ppp_fd, PPPIOCSPASS, pass) < 0) {
957             syslog(LOG_ERR, "Couldn't set pass-filter in kernel: %m");
958             ret = 0;
959         }
960     }
961     if (active->bf_len > 0) {
962         if (ioctl(ppp_fd, PPPIOCSACTIVE, active) < 0) {
963             syslog(LOG_ERR, "Couldn't set active-filter in kernel: %m");
964             ret = 0;
965         }
966     }
967     return ret;
968 }
969 #endif
970
971 //==========================================================================
972 /*
973  * sifvjcomp - config tcp header compression
974  */
975 int
976 sifvjcomp(u, vjcomp, cidcomp, maxcid)
977     int u, vjcomp, cidcomp, maxcid;
978 {
979     u_int x;
980     int err;
981     
982     if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCGFLAGS, (caddr_t) &x, 0)) != 0) {
983         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %d",err);
984         return 0;
985     }
986     x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
987     x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
988     if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSFLAGS, (caddr_t) &x, 0)) != 0) {
989         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %d",err);
990         return 0;
991     }
992     if (vjcomp && ((err=cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSMAXCID, (caddr_t) &maxcid, 0)) != 0)) {
993         syslog(LOG_ERR, "ioctl(PPPIOCSMAXCID): %d",err);
994         return 0;
995     }
996     return 1;
997 }
998
999 //==========================================================================
1000 /*
1001  * sifup - Config the interface up and enable IP packets to pass.
1002  */
1003 int
1004 sifup(u)
1005     int u;
1006 {
1007     struct ifreq ifr;
1008
1009 //db_printf("%s called\n", __PRETTY_FUNCTION__);
1010     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1011     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
1012         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
1013         return 0;
1014     }
1015     ifr.ifr_flags |= IFF_UP;
1016     if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
1017         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
1018         return 0;
1019     }
1020     if_is_up = 1;
1021     return 1;
1022 }
1023
1024 //==========================================================================
1025 /*
1026  * sifnpmode - Set the mode for handling packets for a given NP.
1027  */
1028 int
1029 sifnpmode(u, proto, mode)
1030     int u;
1031     int proto;
1032     enum NPmode mode;
1033 {
1034     struct npioctl npi;
1035
1036 //db_printf("%s called\n", __PRETTY_FUNCTION__);
1037     npi.protocol = proto;
1038     npi.mode = mode;
1039     {
1040         int err;
1041     
1042         if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSNPMODE, (caddr_t)&npi, 0)) < 0) {
1043             syslog(LOG_ERR, "ioctl(set NP %d mode to %d): %d", proto, mode,err);
1044             return 0;
1045         }
1046     }
1047     
1048     return 1;
1049 }
1050
1051 //==========================================================================
1052 /*
1053  * sifdown - Config the interface down and disable IP.
1054  */
1055 int
1056 sifdown(u)
1057     int u;
1058 {
1059     struct ifreq ifr;
1060     int rv;
1061     struct npioctl npi;
1062
1063 db_printf("%s called\n", __PRETTY_FUNCTION__);
1064     rv = 1;
1065     npi.protocol = PPP_IP;
1066     npi.mode = NPMODE_ERROR;
1067     {
1068         int err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSNPMODE, (caddr_t) &npi, 0);
1069         if( err < 0 )
1070             syslog(LOG_WARNING, "ioctl(PPPIOCSNPMODE): %d",err);
1071     }
1072     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
1073     if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
1074         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
1075         rv = 0;
1076     } else {
1077         ifr.ifr_flags &= ~IFF_UP;
1078         if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
1079             syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
1080             rv = 0;
1081         } else
1082             if_is_up = 0;
1083     }
1084     return rv;
1085     return 0;
1086 }
1087
1088 //==========================================================================
1089 /*
1090  * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
1091  * if it exists.
1092  */
1093 #define SET_SA_FAMILY(addr, family)             \
1094     BZERO((char *) &(addr), sizeof(addr));      \
1095     addr.sa_family = (family);                  \
1096     addr.sa_len = sizeof(addr);
1097
1098 //==========================================================================
1099 /*
1100  * sifaddr - Config the interface IP addresses and netmask.
1101  */
1102 int
1103 sifaddr(u, o, h, m)
1104     int u;
1105     u_int32_t o, h, m;
1106 {
1107     struct ifaliasreq ifra;
1108     struct ifreq ifr;
1109
1110 //db_printf("%s called\n", __PRETTY_FUNCTION__);
1111     strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
1112     SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
1113     ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
1114     SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
1115     ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
1116     if (m != 0) {
1117         SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
1118         ((struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m;
1119     } else
1120         BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
1121     BZERO(&ifr, sizeof(ifr));
1122     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1123     if (ioctl(sockfd, SIOCDIFADDR, (caddr_t) &ifr) < 0) {
1124         if (errno != EADDRNOTAVAIL)
1125             syslog(LOG_WARNING, "Couldn't remove interface address: %d",errno);
1126     }
1127     if (ioctl(sockfd, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
1128         if (errno != EEXIST) {
1129             syslog(LOG_ERR, "Couldn't set interface address: %d",errno);
1130             return 0;
1131         }
1132         syslog(LOG_WARNING,
1133                "Couldn't set interface address: Address %s already exists",
1134                 ip_ntoa(o));
1135     }
1136     ifaddrs[0] = o;
1137     ifaddrs[1] = h;
1138     return 1;
1139 }
1140
1141 //==========================================================================
1142 /*
1143  * cifaddr - Clear the interface IP addresses, and delete routes
1144  * through the interface if possible.
1145  */
1146 int
1147 cifaddr(u, o, h)
1148     int u;
1149     u_int32_t o, h;
1150 {
1151     struct ifaliasreq ifra;
1152
1153 db_printf("%s called\n", __PRETTY_FUNCTION__);
1154     ifaddrs[0] = 0;
1155     strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
1156     SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
1157     ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
1158     SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
1159     ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
1160     BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
1161     if (ioctl(sockfd, SIOCDIFADDR, (caddr_t) &ifra) < 0) {
1162         if (errno != EADDRNOTAVAIL)
1163             syslog(LOG_WARNING, "Couldn't delete interface address: %m");
1164         return 0;
1165     }
1166     return 1;
1167 }
1168
1169 //==========================================================================
1170 /*
1171  * sifdefaultroute - assign a default route through the address given.
1172  */
1173 int
1174 sifdefaultroute(u, l, g)
1175     int u;
1176     u_int32_t l, g;
1177 {
1178 db_printf("%s called\n", __PRETTY_FUNCTION__);
1179     return dodefaultroute(g, 's');
1180 }
1181
1182 //==========================================================================
1183 /*
1184  * cifdefaultroute - delete a default route through the address given.
1185  */
1186 int
1187 cifdefaultroute(u, l, g)
1188     int u;
1189     u_int32_t l, g;
1190 {
1191 db_printf("%s called\n", __PRETTY_FUNCTION__);
1192     return dodefaultroute(g, 'c');
1193 }
1194
1195 //==========================================================================
1196 /*
1197  * dodefaultroute - talk to a routing socket to add/delete a default route.
1198  */
1199 static int
1200 dodefaultroute(g, cmd)
1201     u_int32_t g;
1202     int cmd;
1203 {
1204     int routes;
1205     struct {
1206         struct rt_msghdr        hdr;
1207         struct sockaddr_in      dst;
1208         struct sockaddr_in      gway;
1209         struct sockaddr_in      mask;
1210     } rtmsg;
1211
1212 db_printf("%s %08x %c\n", __PRETTY_FUNCTION__,g,cmd);
1213     if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
1214         syslog(LOG_ERR, "Couldn't %s default route: socket: %d",
1215                cmd=='s'? "add": "delete",errno);
1216         return 0;
1217     }
1218
1219     memset(&rtmsg, 0, sizeof(rtmsg));
1220     rtmsg.hdr.rtm_type = cmd == 's'? RTM_ADD: RTM_DELETE;
1221     rtmsg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
1222     rtmsg.hdr.rtm_version = RTM_VERSION;
1223     rtmsg.hdr.rtm_seq = ++rtm_seq;
1224     rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
1225     rtmsg.dst.sin_len = sizeof(rtmsg.dst);
1226     rtmsg.dst.sin_family = AF_INET;
1227     rtmsg.gway.sin_len = sizeof(rtmsg.gway);
1228     rtmsg.gway.sin_family = AF_INET;
1229     rtmsg.gway.sin_addr.s_addr = g;
1230     rtmsg.mask.sin_len = sizeof(rtmsg.dst);
1231     rtmsg.mask.sin_family = AF_INET;
1232
1233     rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
1234     if (write(routes, &rtmsg, sizeof(rtmsg)) < 0) {
1235         syslog(LOG_ERR, "Couldn't %s default route: %d",
1236                cmd=='s'? "add": "delete",errno);
1237         close(routes);
1238         return 0;
1239     }
1240
1241     close(routes);
1242     default_route_gateway = (cmd == 's')? g: 0;
1243     return 1;
1244 }
1245
1246 //==========================================================================
1247
1248 #if RTM_VERSION >= 3
1249
1250 /*
1251  * sifproxyarp - Make a proxy ARP entry for the peer.
1252  */
1253 static struct {
1254     struct rt_msghdr            hdr;
1255     struct sockaddr_inarp       dst;
1256     struct sockaddr_dl          hwa;
1257     char                        extra[128];
1258 } arpmsg;
1259
1260 static int arpmsg_valid;
1261
1262 int
1263 sifproxyarp(unit, hisaddr)
1264     int unit;
1265     u_int32_t hisaddr;
1266 {
1267     int routes;
1268
1269 db_printf("%s called\n", __PRETTY_FUNCTION__);
1270     /*
1271      * Get the hardware address of an interface on the same subnet
1272      * as our local address.
1273      */
1274     memset(&arpmsg, 0, sizeof(arpmsg));
1275     if (!get_ether_addr(hisaddr, &arpmsg.hwa)) {
1276         syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
1277         return 0;
1278     }
1279
1280     if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
1281         syslog(LOG_ERR, "Couldn't add proxy arp entry: socket: %m");
1282         return 0;
1283     }
1284
1285     arpmsg.hdr.rtm_type = RTM_ADD;
1286     arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC;
1287     arpmsg.hdr.rtm_version = RTM_VERSION;
1288     arpmsg.hdr.rtm_seq = ++rtm_seq;
1289     arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
1290     arpmsg.hdr.rtm_inits = RTV_EXPIRE;
1291     arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp);
1292     arpmsg.dst.sin_family = AF_INET;
1293     arpmsg.dst.sin_addr.s_addr = hisaddr;
1294     arpmsg.dst.sin_other = SIN_PROXY;
1295
1296     arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg
1297         + arpmsg.hwa.sdl_len;
1298     if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
1299         syslog(LOG_ERR, "Couldn't add proxy arp entry: %m");
1300         close(routes);
1301         return 0;
1302     }
1303
1304     close(routes);
1305     arpmsg_valid = 1;
1306     proxy_arp_addr = hisaddr;
1307     return 1;
1308 }
1309
1310 /*
1311  * cifproxyarp - Delete the proxy ARP entry for the peer.
1312  */
1313 int
1314 cifproxyarp(unit, hisaddr)
1315     int unit;
1316     u_int32_t hisaddr;
1317 {
1318     int routes;
1319
1320 db_printf("%s called\n", __PRETTY_FUNCTION__);
1321     if (!arpmsg_valid)
1322         return 0;
1323     arpmsg_valid = 0;
1324
1325     arpmsg.hdr.rtm_type = RTM_DELETE;
1326     arpmsg.hdr.rtm_seq = ++rtm_seq;
1327
1328     if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
1329         syslog(LOG_ERR, "Couldn't delete proxy arp entry: socket: %m");
1330         return 0;
1331     }
1332
1333     if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
1334         syslog(LOG_ERR, "Couldn't delete proxy arp entry: %m");
1335         close(routes);
1336         return 0;
1337     }
1338
1339     close(routes);
1340     proxy_arp_addr = 0;
1341     return 1;
1342 }
1343
1344 //==========================================================================
1345
1346 #else   /* RTM_VERSION */
1347
1348 /*
1349  * sifproxyarp - Make a proxy ARP entry for the peer.
1350  */
1351 int
1352 sifproxyarp(unit, hisaddr)
1353     int unit;
1354     u_int32_t hisaddr;
1355 {
1356     struct arpreq arpreq;
1357     struct {
1358         struct sockaddr_dl      sdl;
1359         char                    space[128];
1360     } dls;
1361
1362 db_printf("%s called\n", __PRETTY_FUNCTION__);
1363     BZERO(&arpreq, sizeof(arpreq));
1364
1365     /*
1366      * Get the hardware address of an interface on the same subnet
1367      * as our local address.
1368      */
1369     if (!get_ether_addr(hisaddr, &dls.sdl)) {
1370         syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
1371         return 0;
1372     }
1373
1374     arpreq.arp_ha.sa_len = sizeof(struct sockaddr);
1375     arpreq.arp_ha.sa_family = AF_UNSPEC;
1376     BCOPY(LLADDR(&dls.sdl), arpreq.arp_ha.sa_data, dls.sdl.sdl_alen);
1377     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
1378     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
1379     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
1380     if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) < 0) {
1381         syslog(LOG_ERR, "Couldn't add proxy arp entry: %m");
1382         return 0;
1383     }
1384
1385     proxy_arp_addr = hisaddr;
1386     return 1;
1387 }
1388
1389 /*
1390  * cifproxyarp - Delete the proxy ARP entry for the peer.
1391  */
1392 int
1393 cifproxyarp(unit, hisaddr)
1394     int unit;
1395     u_int32_t hisaddr;
1396 {
1397     struct arpreq arpreq;
1398
1399 db_printf("%s called\n", __PRETTY_FUNCTION__);
1400     BZERO(&arpreq, sizeof(arpreq));
1401     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
1402     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
1403     if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
1404         syslog(LOG_WARNING, "Couldn't delete proxy arp entry: %m");
1405         return 0;
1406     }
1407     proxy_arp_addr = 0;
1408     return 1;
1409 }
1410 #endif  /* RTM_VERSION */
1411
1412
1413 //==========================================================================
1414 /*
1415  * get_ether_addr - get the hardware address of an interface on the
1416  * the same subnet as ipaddr.
1417  */
1418 #define MAX_IFS         32
1419
1420 static int
1421 get_ether_addr(ipaddr, hwaddr)
1422     u_int32_t ipaddr;
1423     struct sockaddr_dl *hwaddr;
1424 {
1425     struct ifreq *ifr, *ifend, *ifp;
1426     u_int32_t ina, mask;
1427     struct sockaddr_dl *dla;
1428     struct ifreq ifreq;
1429     struct ifconf ifc;
1430     struct ifreq ifs[MAX_IFS];
1431
1432 db_printf("%s called\n", __PRETTY_FUNCTION__);
1433     ifc.ifc_len = sizeof(ifs);
1434     ifc.ifc_req = ifs;
1435     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
1436         syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
1437         return 0;
1438     }
1439
1440     /*
1441      * Scan through looking for an interface with an Internet
1442      * address on the same subnet as `ipaddr'.
1443      */
1444     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1445     for (ifr = ifc.ifc_req; ifr < ifend;
1446                 ifr = (struct ifreq *) ((char *)&ifr->ifr_addr
1447                     + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)))) {
1448         if (ifr->ifr_addr.sa_family == AF_INET) {
1449             ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1450             strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1451             /*
1452              * Check that the interface is up, and not point-to-point
1453              * or loopback.
1454              */
1455             if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1456                 continue;
1457             if ((ifreq.ifr_flags &
1458                  (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
1459                  != (IFF_UP|IFF_BROADCAST))
1460                 continue;
1461             /*
1462              * Get its netmask and check that it's on the right subnet.
1463              */
1464             if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1465                 continue;
1466             mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr;
1467             if ((ipaddr & mask) != (ina & mask))
1468                 continue;
1469
1470             break;
1471         }
1472     }
1473
1474     if (ifr >= ifend)
1475         return 0;
1476     syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name);
1477
1478     /*
1479      * Now scan through again looking for a link-level address
1480      * for this interface.
1481      */
1482     ifp = ifr;
1483     for (ifr = ifc.ifc_req; ifr < ifend; ) {
1484         if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
1485             && ifr->ifr_addr.sa_family == AF_LINK) {
1486             /*
1487              * Found the link-level address - copy it out
1488              */
1489             dla = (struct sockaddr_dl *) &ifr->ifr_addr;
1490             BCOPY(dla, hwaddr, dla->sdl_len);
1491             return 1;
1492         }
1493         ifr = (struct ifreq *) ((char *)&ifr->ifr_addr
1494             + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)));
1495     }
1496
1497     return 0;
1498 }
1499
1500 //==========================================================================
1501 /*
1502  * Return user specified netmask, modified by any mask we might determine
1503  * for address `addr' (in network byte order).
1504  * Here we scan through the system's list of interfaces, looking for
1505  * any non-point-to-point interfaces which might appear to be on the same
1506  * network as `addr'.  If we find any, we OR in their netmask to the
1507  * user-specified netmask.
1508  */
1509 u_int32_t
1510 GetMask(addr)
1511     u_int32_t addr;
1512 {
1513     u_int32_t mask, nmask, ina;
1514     struct ifreq *ifr, *ifend, ifreq;
1515     struct ifconf ifc;
1516     struct ifreq ifs[MAX_IFS];
1517
1518     addr = ntohl(addr);
1519     if (IN_CLASSA(addr))        /* determine network mask for address class */
1520         nmask = IN_CLASSA_NET;
1521     else if (IN_CLASSB(addr))
1522         nmask = IN_CLASSB_NET;
1523     else
1524         nmask = IN_CLASSC_NET;
1525     /* class D nets are disallowed by bad_ip_adrs */
1526     mask = netmask | htonl(nmask);
1527
1528     /*
1529      * Scan through the system's network interfaces.
1530      */
1531     ifc.ifc_len = sizeof(ifs);
1532     ifc.ifc_req = ifs;
1533     if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
1534         syslog(LOG_WARNING, "ioctl(SIOCGIFCONF): %m");
1535         return mask;
1536     }
1537     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
1538     for (ifr = ifc.ifc_req; ifr < ifend;
1539                 ifr = (struct ifreq *) ((char *)&ifr->ifr_addr
1540                     + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)))) {
1541         /*
1542          * Check the interface's internet address.
1543          */
1544         if (ifr->ifr_addr.sa_family != AF_INET)
1545             continue;
1546         ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
1547         if ((ntohl(ina) & nmask) != (addr & nmask))
1548             continue;
1549         /*
1550          * Check that the interface is up, and not point-to-point or loopback.
1551          */
1552         strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
1553         if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
1554             continue;
1555         if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
1556             != IFF_UP)
1557             continue;
1558         /*
1559          * Get its netmask and OR it into our mask.
1560          */
1561         if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
1562             continue;
1563         mask |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr;
1564     }
1565
1566     return mask;
1567 }
1568
1569 //==========================================================================
1570 /*
1571  * Use the hostid as part of the random number seed.
1572  */
1573 int
1574 get_host_seed()
1575 {
1576 //db_printf("%s called\n", __PRETTY_FUNCTION__);
1577 #ifndef __ECOS
1578     return gethostid();
1579 #endif
1580     return 0;
1581 }
1582
1583 //=====================================================================
1584 // PAP stubs
1585 //
1586 // When omitting PAP, these fill in the dangling references from auth.c
1587 //
1588
1589 #ifndef CYGPKG_PPP_PAP
1590
1591 void
1592 upap_authwithpeer(unit, user, password)
1593     int unit;
1594     char *user, *password;
1595 {
1596     unit=unit;
1597     user=user;
1598     password=password;
1599 }
1600
1601 void
1602 upap_authpeer(unit)
1603     int unit;
1604 {
1605     unit=unit;
1606 }
1607
1608 #endif
1609
1610 //=====================================================================
1611 // CHAP stubs
1612 //
1613 // When omitting CHAP, these fill in the dangling references from auth.c
1614 //
1615
1616 #ifndef CYGPKG_PPP_CHAP
1617
1618 void
1619 ChapAuthWithPeer(unit, our_name, digest)
1620     int unit;
1621     char *our_name;
1622     int digest;
1623 {
1624     unit=unit;
1625     our_name=our_name;
1626     digest=digest;
1627 }
1628
1629 void
1630 ChapAuthPeer(unit, our_name, digest)
1631     int unit;
1632     char *our_name;
1633     int digest;
1634 {
1635     unit=unit;
1636     our_name=our_name;
1637     digest=digest;
1638 }
1639
1640 #endif
1641
1642 //=====================================================================
1643 // eCos API
1644
1645 externC cyg_int32 cyg_ppp_options_init( cyg_ppp_options_t *options )
1646 {
1647     if( options == NULL )
1648         return -1;
1649     
1650     options->debug              = 0;
1651     options->kdebugflag         = 0;
1652     options->default_route      = 1;
1653     options->modem              = 0;
1654     options->flowctl            = CYG_PPP_FLOWCTL_HARDWARE;
1655     options->refuse_pap         = 0;
1656     options->refuse_chap        = 0;
1657     options->neg_accm           = 0;
1658     options->conf_accm          = 0;
1659
1660     options->baud               = CYGNUM_SERIAL_BAUD_115200;
1661     
1662     options->idle_time_limit    = 1*60;
1663     options->maxconnect         = 0;
1664
1665     options->our_address        = 0;
1666     options->his_address        = 0;
1667
1668     options->script             = NULL;
1669     
1670     strncpy( options->user, CYGPKG_PPP_AUTH_DEFAULT_USER, MAXNAMELEN );
1671     strncpy( options->passwd, CYGPKG_PPP_AUTH_DEFAULT_PASSWD, MAXSECRETLEN );
1672
1673     return 0;
1674 }
1675
1676 // -------------------------------------------------------------------------
1677
1678
1679 #define CYGNUM_PPP_PPPD_THREAD_STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL+0x1000)
1680
1681 static char cyg_pppd_stack[CYGNUM_PPP_PPPD_THREAD_STACK_SIZE];
1682 static cyg_thread cyg_pppd_thread_obj;
1683
1684 static char cyg_ppp_tx_thread_stack[CYGNUM_HAL_STACK_SIZE_TYPICAL];
1685 static cyg_thread cyg_ppp_tx_thread_obj;
1686
1687
1688 externC void cyg_pppd_main(CYG_ADDRWORD arg);
1689
1690
1691 externC cyg_ppp_handle_t cyg_ppp_up( const char *devnam_arg,
1692                                      const cyg_ppp_options_t *options )
1693 {
1694
1695     if( options == NULL || phase != PHASE_DEAD )
1696         return 0;
1697     
1698     // Initialize control block    
1699         memset(&ppp_tty, 0, sizeof(struct tty));
1700
1701     strncpy( devnam, devnam_arg, PATH_MAX );
1702
1703     ppp_tty.options = options;
1704
1705     cyg_semaphore_init( &ppp_tty.tx_sem,  0 );
1706
1707     // Start the PPPD thread
1708     cyg_thread_create(CYGNUM_PPP_PPPD_THREAD_PRIORITY,
1709                       cyg_pppd_main,
1710                       (CYG_ADDRWORD)&ppp_tty,
1711                       "PPPD",
1712                       &cyg_pppd_stack[0],
1713                       CYGNUM_PPP_PPPD_THREAD_STACK_SIZE,
1714                       &ppp_tty.pppd_thread,
1715                       &cyg_pppd_thread_obj
1716             );
1717     cyg_thread_resume(ppp_tty.pppd_thread);
1718
1719     // Start the TX thread
1720     cyg_thread_create(CYGNUM_PPP_PPPD_THREAD_PRIORITY+1,
1721                       cyg_ppp_tx_thread,
1722                       (CYG_ADDRWORD)&ppp_tty,
1723                       "PPP Tx Thread",
1724                       &cyg_ppp_tx_thread_stack[0],
1725                       sizeof(cyg_ppp_tx_thread_stack),
1726                       &ppp_tty.tx_thread,
1727                       &cyg_ppp_tx_thread_obj
1728             );
1729     cyg_thread_resume(ppp_tty.tx_thread);
1730
1731     // Wait for the PPPD thread to get going and start the PPP
1732     // initialization phase.
1733     while(phase == PHASE_DEAD)
1734         cyg_thread_delay(100);
1735     
1736     return (cyg_ppp_handle_t)&ppp_tty;
1737 }
1738
1739 // -------------------------------------------------------------------------
1740
1741 externC char **script;
1742
1743 externC void cyg_ppp_options_install( const cyg_ppp_options_t *options )
1744 {
1745     debug               = options->debug;
1746     kdebugflag          = options->kdebugflag;
1747     
1748     modem               = options->modem;
1749     flowctl             = options->flowctl;
1750     refuse_pap          = options->refuse_pap;
1751     refuse_chap         = options->refuse_chap;
1752     neg_accm            = options->neg_accm;
1753     conf_accm           = options->conf_accm;
1754
1755     inspeed             = options->baud;
1756     
1757     idle_time_limit     = options->idle_time_limit;
1758     maxconnect          = options->maxconnect;
1759
1760     script              = options->script;
1761     
1762     strncpy( user, &options->user[0], MAXNAMELEN );
1763     strncpy( passwd, &options->passwd[0], MAXSECRETLEN );
1764     
1765 }
1766
1767 // -------------------------------------------------------------------------
1768
1769 externC cyg_int32 cyg_ppp_down( const cyg_ppp_handle_t handle )
1770 {
1771     if( phase != PHASE_DEAD )
1772     {
1773         externC int kill_link;
1774         kill_link = 1;
1775         cyg_thread_release( ppp_tty.pppd_thread );
1776         ppp_tty.pppd_wakeup = 1;    
1777         return 0;
1778     }
1779     else
1780         return -1;
1781 }
1782
1783 // -------------------------------------------------------------------------
1784
1785 externC cyg_int32 cyg_ppp_wait_up( cyg_ppp_handle_t handle )
1786 {
1787     while(!( (phase == PHASE_NETWORK && ifaddrs[0] != 0) ||
1788              phase == PHASE_DEAD ) )
1789         cyg_thread_delay(100);
1790
1791     return phase == PHASE_NETWORK ? 0 : -1;
1792 }
1793
1794 // -------------------------------------------------------------------------
1795
1796 externC void cyg_ppp_wait_down( cyg_ppp_handle_t handle )
1797 {
1798     while( ppp_tty.tx_thread_running || ppp_tty.pppd_thread_running )
1799         cyg_thread_delay(100);
1800     
1801     cyg_thread_delete( ppp_tty.tx_thread );
1802     cyg_thread_delete( ppp_tty.pppd_thread );
1803 }
1804
1805 // -------------------------------------------------------------------------
1806 #ifdef CYGOPT_PPP_NS_NEGOTIATE
1807 externC u_int32_t cyg_ppp_get_neg_addrs(cyg_ppp_neg_addrs_t *addrs)
1808 {
1809         if (phase == PHASE_NETWORK && ifaddrs[0] != 0)
1810         {
1811                 addrs->local_ip = ipcp_gotoptions[0].ouraddr;
1812                 addrs->peer_ip = ipcp_hisoptions[0].hisaddr;
1813                 addrs->pri_dns = ipcp_gotoptions[0].dnsaddr[0];
1814                 addrs->alt_dns = ipcp_gotoptions[0].dnsaddr[1];
1815                 addrs->pri_wins = ipcp_gotoptions[0].winsaddr[0];
1816                 addrs->alt_wins = ipcp_gotoptions[0].winsaddr[1];
1817                 return(1);
1818         }
1819         else
1820         {
1821                 return(0);
1822         }
1823 }
1824 #endif
1825 //=====================================================================
1826 // eCos extras
1827
1828 void syslog( int level, char *fmt, ... )
1829 {
1830     va_list ap;
1831     int ret;
1832
1833 #ifdef CYGPKG_PPP_DEBUG_WARN_ONLY
1834     if(!( level == LOG_ERR ||
1835           level == LOG_WARNING ))
1836         return;
1837 #endif
1838     
1839     va_start(ap, fmt);
1840     diag_printf("SYSLOG %02x: ",level);
1841     ret = diag_vprintf(fmt, ap);
1842     diag_printf("\n");
1843     va_end(ap);
1844 }
1845
1846 //=====================================================================
1847
1848 char *crypt (const char *key, const char *salt)
1849 {
1850     static char res[13];
1851
1852     db_printf("%s called\n", __PRETTY_FUNCTION__);
1853     
1854     return res;
1855 }
1856
1857
1858 //=====================================================================
1859 /*
1860  * Substitute procedures for those systems which don't have
1861  * drand48 et al.
1862  */
1863
1864 double
1865 drand48(void)
1866 {
1867     return (double)rand() / (double)0x7fffffffL; /* 2**31-1 */
1868 }
1869
1870 long
1871 mrand48(void)
1872 {
1873     return rand();
1874 }
1875
1876 void
1877 srand48(long seedval)
1878 {
1879     srand(seedval);
1880 }
1881
1882
1883 //=====================================================================
1884
1885 #if 0
1886
1887 #undef MD5Init
1888 #undef MD5Update
1889 #undef MD5Final
1890
1891 #include <sys/types.h>
1892
1893 #include <sys/md5.h>
1894
1895
1896 void   cyg_MD5Init( MD5_CTX *ctx );
1897 void   cyg_MD5Update (MD5_CTX *ctx, const unsigned char *buf, unsigned int size);
1898 void   cyg_MD5Final (unsigned char hash[16], MD5_CTX *ctx);
1899   
1900
1901 void   cyg_ppp_MD5Init( MD5_CTX *ctx )
1902 {
1903     db_printf("%s called\n", __PRETTY_FUNCTION__);
1904     cyg_MD5Init( ctx );
1905     return;
1906 }
1907
1908 void   cyg_ppp_MD5Update (MD5_CTX *ctx, const unsigned char *buf, unsigned int size)
1909 {
1910     db_printf("%s called\n", __PRETTY_FUNCTION__);
1911     cyg_MD5Update( ctx, buf, size );
1912     return;
1913 }
1914
1915 void   cyg_ppp_MD5Final (unsigned char hash[16], MD5_CTX *ctx)
1916 {
1917     db_printf("%s called\n", __PRETTY_FUNCTION__);
1918     cyg_MD5Final( hash, ctx );
1919     return;
1920 }
1921
1922 #endif
1923
1924 //=====================================================================
1925 // End of sys-ecos.c
1926
1927