]> git.ozlabs.org Git - ppp.git/blob - pppd/sys-solaris.c
Updated Solaris-related READMEs for the current code.
[ppp.git] / pppd / sys-solaris.c
1 /*
2  * System-dependent procedures for pppd under Solaris 2.
3  *
4  * Parts re-written by Adi Masputra <adi.masputra@sun.com>, based on 
5  * the original sys-svr4.c
6  *
7  * Copyright (c) 2000 by Sun Microsystems, Inc.
8  * All rights reserved.
9  *
10  * Permission to use, copy, modify, and distribute this software and its
11  * documentation is hereby granted, provided that the above copyright
12  * notice appears in all copies.  
13  *
14  * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
15  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
16  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
17  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT.  SUN SHALL NOT BE LIABLE FOR
18  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
19  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
20  *
21  * Copyright (c) 1994 The Australian National University.
22  * All rights reserved.
23  *
24  * Permission to use, copy, modify, and distribute this software and its
25  * documentation is hereby granted, provided that the above copyright
26  * notice appears in all copies.  This software is provided without any
27  * warranty, express or implied. The Australian National University
28  * makes no representations about the suitability of this software for
29  * any purpose.
30  *
31  * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
32  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
33  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
34  * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
35  * OF SUCH DAMAGE.
36  *
37  * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
38  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
39  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
40  * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
41  * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
42  * OR MODIFICATIONS.
43  */
44
45 #define RCSID   "$Id: sys-solaris.c,v 1.8 2002/09/07 05:15:25 carlsonj Exp $"
46
47 #include <limits.h>
48 #include <stdio.h>
49 #include <stddef.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <ctype.h>
53 #include <errno.h>
54 #include <fcntl.h>
55 #include <unistd.h>
56 #include <termios.h>
57 #ifndef CRTSCTS
58 #include <sys/termiox.h>
59 #endif
60 #include <signal.h>
61 #include <utmpx.h>
62 #include <sys/types.h>
63 #include <sys/ioccom.h>
64 #include <sys/stream.h>
65 #include <sys/stropts.h>
66 #include <sys/socket.h>
67 #include <sys/sockio.h>
68 #include <sys/sysmacros.h>
69 #include <sys/systeminfo.h>
70 #include <sys/dlpi.h>
71 #include <sys/stat.h>
72 #include <sys/mkdev.h>
73 #include <net/if.h>
74 #include <net/if_arp.h>
75 #include <net/route.h>
76 #include <net/ppp_defs.h>
77 #include <net/pppio.h>
78 #include <netinet/in.h>
79 #ifdef SOL2
80 #include <sys/tihdr.h>
81 #include <sys/tiuser.h>
82 #include <inet/common.h>
83 #include <inet/mib2.h>
84 #include <sys/ethernet.h>
85 #endif
86
87 #include "pppd.h"
88 #include "fsm.h"
89 #include "lcp.h"
90 #include "ipcp.h"
91 #include "ccp.h"
92
93 #if !defined(PPP_DRV_NAME)
94 #define PPP_DRV_NAME    "ppp"
95 #endif /* !defined(PPP_DRV_NAME) */
96
97 #if !defined(PPP_DEV_NAME)
98 #define PPP_DEV_NAME    "/dev/" PPP_DRV_NAME
99 #endif /* !defined(PPP_DEV_NAME) */
100
101 #if !defined(AHDLC_MOD_NAME)
102 #define AHDLC_MOD_NAME  "ppp_ahdl"
103 #endif /* !defined(AHDLC_MOD_NAME) */
104
105 #if !defined(COMP_MOD_NAME)
106 #define COMP_MOD_NAME   "ppp_comp"
107 #endif /* !defined(COMP_MOD_NAME) */
108
109 #if !defined(IP_DEV_NAME)
110 #define IP_DEV_NAME     "/dev/ip"
111 #endif /* !defined(IP_DEV_NAME) */
112
113 #if !defined(IP_MOD_NAME)
114 #define IP_MOD_NAME     "ip"
115 #endif /* !defined(IP_MOD_NAME) */
116
117 #if !defined(UDP_DEV_NAME) && defined(SOL2)
118 #define UDP_DEV_NAME    "/dev/udp"
119 #endif /* !defined(UDP_DEV_NAME) && defined(SOL2) */
120
121 #if !defined(UDP6_DEV_NAME) && defined(SOL2)
122 #define UDP6_DEV_NAME   "/dev/udp6"
123 #endif /* !defined(UDP6_DEV_NAME) && defined(SOL2) */
124
125 static const char rcsid[] = RCSID;
126
127 #if defined(SOL2)
128 /*
129  * "/dev/udp" is used as a multiplexor to PLINK the interface stream
130  * under. It is used in place of "/dev/ip" since STREAMS will not let
131  * a driver be PLINK'ed under itself, and "/dev/ip" is typically the
132  * driver at the bottom of the tunneling interfaces stream.
133  */
134 static char *mux_dev_name = UDP_DEV_NAME;
135 #else
136 static char *mux_dev_name = IP_DEV_NAME;
137 #endif
138 static int      pppfd;
139 static int      fdmuxid = -1;
140 static int      ipfd;
141 static int      ipmuxid = -1;
142
143 #if defined(INET6) && defined(SOL2)
144 static int      ip6fd;          /* IP file descriptor */
145 static int      ip6muxid = -1;  /* Multiplexer file descriptor */
146 static int      if6_is_up = 0;  /* IPv6 interface has been marked up */
147
148 #define _IN6_LLX_FROM_EUI64(l, s, eui64, as) do {       \
149         s->sin6_addr.s6_addr32[0] = htonl(as);  \
150         eui64_copy(eui64, s->sin6_addr.s6_addr32[2]);   \
151         s->sin6_family = AF_INET6;              \
152         l.lifr_addr.ss_family = AF_INET6;       \
153         l.lifr_addrlen = 10;                    \
154         l.lifr_addr = laddr;                    \
155         } while (0)
156
157 #define IN6_LLADDR_FROM_EUI64(l, s, eui64)  \
158     _IN6_LLX_FROM_EUI64(l, s, eui64, 0xfe800000)
159
160 #define IN6_LLTOKEN_FROM_EUI64(l, s, eui64) \
161     _IN6_LLX_FROM_EUI64(l, s, eui64, 0)
162
163 #endif /* defined(INET6) && defined(SOL2) */
164
165 #if defined(INET6) && defined(SOL2)
166 static char     first_ether_name[LIFNAMSIZ];    /* Solaris 8 and above */
167 #else
168 static char     first_ether_name[IFNAMSIZ];     /* Before Solaris 8 */
169 #define MAXIFS          256                     /* Max # of interfaces */
170 #endif /* defined(INET6) && defined(SOL2) */
171
172 static int      restore_term;
173 static struct termios inittermios;
174 #ifndef CRTSCTS
175 static struct termiox inittermiox;
176 static int      termiox_ok;
177 #endif
178 static struct winsize wsinfo;   /* Initial window size info */
179 static pid_t    tty_sid;        /* original session ID for terminal */
180
181 extern u_char   inpacket_buf[]; /* borrowed from main.c */
182
183 #define MAX_POLLFDS     32
184 static struct pollfd pollfds[MAX_POLLFDS];
185 static int n_pollfds;
186
187 static int      link_mtu, link_mru;
188
189 #define NMODULES        32
190 static int      tty_nmodules;
191 static char     tty_modules[NMODULES][FMNAMESZ+1];
192 static int      tty_npushed;
193
194 static int      if_is_up;       /* Interface has been marked up */
195 static u_int32_t remote_addr;           /* IP address of peer */
196 static u_int32_t default_route_gateway; /* Gateway for default route added */
197 static u_int32_t proxy_arp_addr;        /* Addr for proxy arp entry added */
198
199 /* Prototypes for procedures local to this file. */
200 static int translate_speed __P((int));
201 static int baud_rate_of __P((int));
202 static int get_ether_addr __P((u_int32_t, struct sockaddr *));
203 static int get_hw_addr __P((char *, u_int32_t, struct sockaddr *));
204 static int get_hw_addr_dlpi __P((char *, struct sockaddr *));
205 static int dlpi_attach __P((int, int));
206 static int dlpi_info_req __P((int));
207 static int dlpi_get_reply __P((int, union DL_primitives *, int, int));
208 static int strioctl __P((int, int, void *, int, int));
209
210 #ifdef SOL2
211 /*
212  * sifppa - Sets interface ppa
213  *
214  * without setting the ppa, ip module will return EINVAL upon setting the
215  * interface UP (SIOCSxIFFLAGS). This is because ip module in 2.8 expects
216  * two DLPI_INFO_REQ to be sent down to the driver (below ip) before
217  * IFF_UP can be set. Plumbing the device causes one DLPI_INFO_REQ to
218  * be sent down, and the second DLPI_INFO_REQ is sent upon receiving
219  * IF_UNITSEL (old) or SIOCSLIFNAME (new) ioctls. Such setting of the ppa
220  * is required because the ppp DLPI provider advertises itself as
221  * a DLPI style 2 type, which requires a point of attachment to be
222  * specified. The only way the user can specify a point of attachment
223  * is via SIOCSLIFNAME or IF_UNITSEL.
224  *
225  * Such changes in the behavior of ip module was made to meet new or
226  * evolving standards requirements.
227  *
228  */
229 static int
230 sifppa(fd, ppa)
231     int fd;
232     int ppa;
233 {
234     return (int)ioctl(fd, IF_UNITSEL, (char *)&ppa);
235 }
236 #endif /* SOL2 */
237
238 #if defined(SOL2) && defined(INET6)
239 /*
240  * get_first_ethernet - returns the first Ethernet interface name found in 
241  * the system, or NULL if none is found
242  *
243  * NOTE: This is the lifreq version (Solaris 8 and above)
244  */
245 char *
246 get_first_ethernet()
247 {
248     struct lifnum lifn;
249     struct lifconf lifc;
250     struct lifreq *plifreq;
251     struct lifreq lifr;
252     int fd, num_ifs, i, found;
253     uint_t fl, req_size;
254     char *req;
255
256     fd = socket(AF_INET, SOCK_DGRAM, 0);
257     if (fd < 0) {
258         return 0;
259     }
260
261     /*
262      * Find out how many interfaces are running
263      */
264     lifn.lifn_family = AF_UNSPEC;
265     lifn.lifn_flags = LIFC_NOXMIT;
266     if (ioctl(fd, SIOCGLIFNUM, &lifn) < 0) {
267         close(fd);
268         error("could not determine number of interfaces: %m");
269         return 0;
270     }
271
272     num_ifs = lifn.lifn_count;
273     req_size = num_ifs * sizeof(struct lifreq);
274     req = malloc(req_size);
275     if (req == NULL) {
276         close(fd);
277         error("out of memory");
278         return 0;
279     }
280
281     /*
282      * Get interface configuration info for all interfaces
283      */
284     lifc.lifc_family = AF_UNSPEC;
285     lifc.lifc_flags = LIFC_NOXMIT;
286     lifc.lifc_len = req_size;
287     lifc.lifc_buf = req;
288     if (ioctl(fd, SIOCGLIFCONF, &lifc) < 0) {
289         close(fd);
290         free(req);
291         error("SIOCGLIFCONF: %m");
292         return 0;
293     }
294
295     /*
296      * And traverse each interface to look specifically for the first
297      * occurence of an Ethernet interface which has been marked up
298      */
299     plifreq = lifc.lifc_req;
300     found = 0;
301     for (i = lifc.lifc_len / sizeof(struct lifreq); i > 0; i--, plifreq++) {
302
303         if (strchr(plifreq->lifr_name, ':') != NULL)
304             continue;
305
306         memset(&lifr, 0, sizeof(lifr));
307         strncpy(lifr.lifr_name, plifreq->lifr_name, sizeof(lifr.lifr_name));
308         if (ioctl(fd, SIOCGLIFFLAGS, &lifr) < 0) {
309             close(fd);
310             free(req);
311             error("SIOCGLIFFLAGS: %m");
312             return 0;
313         }
314         fl = lifr.lifr_flags;
315
316         if ((fl & (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
317                 != (IFF_UP | IFF_BROADCAST))
318             continue;
319
320         found = 1;
321         break;
322     }
323     free(req);
324     close(fd);
325
326     if (found) {
327         strncpy(first_ether_name, lifr.lifr_name, sizeof(first_ether_name));
328         return (char *)first_ether_name;
329     } else
330         return NULL;
331 }
332 #else
333 /*
334  * get_first_ethernet - returns the first Ethernet interface name found in 
335  * the system, or NULL if none is found
336  *
337  * NOTE: This is the ifreq version (before Solaris 8). 
338  */
339 char *
340 get_first_ethernet()
341 {
342     struct ifconf ifc;
343     struct ifreq *pifreq;
344     struct ifreq ifr;
345     int fd, num_ifs, i, found;
346     uint_t fl, req_size;
347     char *req;
348
349     fd = socket(AF_INET, SOCK_DGRAM, 0);
350     if (fd < 0) {
351         return 0;
352     }
353
354     /*
355      * Find out how many interfaces are running
356      */
357     if (ioctl(fd, SIOCGIFNUM, (char *)&num_ifs) < 0) {
358         num_ifs = MAXIFS;
359     }
360
361     req_size = num_ifs * sizeof(struct ifreq);
362     req = malloc(req_size);
363     if (req == NULL) {
364         close(fd);
365         error("out of memory");
366         return 0;
367     }
368
369     /*
370      * Get interface configuration info for all interfaces
371      */
372     ifc.ifc_len = req_size;
373     ifc.ifc_buf = req;
374     if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
375         close(fd);
376         free(req);
377         error("SIOCGIFCONF: %m");
378         return 0;
379     }
380
381     /*
382      * And traverse each interface to look specifically for the first
383      * occurence of an Ethernet interface which has been marked up
384      */
385     pifreq = ifc.ifc_req;
386     found = 0;
387     for (i = ifc.ifc_len / sizeof(struct ifreq); i > 0; i--, pifreq++) {
388
389         if (strchr(pifreq->ifr_name, ':') != NULL)
390             continue;
391
392         memset(&ifr, 0, sizeof(ifr));
393         strncpy(ifr.ifr_name, pifreq->ifr_name, sizeof(ifr.ifr_name));
394         if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
395             close(fd);
396             free(req);
397             error("SIOCGIFFLAGS: %m");
398             return 0;
399         }
400         fl = ifr.ifr_flags;
401
402         if ((fl & (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
403                 != (IFF_UP | IFF_BROADCAST))
404             continue;
405
406         found = 1;
407         break;
408     }
409     free(req);
410     close(fd);
411
412     if (found) {
413         strncpy(first_ether_name, ifr.ifr_name, sizeof(first_ether_name));
414         return (char *)first_ether_name;
415     } else
416         return NULL;
417 }
418 #endif /* defined(SOL2) && defined(INET6) */
419
420 #if defined(SOL2)
421 /*
422  * get_if_hwaddr - get the hardware address for the specified
423  * network interface device.
424  */
425 int
426 get_if_hwaddr(u_char *addr, char *if_name)
427 {
428     struct sockaddr s_eth_addr;
429     struct ether_addr *eth_addr = (struct ether_addr *)&s_eth_addr.sa_data;
430
431     if (if_name == NULL)
432         return -1;
433
434     /*
435      * Send DL_INFO_REQ to the driver to solicit its MAC address
436      */
437     if (!get_hw_addr_dlpi(if_name, &s_eth_addr)) {
438         error("could not obtain hardware address for %s", if_name);
439         return -1;
440     }
441
442     memcpy(addr, eth_addr->ether_addr_octet, 6);
443     return 1;
444 }
445 #endif /* SOL2 */
446
447 #if defined(SOL2) && defined(INET6)
448 /*
449  * slifname - Sets interface ppa and flags
450  *
451  * in addition to the comments stated in sifppa(), IFF_IPV6 bit must
452  * be set in order to declare this as an IPv6 interface
453  */
454 static int
455 slifname(fd, ppa)
456     int fd;
457     int ppa;
458 {
459     struct  lifreq lifr;
460     int     ret;
461
462     memset(&lifr, 0, sizeof(lifr));
463     ret = ioctl(fd, SIOCGLIFFLAGS, &lifr);
464     if (ret < 0)
465         goto slifname_done;
466
467     lifr.lifr_flags |= IFF_IPV6;
468     lifr.lifr_flags &= ~(IFF_BROADCAST | IFF_IPV4);
469     lifr.lifr_ppa = ppa;
470     strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
471
472     ret = ioctl(fd, SIOCSLIFNAME, &lifr);
473
474 slifname_done:
475     return ret;
476
477
478 }
479
480
481 /*
482  * ether_to_eui64 - Convert 48-bit Ethernet address into 64-bit EUI
483  *
484  * walks the list of valid ethernet interfaces, and convert the first
485  * found 48-bit MAC address into EUI 64. caller also assumes that
486  * the system has a properly configured Ethernet interface for this
487  * function to return non-zero.
488  */
489 int
490 ether_to_eui64(eui64_t *p_eui64)
491 {
492     struct sockaddr s_eth_addr;
493     struct ether_addr *eth_addr = (struct ether_addr *)&s_eth_addr.sa_data;
494     char *if_name;
495
496     if ((if_name = get_first_ethernet()) == NULL) {
497         error("no persistent id can be found");
498         return 0;
499     }
500  
501     /*
502      * Send DL_INFO_REQ to the driver to solicit its MAC address
503      */
504     if (!get_hw_addr_dlpi(if_name, &s_eth_addr)) {
505         error("could not obtain hardware address for %s", if_name);
506         return 0;
507     }
508
509     /*
510      * And convert the EUI-48 into EUI-64, per RFC 2472 [sec 4.1]
511      */
512     p_eui64->e8[0] = (eth_addr->ether_addr_octet[0] & 0xFF) | 0x02;
513     p_eui64->e8[1] = (eth_addr->ether_addr_octet[1] & 0xFF);
514     p_eui64->e8[2] = (eth_addr->ether_addr_octet[2] & 0xFF);
515     p_eui64->e8[3] = 0xFF;
516     p_eui64->e8[4] = 0xFE;
517     p_eui64->e8[5] = (eth_addr->ether_addr_octet[3] & 0xFF);
518     p_eui64->e8[6] = (eth_addr->ether_addr_octet[4] & 0xFF);
519     p_eui64->e8[7] = (eth_addr->ether_addr_octet[5] & 0xFF);
520
521     return 1;
522 }
523 #endif /* defined(SOL2) && defined(INET6) */
524
525 /*
526  * sys_init - System-dependent initialization.
527  */
528 void
529 sys_init()
530 {
531     int ifd, x;
532     struct ifreq ifr;
533 #if defined(INET6) && defined(SOL2)
534     int i6fd;
535     struct lifreq lifr;
536 #endif /* defined(INET6) && defined(SOL2) */
537 #if !defined(SOL2)
538     struct {
539         union DL_primitives prim;
540         char space[64];
541     } reply;
542 #endif /* !defined(SOL2) */
543
544     ipfd = open(mux_dev_name, O_RDWR, 0);
545     if (ipfd < 0)
546         fatal("Couldn't open IP device: %m");
547
548 #if defined(INET6) && defined(SOL2)
549     ip6fd = open(UDP6_DEV_NAME, O_RDWR, 0);
550     if (ip6fd < 0)
551         fatal("Couldn't open IP device (2): %m");
552 #endif /* defined(INET6) && defined(SOL2) */
553
554     if (default_device && !notty)
555         tty_sid = getsid((pid_t)0);
556
557     pppfd = open(PPP_DEV_NAME, O_RDWR | O_NONBLOCK, 0);
558     if (pppfd < 0)
559         fatal("Can't open %s: %m", PPP_DEV_NAME);
560     if (kdebugflag & 1) {
561         x = PPPDBG_LOG + PPPDBG_DRIVER;
562         strioctl(pppfd, PPPIO_DEBUG, &x, sizeof(int), 0);
563     }
564
565     /* Assign a new PPA and get its unit number. */
566     if (strioctl(pppfd, PPPIO_NEWPPA, &ifunit, 0, sizeof(int)) < 0)
567         fatal("Can't create new PPP interface: %m");
568
569 #if defined(SOL2)
570     /*
571      * Since sys_init() is called prior to ifname being set in main(),
572      * we need to get the ifname now, otherwise slifname(), and others,
573      * will fail, or maybe, I should move them to a later point ?
574      * <adi.masputra@sun.com>
575      */
576     sprintf(ifname, PPP_DRV_NAME "%d", ifunit);
577 #endif /* defined(SOL2) */
578     /*
579      * Open the ppp device again and link it under the ip multiplexor.
580      * IP will assign a unit number which hopefully is the same as ifunit.
581      * I don't know any way to be certain they will be the same. :-(
582      */
583     ifd = open(PPP_DEV_NAME, O_RDWR, 0);
584     if (ifd < 0)
585         fatal("Can't open %s (2): %m", PPP_DEV_NAME);
586     if (kdebugflag & 1) {
587         x = PPPDBG_LOG + PPPDBG_DRIVER;
588         strioctl(ifd, PPPIO_DEBUG, &x, sizeof(int), 0);
589     }
590
591 #if defined(INET6) && defined(SOL2)
592     i6fd = open(PPP_DEV_NAME, O_RDWR, 0);
593     if (i6fd < 0) {
594         close(ifd);
595         fatal("Can't open %s (3): %m", PPP_DEV_NAME);
596     }
597     if (kdebugflag & 1) {
598         x = PPPDBG_LOG + PPPDBG_DRIVER;
599         strioctl(i6fd, PPPIO_DEBUG, &x, sizeof(int), 0);
600     }
601 #endif /* defined(INET6) && defined(SOL2) */
602
603 #if defined(SOL2)
604     if (ioctl(ifd, I_PUSH, IP_MOD_NAME) < 0) {
605         close(ifd);
606 #if defined(INET6)
607         close(i6fd);
608 #endif /* defined(INET6) */
609         fatal("Can't push IP module: %m");
610     }
611
612     /*
613      * Assign ppa according to the unit number returned by ppp device
614      * after plumbing is completed above.
615      */
616     if (sifppa(ifd, ifunit) < 0) {
617         close (ifd);
618 #if defined(INET6)
619         close(i6fd);
620 #endif /* defined(INET6) */
621         fatal("Can't set ppa for unit %d: %m", ifunit);
622     }
623
624 #if defined(INET6)
625     /*
626      * An IPv6 interface is created anyway, even when the user does not 
627      * explicitly enable it. Note that the interface will be marked
628      * IPv6 during slifname().
629      */
630     if (ioctl(i6fd, I_PUSH, IP_MOD_NAME) < 0) {
631         close(ifd);
632         close(i6fd);
633         fatal("Can't push IP module (2): %m");
634     }
635
636     /*
637      * Assign ppa according to the unit number returned by ppp device
638      * after plumbing is completed above. In addition, mark the interface
639      * as an IPv6 interface.
640      */
641     if (slifname(i6fd, ifunit) < 0) {
642         close(ifd);
643         close(i6fd);
644         fatal("Can't set ifname for unit %d: %m", ifunit);
645     }
646 #endif /* defined(INET6) */
647
648     ipmuxid = ioctl(ipfd, I_PLINK, ifd);
649     close(ifd);
650     if (ipmuxid < 0) {
651 #if defined(INET6)
652         close(i6fd);
653 #endif /* defined(INET6) */
654         fatal("Can't I_PLINK PPP device to IP: %m");
655     }
656
657     memset(&ifr, 0, sizeof(ifr));
658     sprintf(ifr.ifr_name, "%s", ifname);
659     ifr.ifr_ip_muxid = ipmuxid;
660
661     /*
662      * In Sol 8 and later, STREAMS dynamic module plumbing feature exists.
663      * This is so that an arbitrary module can be inserted, or deleted, 
664      * between ip module and the device driver without tearing down the 
665      * existing stream. Such feature requires the mux ids, which is set 
666      * by SIOCSIFMUXID (or SIOCLSIFMUXID).
667      */
668     if (ioctl(ipfd, SIOCSIFMUXID, &ifr) < 0) {
669         ioctl(ipfd, I_PUNLINK, ipmuxid);
670 #if defined(INET6)
671         close(i6fd);
672 #endif /* defined(INET6) */
673         fatal("SIOCSIFMUXID: %m");
674     }
675
676 #else /* else if !defined(SOL2) */
677
678     if (dlpi_attach(ifd, ifunit) < 0 ||
679         dlpi_get_reply(ifd, &reply.prim, DL_OK_ACK, sizeof(reply)) < 0) {
680         close(ifd);
681         fatal("Can't attach to ppp%d: %m", ifunit);
682     }
683
684     ipmuxid = ioctl(ipfd, I_LINK, ifd);
685     close(ifd);
686     if (ipmuxid < 0)
687         fatal("Can't link PPP device to IP: %m");
688 #endif /* defined(SOL2) */
689
690 #if defined(INET6) && defined(SOL2)
691     ip6muxid = ioctl(ip6fd, I_PLINK, i6fd);
692     close(i6fd);
693     if (ip6muxid < 0) {
694         ioctl(ipfd, I_PUNLINK, ipmuxid);
695         fatal("Can't I_PLINK PPP device to IP (2): %m");
696     }
697
698     memset(&lifr, 0, sizeof(lifr));
699     sprintf(lifr.lifr_name, "%s", ifname);
700     lifr.lifr_ip_muxid = ip6muxid;
701
702     /*
703      * Let IP know of the mux id [see comment for SIOCSIFMUXID above]
704      */
705     if (ioctl(ip6fd, SIOCSLIFMUXID, &lifr) < 0) {
706         ioctl(ipfd, I_PUNLINK, ipmuxid);
707         ioctl(ip6fd, I_PUNLINK, ip6muxid);
708         fatal("Can't link PPP device to IP (2): %m");
709     }
710 #endif /* defined(INET6) && defined(SOL2) */
711
712 #if !defined(SOL2)
713     /* Set the interface name for the link. */
714     slprintf(ifr.ifr_name, sizeof(ifr.ifr_name), PPP_DRV_NAME "%d", ifunit);
715     ifr.ifr_metric = ipmuxid;
716     if (strioctl(ipfd, SIOCSIFNAME, (char *)&ifr, sizeof ifr, 0) < 0)
717         fatal("Can't set interface name %s: %m", ifr.ifr_name);
718 #endif /* !defined(SOL2) */
719
720     n_pollfds = 0;
721 }
722
723 /*
724  * sys_cleanup - restore any system state we modified before exiting:
725  * mark the interface down, delete default route and/or proxy arp entry.
726  * This should call die() because it's called from die().
727  */
728 void
729 sys_cleanup()
730 {
731 #if defined(SOL2)
732     struct ifreq ifr;
733 #if defined(INET6)
734     struct lifreq lifr;
735 #endif /* defined(INET6) */
736 #endif /* defined(SOL2) */
737
738 #if defined(SOL2) && defined(INET6)
739     if (if6_is_up)
740         sif6down(0);
741 #endif /* defined(SOL2) && defined(INET6) */
742     if (if_is_up)
743         sifdown(0);
744     if (default_route_gateway)
745         cifdefaultroute(0, default_route_gateway, default_route_gateway);
746     if (proxy_arp_addr)
747         cifproxyarp(0, proxy_arp_addr);
748 #if defined(SOL2)
749     /*
750      * Make sure we ask ip what the muxid, because 'ifconfig modlist' will
751      * unlink and re-link the modules, causing the muxid to change.
752      */
753     memset(&ifr, 0, sizeof(ifr));
754     sprintf(ifr.ifr_name, "%s", ifname);
755     if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) {
756         error("SIOCGIFFLAGS: %m");
757         return;
758     }
759
760     if (ioctl(ipfd, SIOCGIFMUXID, &ifr) < 0) {
761         error("SIOCGIFMUXID: %m");
762         return;
763     }
764
765     ipmuxid = ifr.ifr_ip_muxid;
766      
767     if (ioctl(ipfd, I_PUNLINK, ipmuxid) < 0) {
768         error("Can't I_PUNLINK PPP from IP: %m");
769         return;
770     }
771 #if defined(INET6)
772     /*
773      * Make sure we ask ip what the muxid, because 'ifconfig modlist' will
774      * unlink and re-link the modules, causing the muxid to change.
775      */
776     memset(&lifr, 0, sizeof(lifr));
777     sprintf(lifr.lifr_name, "%s", ifname);
778     if (ioctl(ip6fd, SIOCGLIFFLAGS, &lifr) < 0) {
779         error("SIOCGLIFFLAGS: %m");
780         return;
781     }
782
783     if (ioctl(ip6fd, SIOCGLIFMUXID, &lifr) < 0) {
784         error("SIOCGLIFMUXID: %m");
785         return;
786     }
787
788     ip6muxid = lifr.lifr_ip_muxid;
789
790     if (ioctl(ip6fd, I_PUNLINK, ip6muxid) < 0) {
791         error("Can't I_PUNLINK PPP from IP (2): %m");
792     }
793 #endif /* defined(INET6) */
794 #endif /* defined(SOL2) */
795 }
796
797 /*
798  * sys_close - Clean up in a child process before execing.
799  */
800 void
801 sys_close()
802 {
803     close(ipfd);
804 #if defined(INET6) && defined(SOL2)
805     close(ip6fd);
806 #endif /* defined(INET6) && defined(SOL2) */
807     if (pppfd >= 0)
808         close(pppfd);
809 }
810
811 /*
812  * sys_check_options - check the options that the user specified
813  */
814 int
815 sys_check_options()
816 {
817     return 1;
818 }
819
820 #if 0
821 /*
822  * daemon - Detach us from controlling terminal session.
823  */
824 int
825 daemon(nochdir, noclose)
826     int nochdir, noclose;
827 {
828     int pid;
829
830     if ((pid = fork()) < 0)
831         return -1;
832     if (pid != 0)
833         exit(0);                /* parent dies */
834     setsid();
835     if (!nochdir)
836         chdir("/");
837     if (!noclose) {
838         fclose(stdin);          /* don't need stdin, stdout, stderr */
839         fclose(stdout);
840         fclose(stderr);
841     }
842     return 0;
843 }
844 #endif
845
846 /*
847  * ppp_available - check whether the system has any ppp interfaces
848  */
849 int
850 ppp_available()
851 {
852     struct stat buf;
853
854     return stat(PPP_DEV_NAME, &buf) >= 0;
855 }
856
857 /*
858  * any_compressions - see if compression is enabled or not
859  *
860  * In the STREAMS implementation of kernel-portion pppd,
861  * the comp STREAMS module performs the ACFC, PFC, as well
862  * CCP and VJ compressions. However, if the user has explicitly
863  * declare to not enable them from the command line, there is
864  * no point of having the comp module be pushed on the stream.
865  */
866 static int
867 any_compressions()
868 {
869     if ((!lcp_wantoptions[0].neg_accompression) &&
870         (!lcp_wantoptions[0].neg_pcompression) &&
871         (!ccp_protent.enabled_flag) &&
872         (!ipcp_wantoptions[0].neg_vj)) {
873             return 0;
874     }
875     return 1;
876 }
877
878 /*
879  * tty_establish_ppp - Turn the serial port into a ppp interface.
880  */
881 int
882 tty_establish_ppp(fd)
883     int fd;
884 {
885     int i;
886
887     /* Pop any existing modules off the tty stream. */
888     for (i = 0;; ++i)
889         if (ioctl(fd, I_LOOK, tty_modules[i]) < 0
890             || strcmp(tty_modules[i], "ptem") == 0
891             || ioctl(fd, I_POP, 0) < 0)
892             break;
893     tty_nmodules = i;
894
895     /* Push the async hdlc module and the compressor module. */
896     tty_npushed = 0;
897
898     if(!sync_serial) {
899         if (ioctl(fd, I_PUSH, AHDLC_MOD_NAME) < 0) {
900             error("Couldn't push PPP Async HDLC module: %m");
901             return -1;
902         }
903         ++tty_npushed;
904     }
905     if (kdebugflag & 4) {
906         i = PPPDBG_LOG + PPPDBG_AHDLC;
907         strioctl(pppfd, PPPIO_DEBUG, &i, sizeof(int), 0);
908     }
909     /*
910      * There's no need to push comp module if we don't intend
911      * to compress anything
912      */
913     if (any_compressions()) { 
914         if (ioctl(fd, I_PUSH, COMP_MOD_NAME) < 0)
915             error("Couldn't push PPP compression module: %m");
916         else
917             ++tty_npushed;
918     }
919
920     if (kdebugflag & 2) {
921         i = PPPDBG_LOG; 
922         if (any_compressions())
923             i += PPPDBG_COMP;
924         strioctl(pppfd, PPPIO_DEBUG, &i, sizeof(int), 0);
925     }
926
927     /* Link the serial port under the PPP multiplexor. */
928     if ((fdmuxid = ioctl(pppfd, I_LINK, fd)) < 0) {
929         error("Can't link tty to PPP mux: %m");
930         return -1;
931     }
932
933     return pppfd;
934 }
935
936 /*
937  * tty_disestablish_ppp - Restore the serial port to normal operation.
938  * It attempts to reconstruct the stream with the previously popped
939  * modules.  This shouldn't call die() because it's called from die().
940  */
941 void
942 tty_disestablish_ppp(fd)
943     int fd;
944 {
945     int i;
946
947     if (fdmuxid >= 0) {
948         if (ioctl(pppfd, I_UNLINK, fdmuxid) < 0) {
949             if (!hungup)
950                 error("Can't unlink tty from PPP mux: %m");
951         }
952         fdmuxid = -1;
953
954         if (!hungup) {
955             while (tty_npushed > 0 && ioctl(fd, I_POP, 0) >= 0)
956                 --tty_npushed;
957             for (i = tty_nmodules - 1; i >= 0; --i)
958                 if (ioctl(fd, I_PUSH, tty_modules[i]) < 0)
959                     error("Couldn't restore tty module %s: %m",
960                            tty_modules[i]);
961         }
962         if (hungup && default_device && tty_sid > 0) {
963             /*
964              * If we have received a hangup, we need to send a SIGHUP
965              * to the terminal's controlling process.  The reason is
966              * that the original stream head for the terminal hasn't
967              * seen the M_HANGUP message (it went up through the ppp
968              * driver to the stream head for our fd to /dev/ppp).
969              */
970             kill(tty_sid, SIGHUP);
971         }
972     }
973 }
974
975 /*
976  * Check whether the link seems not to be 8-bit clean.
977  */
978 void
979 clean_check()
980 {
981     int x;
982     char *s;
983
984     if (strioctl(pppfd, PPPIO_GCLEAN, &x, 0, sizeof(x)) < 0)
985         return;
986     s = NULL;
987     switch (~x) {
988     case RCV_B7_0:
989         s = "bit 7 set to 1";
990         break;
991     case RCV_B7_1:
992         s = "bit 7 set to 0";
993         break;
994     case RCV_EVNP:
995         s = "odd parity";
996         break;
997     case RCV_ODDP:
998         s = "even parity";
999         break;
1000     }
1001     if (s != NULL) {
1002         warn("Serial link is not 8-bit clean:");
1003         warn("All received characters had %s", s);
1004     }
1005 }
1006
1007 /*
1008  * List of valid speeds.
1009  */
1010 struct speed {
1011     int speed_int, speed_val;
1012 } speeds[] = {
1013 #ifdef B50
1014     { 50, B50 },
1015 #endif
1016 #ifdef B75
1017     { 75, B75 },
1018 #endif
1019 #ifdef B110
1020     { 110, B110 },
1021 #endif
1022 #ifdef B134
1023     { 134, B134 },
1024 #endif
1025 #ifdef B150
1026     { 150, B150 },
1027 #endif
1028 #ifdef B200
1029     { 200, B200 },
1030 #endif
1031 #ifdef B300
1032     { 300, B300 },
1033 #endif
1034 #ifdef B600
1035     { 600, B600 },
1036 #endif
1037 #ifdef B1200
1038     { 1200, B1200 },
1039 #endif
1040 #ifdef B1800
1041     { 1800, B1800 },
1042 #endif
1043 #ifdef B2000
1044     { 2000, B2000 },
1045 #endif
1046 #ifdef B2400
1047     { 2400, B2400 },
1048 #endif
1049 #ifdef B3600
1050     { 3600, B3600 },
1051 #endif
1052 #ifdef B4800
1053     { 4800, B4800 },
1054 #endif
1055 #ifdef B7200
1056     { 7200, B7200 },
1057 #endif
1058 #ifdef B9600
1059     { 9600, B9600 },
1060 #endif
1061 #ifdef B19200
1062     { 19200, B19200 },
1063 #endif
1064 #ifdef B38400
1065     { 38400, B38400 },
1066 #endif
1067 #ifdef EXTA
1068     { 19200, EXTA },
1069 #endif
1070 #ifdef EXTB
1071     { 38400, EXTB },
1072 #endif
1073 #ifdef B57600
1074     { 57600, B57600 },
1075 #endif
1076 #ifdef B76800
1077     { 76800, B76800 },
1078 #endif
1079 #ifdef B115200
1080     { 115200, B115200 },
1081 #endif
1082 #ifdef B153600
1083     { 153600, B153600 },
1084 #endif
1085 #ifdef B230400
1086     { 230400, B230400 },
1087 #endif
1088 #ifdef B307200
1089     { 307200, B307200 },
1090 #endif
1091 #ifdef B460800
1092     { 460800, B460800 },
1093 #endif
1094     { 0, 0 }
1095 };
1096
1097 /*
1098  * Translate from bits/second to a speed_t.
1099  */
1100 static int
1101 translate_speed(bps)
1102     int bps;
1103 {
1104     struct speed *speedp;
1105
1106     if (bps == 0)
1107         return 0;
1108     for (speedp = speeds; speedp->speed_int; speedp++)
1109         if (bps == speedp->speed_int)
1110             return speedp->speed_val;
1111     warn("speed %d not supported", bps);
1112     return 0;
1113 }
1114
1115 /*
1116  * Translate from a speed_t to bits/second.
1117  */
1118 static int
1119 baud_rate_of(speed)
1120     int speed;
1121 {
1122     struct speed *speedp;
1123
1124     if (speed == 0)
1125         return 0;
1126     for (speedp = speeds; speedp->speed_int; speedp++)
1127         if (speed == speedp->speed_val)
1128             return speedp->speed_int;
1129     return 0;
1130 }
1131
1132 /*
1133  * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
1134  * at the requested speed, etc.  If `local' is true, set CLOCAL
1135  * regardless of whether the modem option was specified.
1136  */
1137 void
1138 set_up_tty(fd, local)
1139     int fd, local;
1140 {
1141     int speed;
1142     struct termios tios;
1143 #if !defined (CRTSCTS)
1144     struct termiox tiox;
1145 #endif
1146
1147     if (!sync_serial && tcgetattr(fd, &tios) < 0)
1148         fatal("tcgetattr: %m");
1149
1150 #ifndef CRTSCTS
1151     termiox_ok = 1;
1152     if (!sync_serial && ioctl (fd, TCGETX, &tiox) < 0) {
1153         termiox_ok = 0;
1154         if (errno != ENOTTY)
1155             error("TCGETX: %m");
1156     }
1157 #endif
1158
1159     if (!restore_term) {
1160         inittermios = tios;
1161 #ifndef CRTSCTS
1162         inittermiox = tiox;
1163 #endif
1164         if (!sync_serial)
1165             ioctl(fd, TIOCGWINSZ, &wsinfo);
1166     }
1167
1168     tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
1169 #ifdef CRTSCTS
1170     if (crtscts > 0)
1171         tios.c_cflag |= CRTSCTS;
1172     else if (crtscts < 0)
1173         tios.c_cflag &= ~CRTSCTS;
1174 #else
1175     if (crtscts != 0 && !termiox_ok) {
1176         error("Can't set RTS/CTS flow control");
1177     } else if (crtscts > 0) {
1178         tiox.x_hflag |= RTSXOFF|CTSXON;
1179     } else if (crtscts < 0) {
1180         tiox.x_hflag &= ~(RTSXOFF|CTSXON);
1181     }
1182 #endif
1183
1184     tios.c_cflag |= CS8 | CREAD | HUPCL;
1185     if (local || !modem)
1186         tios.c_cflag |= CLOCAL;
1187     tios.c_iflag = IGNBRK | IGNPAR;
1188     tios.c_oflag = 0;
1189     tios.c_lflag = 0;
1190     tios.c_cc[VMIN] = 1;
1191     tios.c_cc[VTIME] = 0;
1192
1193     if (crtscts == -2) {
1194         tios.c_iflag |= IXON | IXOFF;
1195         tios.c_cc[VSTOP] = 0x13;        /* DC3 = XOFF = ^S */
1196         tios.c_cc[VSTART] = 0x11;       /* DC1 = XON  = ^Q */
1197     }
1198
1199     speed = translate_speed(inspeed);
1200     if (speed) {
1201         cfsetospeed(&tios, speed);
1202         cfsetispeed(&tios, speed);
1203     } else {
1204         speed = cfgetospeed(&tios);
1205         /*
1206          * We can't proceed if the serial port speed is 0,
1207          * since that implies that the serial port is disabled.
1208          */
1209         if ((speed == B0) && !sync_serial)
1210             fatal("Baud rate for %s is 0; need explicit baud rate", devnam);
1211     }
1212
1213     if (!sync_serial && tcsetattr(fd, TCSAFLUSH, &tios) < 0)
1214         fatal("tcsetattr: %m");
1215
1216 #ifndef CRTSCTS
1217     if (!sync_serial && termiox_ok && ioctl (fd, TCSETXF, &tiox) < 0){
1218         error("TCSETXF: %m");
1219     }
1220 #endif
1221
1222     baud_rate = inspeed = baud_rate_of(speed);
1223     if (!sync_serial)
1224         restore_term = 1;
1225 }
1226
1227 /*
1228  * restore_tty - restore the terminal to the saved settings.
1229  */
1230 void
1231 restore_tty(fd)
1232     int fd;
1233 {
1234     if (restore_term) {
1235         if (!default_device) {
1236             /*
1237              * Turn off echoing, because otherwise we can get into
1238              * a loop with the tty and the modem echoing to each other.
1239              * We presume we are the sole user of this tty device, so
1240              * when we close it, it will revert to its defaults anyway.
1241              */
1242             inittermios.c_lflag &= ~(ECHO | ECHONL);
1243         }
1244         if (!sync_serial && tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
1245             if (!hungup && errno != ENXIO)
1246                 warn("tcsetattr: %m");
1247 #ifndef CRTSCTS
1248         if (!sync_serial && ioctl (fd, TCSETXF, &inittermiox) < 0){
1249             if (!hungup && errno != ENXIO)
1250                 error("TCSETXF: %m");
1251         }
1252 #endif
1253         if (!sync_serial)
1254             ioctl(fd, TIOCSWINSZ, &wsinfo);
1255         restore_term = 0;
1256     }
1257 }
1258
1259 /*
1260  * setdtr - control the DTR line on the serial port.
1261  * This is called from die(), so it shouldn't call die().
1262  */
1263 void
1264 setdtr(fd, on)
1265 int fd, on;
1266 {
1267     int modembits = TIOCM_DTR;
1268
1269     ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
1270 }
1271
1272 /*
1273  * open_loopback - open the device we use for getting packets
1274  * in demand mode.  Under Solaris 2, we use our existing fd
1275  * to the ppp driver.
1276  */
1277 int
1278 open_ppp_loopback()
1279 {
1280     return pppfd;
1281 }
1282
1283 /*
1284  * output - Output PPP packet.
1285  */
1286 void
1287 output(unit, p, len)
1288     int unit;
1289     u_char *p;
1290     int len;
1291 {
1292     struct strbuf data;
1293     int retries;
1294     struct pollfd pfd;
1295
1296     dump_packet("sent", p, len);
1297     if (snoop_send_hook) snoop_send_hook(p, len);
1298
1299     data.len = len;
1300     data.buf = (caddr_t) p;
1301     retries = 4;
1302     while (putmsg(pppfd, NULL, &data, 0) < 0) {
1303         if (--retries < 0 || (errno != EWOULDBLOCK && errno != EAGAIN)) {
1304             if (errno != ENXIO)
1305                 error("Couldn't send packet: %m");
1306             break;
1307         }
1308         pfd.fd = pppfd;
1309         pfd.events = POLLOUT;
1310         poll(&pfd, 1, 250);     /* wait for up to 0.25 seconds */
1311     }
1312 }
1313
1314
1315 /*
1316  * wait_input - wait until there is data available,
1317  * for the length of time specified by *timo (indefinite
1318  * if timo is NULL).
1319  */
1320 void
1321 wait_input(timo)
1322     struct timeval *timo;
1323 {
1324     int t;
1325
1326     t = timo == NULL? -1: timo->tv_sec * 1000 + timo->tv_usec / 1000;
1327     if (poll(pollfds, n_pollfds, t) < 0 && errno != EINTR)
1328         fatal("poll: %m");
1329 }
1330
1331 /*
1332  * add_fd - add an fd to the set that wait_input waits for.
1333  */
1334 void add_fd(fd)
1335     int fd;
1336 {
1337     int n;
1338
1339     for (n = 0; n < n_pollfds; ++n)
1340         if (pollfds[n].fd == fd)
1341             return;
1342     if (n_pollfds < MAX_POLLFDS) {
1343         pollfds[n_pollfds].fd = fd;
1344         pollfds[n_pollfds].events = POLLIN | POLLPRI | POLLHUP;
1345         ++n_pollfds;
1346     } else
1347         error("Too many inputs!");
1348 }
1349
1350 /*
1351  * remove_fd - remove an fd from the set that wait_input waits for.
1352  */
1353 void remove_fd(fd)
1354     int fd;
1355 {
1356     int n;
1357
1358     for (n = 0; n < n_pollfds; ++n) {
1359         if (pollfds[n].fd == fd) {
1360             while (++n < n_pollfds)
1361                 pollfds[n-1] = pollfds[n];
1362             --n_pollfds;
1363             break;
1364         }
1365     }
1366 }
1367
1368 #if 0
1369 /*
1370  * wait_loop_output - wait until there is data available on the
1371  * loopback, for the length of time specified by *timo (indefinite
1372  * if timo is NULL).
1373  */
1374 void
1375 wait_loop_output(timo)
1376     struct timeval *timo;
1377 {
1378     wait_input(timo);
1379 }
1380
1381 /*
1382  * wait_time - wait for a given length of time or until a
1383  * signal is received.
1384  */
1385 void
1386 wait_time(timo)
1387     struct timeval *timo;
1388 {
1389     int n;
1390
1391     n = select(0, NULL, NULL, NULL, timo);
1392     if (n < 0 && errno != EINTR)
1393         fatal("select: %m");
1394 }
1395 #endif
1396
1397
1398 /*
1399  * read_packet - get a PPP packet from the serial device.
1400  */
1401 int
1402 read_packet(buf)
1403     u_char *buf;
1404 {
1405     struct strbuf ctrl, data;
1406     int flags, len;
1407     unsigned char ctrlbuf[sizeof(union DL_primitives) + 64];
1408
1409     for (;;) {
1410         data.maxlen = PPP_MRU + PPP_HDRLEN;
1411         data.buf = (caddr_t) buf;
1412         ctrl.maxlen = sizeof(ctrlbuf);
1413         ctrl.buf = (caddr_t) ctrlbuf;
1414         flags = 0;
1415         len = getmsg(pppfd, &ctrl, &data, &flags);
1416         if (len < 0) {
1417             if (errno == EAGAIN || errno == EINTR)
1418                 return -1;
1419             fatal("Error reading packet: %m");
1420         }
1421
1422         if (ctrl.len <= 0)
1423             return data.len;
1424
1425         /*
1426          * Got a M_PROTO or M_PCPROTO message.  Interpret it
1427          * as a DLPI primitive??
1428          */
1429         if (debug)
1430             dbglog("got dlpi prim 0x%x, len=%d",
1431                    ((union DL_primitives *)ctrlbuf)->dl_primitive, ctrl.len);
1432
1433     }
1434 }
1435
1436 /*
1437  * get_loop_output - get outgoing packets from the ppp device,
1438  * and detect when we want to bring the real link up.
1439  * Return value is 1 if we need to bring up the link, 0 otherwise.
1440  */
1441 int
1442 get_loop_output()
1443 {
1444     int len;
1445     int rv = 0;
1446
1447     while ((len = read_packet(inpacket_buf)) > 0) {
1448         if (loop_frame(inpacket_buf, len))
1449             rv = 1;
1450     }
1451     return rv;
1452 }
1453
1454 /*
1455  * netif_set_mtu - set the MTU on the PPP network interface.
1456  */
1457 void
1458 netif_set_mtu(unit, mtu)
1459     int unit, mtu;
1460 {
1461     struct ifreq ifr;
1462 #if defined(INET6) && defined(SOL2)
1463     struct lifreq lifr;
1464     int fd;
1465 #endif /* defined(INET6) && defined(SOL2) */
1466
1467     memset(&ifr, 0, sizeof(ifr));
1468     strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1469     ifr.ifr_metric = link_mtu;
1470     if (ioctl(ipfd, SIOCSIFMTU, &ifr) < 0) {
1471         error("Couldn't set IP MTU (%s): %m", ifr.ifr_name);
1472     }
1473
1474 #if defined(INET6) && defined(SOL2) 
1475     fd = socket(AF_INET6, SOCK_DGRAM, 0);
1476     if (fd < 0)
1477         error("Couldn't open IPv6 socket: %m");
1478
1479     memset(&lifr, 0, sizeof(lifr));
1480     strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
1481     lifr.lifr_mtu = link_mtu;
1482     if (ioctl(fd, SIOCSLIFMTU, &lifr) < 0) {
1483         close(fd);
1484         error("Couldn't set IPv6 MTU (%s): %m", ifr.ifr_name);
1485     }
1486     close(fd);
1487 #endif /* defined(INET6) && defined(SOL2) */
1488 }
1489
1490 /*
1491  * tty_send_config - configure the transmit characteristics of
1492  * the ppp interface.
1493  */
1494 void
1495 tty_send_config(mtu, asyncmap, pcomp, accomp)
1496     int mtu;
1497     u_int32_t asyncmap;
1498     int pcomp, accomp;
1499 {
1500     int cf[2];
1501
1502     link_mtu = mtu;
1503     if (strioctl(pppfd, PPPIO_MTU, &mtu, sizeof(mtu), 0) < 0) {
1504         if (hungup && errno == ENXIO)
1505             return;
1506         error("Couldn't set MTU: %m");
1507     }
1508     if (fdmuxid >= 0) {
1509         if (!sync_serial) {
1510             if (strioctl(pppfd, PPPIO_XACCM, &asyncmap, sizeof(asyncmap), 0) < 0) {
1511                 error("Couldn't set transmit ACCM: %m");
1512             }
1513         }
1514         cf[0] = (pcomp? COMP_PROT: 0) + (accomp? COMP_AC: 0);
1515         cf[1] = COMP_PROT | COMP_AC;
1516         if (any_compressions() &&
1517             strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
1518             error("Couldn't set prot/AC compression: %m");
1519         }
1520     }
1521 }
1522
1523 /*
1524  * tty_set_xaccm - set the extended transmit ACCM for the interface.
1525  */
1526 void
1527 tty_set_xaccm(accm)
1528     ext_accm accm;
1529 {
1530     if (sync_serial)
1531         return;
1532
1533     if (fdmuxid >= 0
1534         && strioctl(pppfd, PPPIO_XACCM, accm, sizeof(ext_accm), 0) < 0) {
1535         if (!hungup || errno != ENXIO)
1536             warn("Couldn't set extended ACCM: %m");
1537     }
1538 }
1539
1540 /*
1541  * tty_recv_config - configure the receive-side characteristics of
1542  * the ppp interface.
1543  */
1544 void
1545 tty_recv_config(mru, asyncmap, pcomp, accomp)
1546     int mru;
1547     u_int32_t asyncmap;
1548     int pcomp, accomp;
1549 {
1550     int cf[2];
1551
1552     link_mru = mru;
1553     if (strioctl(pppfd, PPPIO_MRU, &mru, sizeof(mru), 0) < 0) {
1554         if (hungup && errno == ENXIO)
1555             return;
1556         error("Couldn't set MRU: %m");
1557     }
1558     if (fdmuxid >= 0) {
1559         if (!sync_serial) {
1560             if (strioctl(pppfd, PPPIO_RACCM, &asyncmap, sizeof(asyncmap), 0) < 0) {
1561                 error("Couldn't set receive ACCM: %m");
1562             }
1563         }
1564         cf[0] = (pcomp? DECOMP_PROT: 0) + (accomp? DECOMP_AC: 0);
1565         cf[1] = DECOMP_PROT | DECOMP_AC;
1566         if (any_compressions() &&
1567             strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
1568             error("Couldn't set prot/AC decompression: %m");
1569         }
1570     }
1571 }
1572
1573 /*
1574  * ccp_test - ask kernel whether a given compression method
1575  * is acceptable for use.
1576  */
1577 int
1578 ccp_test(unit, opt_ptr, opt_len, for_transmit)
1579     int unit, opt_len, for_transmit;
1580     u_char *opt_ptr;
1581 {
1582     if (strioctl(pppfd, (for_transmit? PPPIO_XCOMP: PPPIO_RCOMP),
1583                  opt_ptr, opt_len, 0) >= 0)
1584         return 1;
1585     return (errno == ENOSR)? 0: -1;
1586 }
1587
1588 /*
1589  * ccp_flags_set - inform kernel about the current state of CCP.
1590  */
1591 void
1592 ccp_flags_set(unit, isopen, isup)
1593     int unit, isopen, isup;
1594 {
1595     int cf[2];
1596
1597     cf[0] = (isopen? CCP_ISOPEN: 0) + (isup? CCP_ISUP: 0);
1598     cf[1] = CCP_ISOPEN | CCP_ISUP | CCP_ERROR | CCP_FATALERROR;
1599     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
1600         if (!hungup || errno != ENXIO)
1601             error("Couldn't set kernel CCP state: %m");
1602     }
1603 }
1604
1605 /*
1606  * get_idle_time - return how long the link has been idle.
1607  */
1608 int
1609 get_idle_time(u, ip)
1610     int u;
1611     struct ppp_idle *ip;
1612 {
1613     return strioctl(pppfd, PPPIO_GIDLE, ip, 0, sizeof(struct ppp_idle)) >= 0;
1614 }
1615
1616 /*
1617  * get_ppp_stats - return statistics for the link.
1618  */
1619 int
1620 get_ppp_stats(u, stats)
1621     int u;
1622     struct pppd_stats *stats;
1623 {
1624     struct ppp_stats s;
1625
1626     if (!sync_serial && 
1627         strioctl(pppfd, PPPIO_GETSTAT, &s, 0, sizeof(s)) < 0) {
1628         error("Couldn't get link statistics: %m");
1629         return 0;
1630     }
1631     stats->bytes_in = s.p.ppp_ibytes;
1632     stats->bytes_out = s.p.ppp_obytes;
1633     stats->pkts_in = s.p.ppp_ipackets;
1634     stats->pkts_out = s.p.ppp_opackets;
1635     return 1;
1636 }
1637
1638 #if 0
1639 /*
1640  * set_filters - transfer the pass and active filters to the kernel.
1641  */
1642 int
1643 set_filters(pass, active)
1644     struct bpf_program *pass, *active;
1645 {
1646     int ret = 1;
1647
1648     if (pass->bf_len > 0) {
1649         if (strioctl(pppfd, PPPIO_PASSFILT, pass,
1650                      sizeof(struct bpf_program), 0) < 0) {
1651             error("Couldn't set pass-filter in kernel: %m");
1652             ret = 0;
1653         }
1654     }
1655     if (active->bf_len > 0) {
1656         if (strioctl(pppfd, PPPIO_ACTIVEFILT, active,
1657                      sizeof(struct bpf_program), 0) < 0) {
1658             error("Couldn't set active-filter in kernel: %m");
1659             ret = 0;
1660         }
1661     }
1662     return ret;
1663 }
1664 #endif
1665
1666 /*
1667  * ccp_fatal_error - returns 1 if decompression was disabled as a
1668  * result of an error detected after decompression of a packet,
1669  * 0 otherwise.  This is necessary because of patent nonsense.
1670  */
1671 int
1672 ccp_fatal_error(unit)
1673     int unit;
1674 {
1675     int cf[2];
1676
1677     cf[0] = cf[1] = 0;
1678     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
1679         if (errno != ENXIO && errno != EINVAL)
1680             error("Couldn't get compression flags: %m");
1681         return 0;
1682     }
1683     return cf[0] & CCP_FATALERROR;
1684 }
1685
1686 /*
1687  * sifvjcomp - config tcp header compression
1688  */
1689 int
1690 sifvjcomp(u, vjcomp, xcidcomp, xmaxcid)
1691     int u, vjcomp, xcidcomp, xmaxcid;
1692 {
1693     int cf[2];
1694     char maxcid[2];
1695
1696     if (vjcomp) {
1697         maxcid[0] = xcidcomp;
1698         maxcid[1] = 15;         /* XXX should be rmaxcid */
1699         if (strioctl(pppfd, PPPIO_VJINIT, maxcid, sizeof(maxcid), 0) < 0) {
1700             error("Couldn't initialize VJ compression: %m");
1701         }
1702     }
1703
1704     cf[0] = (vjcomp? COMP_VJC + DECOMP_VJC: 0)  /* XXX this is wrong */
1705         + (xcidcomp? COMP_VJCCID + DECOMP_VJCCID: 0);
1706     cf[1] = COMP_VJC + DECOMP_VJC + COMP_VJCCID + DECOMP_VJCCID;
1707     if (strioctl(pppfd, PPPIO_CFLAGS, cf, sizeof(cf), sizeof(int)) < 0) {
1708         if (vjcomp)
1709             error("Couldn't enable VJ compression: %m");
1710     }
1711
1712     return 1;
1713 }
1714
1715 /*
1716  * sifup - Config the interface up and enable IP packets to pass.
1717  */
1718 int
1719 sifup(u)
1720     int u;
1721 {
1722     struct ifreq ifr;
1723
1724     strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1725     if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) {
1726         error("Couldn't mark interface up (get): %m");
1727         return 0;
1728     }
1729     ifr.ifr_flags |= IFF_UP;
1730     if (ioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) {
1731         error("Couldn't mark interface up (set): %m");
1732         return 0;
1733     }
1734     if_is_up = 1;
1735     return 1;
1736 }
1737
1738 /*
1739  * sifdown - Config the interface down and disable IP.
1740  */
1741 int
1742 sifdown(u)
1743     int u;
1744 {
1745     struct ifreq ifr;
1746
1747     if (ipmuxid < 0)
1748         return 1;
1749     strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1750     if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) < 0) {
1751         error("Couldn't mark interface down (get): %m");
1752         return 0;
1753     }
1754     ifr.ifr_flags &= ~IFF_UP;
1755     if (ioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) {
1756         error("Couldn't mark interface down (set): %m");
1757         return 0;
1758     }
1759     if_is_up = 0;
1760     return 1;
1761 }
1762
1763 /*
1764  * sifnpmode - Set the mode for handling packets for a given NP.
1765  */
1766 int
1767 sifnpmode(u, proto, mode)
1768     int u;
1769     int proto;
1770     enum NPmode mode;
1771 {
1772     int npi[2];
1773
1774     npi[0] = proto;
1775     npi[1] = (int) mode;
1776     if (strioctl(pppfd, PPPIO_NPMODE, &npi, 2 * sizeof(int), 0) < 0) {
1777         error("ioctl(set NP %d mode to %d): %m", proto, mode);
1778         return 0;
1779     }
1780     return 1;
1781 }
1782
1783 #if defined(SOL2) && defined(INET6)
1784 /*
1785  * sif6up - Config the IPv6 interface up and enable IPv6 packets to pass.
1786  */
1787 int
1788 sif6up(u)
1789     int u;
1790 {
1791     struct lifreq lifr;
1792     int fd;
1793
1794     fd = socket(AF_INET6, SOCK_DGRAM, 0);
1795     if (fd < 0) {
1796         return 0;
1797     }
1798
1799     memset(&lifr, 0, sizeof(lifr));
1800     strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
1801     if (ioctl(fd, SIOCGLIFFLAGS, &lifr) < 0) {
1802         close(fd);
1803         return 0;
1804     }
1805
1806     lifr.lifr_flags |= IFF_UP;
1807     strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
1808     if (ioctl(fd, SIOCSLIFFLAGS, &lifr) < 0) {
1809         close(fd);
1810         return 0;
1811     }
1812
1813     if6_is_up = 1;
1814     close(fd);
1815     return 1;
1816 }
1817
1818 /*
1819  * sifdown - Config the IPv6 interface down and disable IPv6.
1820  */
1821 int
1822 sif6down(u)
1823     int u;
1824 {
1825     struct lifreq lifr;
1826     int fd;
1827
1828     fd = socket(AF_INET6, SOCK_DGRAM, 0);
1829     if (fd < 0)
1830         return 0;
1831
1832     memset(&lifr, 0, sizeof(lifr));
1833     strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
1834     if (ioctl(fd, SIOCGLIFFLAGS, &lifr) < 0) {
1835         close(fd);
1836         return 0;
1837     }
1838
1839     lifr.lifr_flags &= ~IFF_UP;
1840     strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
1841     if (ioctl(fd, SIOCGLIFFLAGS, &lifr) < 0) {
1842         close(fd);
1843         return 0;
1844     }
1845
1846     if6_is_up = 0;
1847     close(fd);
1848     return 1;
1849 }
1850
1851 /*
1852  * sif6addr - Config the interface with an IPv6 link-local address
1853  */
1854 int
1855 sif6addr(u, o, h)
1856     int u;
1857     eui64_t o, h;
1858 {
1859     struct lifreq lifr;
1860     struct sockaddr_storage laddr;
1861     struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&laddr;
1862     int fd;
1863
1864     fd = socket(AF_INET6, SOCK_DGRAM, 0);
1865     if (fd < 0)
1866         return 0;
1867
1868     memset(&lifr, 0, sizeof(lifr));
1869     strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
1870
1871     /*
1872      * Do this because /dev/ppp responds to DL_PHYS_ADDR_REQ with
1873      * zero values, hence the interface token came to be zero too,
1874      * and without this, in.ndpd will complain
1875      */
1876     IN6_LLTOKEN_FROM_EUI64(lifr, sin6, o);
1877     if (ioctl(fd, SIOCSLIFTOKEN, &lifr) < 0) {
1878         close(fd);
1879         return 0;
1880     }
1881
1882     /*
1883      * Set the interface address and destination address
1884      */
1885     IN6_LLADDR_FROM_EUI64(lifr, sin6, o);
1886     if (ioctl(fd, SIOCSLIFADDR, &lifr) < 0) {
1887         close(fd);
1888         return 0;
1889     }
1890
1891     memset(&lifr, 0, sizeof(lifr));
1892     strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name));
1893     IN6_LLADDR_FROM_EUI64(lifr, sin6, h);
1894     if (ioctl(fd, SIOCSLIFDSTADDR, &lifr) < 0) {
1895         close(fd);
1896         return 0;
1897     }
1898
1899     return 1;
1900 }
1901
1902 /*
1903  * cif6addr - Remove the IPv6 address from interface
1904  */
1905 int
1906 cif6addr(u, o, h)
1907     int u;
1908     eui64_t o, h;
1909 {
1910     return 1;
1911 }
1912
1913 #endif /* defined(SOL2) && defined(INET6) */
1914
1915
1916 #define INET_ADDR(x)    (((struct sockaddr_in *) &(x))->sin_addr.s_addr)
1917
1918 /*
1919  * sifaddr - Config the interface IP addresses and netmask.
1920  */
1921 int
1922 sifaddr(u, o, h, m)
1923     int u;
1924     u_int32_t o, h, m;
1925 {
1926     struct ifreq ifr;
1927     int ret = 1;
1928
1929     memset(&ifr, 0, sizeof(ifr));
1930     strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
1931     ifr.ifr_addr.sa_family = AF_INET;
1932     INET_ADDR(ifr.ifr_addr) = m;
1933     if (ioctl(ipfd, SIOCSIFNETMASK, &ifr) < 0) {
1934         error("Couldn't set IP netmask: %m");
1935         ret = 0;
1936     }
1937     ifr.ifr_addr.sa_family = AF_INET;
1938     INET_ADDR(ifr.ifr_addr) = o;
1939     if (ioctl(ipfd, SIOCSIFADDR, &ifr) < 0) {
1940         error("Couldn't set local IP address: %m");
1941         ret = 0;
1942     }
1943
1944     /*
1945      * On some systems, we have to explicitly set the point-to-point
1946      * flag bit before we can set a destination address.
1947      */
1948     if (ioctl(ipfd, SIOCGIFFLAGS, &ifr) >= 0
1949         && (ifr.ifr_flags & IFF_POINTOPOINT) == 0) {
1950         ifr.ifr_flags |= IFF_POINTOPOINT;
1951         if (ioctl(ipfd, SIOCSIFFLAGS, &ifr) < 0) {
1952             error("Couldn't mark interface pt-to-pt: %m");
1953             ret = 0;
1954         }
1955     }
1956     ifr.ifr_dstaddr.sa_family = AF_INET;
1957     INET_ADDR(ifr.ifr_dstaddr) = h;
1958     if (ioctl(ipfd, SIOCSIFDSTADDR, &ifr) < 0) {
1959         error("Couldn't set remote IP address: %m");
1960         ret = 0;
1961     }
1962
1963     remote_addr = h;
1964     return ret;
1965 }
1966
1967 /*
1968  * cifaddr - Clear the interface IP addresses, and delete routes
1969  * through the interface if possible.
1970  */
1971 int
1972 cifaddr(u, o, h)
1973     int u;
1974     u_int32_t o, h;
1975 {
1976 #if defined(__USLC__)           /* was: #if 0 */
1977     cifroute(unit, ouraddr, hisaddr);
1978     if (ipmuxid >= 0) {
1979         notice("Removing ppp interface unit");
1980         if (ioctl(ipfd, I_UNLINK, ipmuxid) < 0) {
1981             error("Can't remove ppp interface unit: %m");
1982             return 0;
1983         }
1984         ipmuxid = -1;
1985     }
1986 #endif
1987     remote_addr = 0;
1988     return 1;
1989 }
1990
1991 /*
1992  * sifdefaultroute - assign a default route through the address given.
1993  */
1994 int
1995 sifdefaultroute(u, l, g)
1996     int u;
1997     u_int32_t l, g;
1998 {
1999     struct rtentry rt;
2000
2001 #if defined(__USLC__)
2002     g = l;                      /* use the local address as gateway */
2003 #endif
2004     memset(&rt, 0, sizeof(rt));
2005     rt.rt_dst.sa_family = AF_INET;
2006     INET_ADDR(rt.rt_dst) = 0;
2007     rt.rt_gateway.sa_family = AF_INET;
2008     INET_ADDR(rt.rt_gateway) = g;
2009     rt.rt_flags = RTF_GATEWAY;
2010
2011     if (ioctl(ipfd, SIOCADDRT, &rt) < 0) {
2012         error("Can't add default route: %m");
2013         return 0;
2014     }
2015
2016     default_route_gateway = g;
2017     return 1;
2018 }
2019
2020 /*
2021  * cifdefaultroute - delete a default route through the address given.
2022  */
2023 int
2024 cifdefaultroute(u, l, g)
2025     int u;
2026     u_int32_t l, g;
2027 {
2028     struct rtentry rt;
2029
2030 #if defined(__USLC__)
2031     g = l;                      /* use the local address as gateway */
2032 #endif
2033     memset(&rt, 0, sizeof(rt));
2034     rt.rt_dst.sa_family = AF_INET;
2035     INET_ADDR(rt.rt_dst) = 0;
2036     rt.rt_gateway.sa_family = AF_INET;
2037     INET_ADDR(rt.rt_gateway) = g;
2038     rt.rt_flags = RTF_GATEWAY;
2039
2040     if (ioctl(ipfd, SIOCDELRT, &rt) < 0) {
2041         error("Can't delete default route: %m");
2042         return 0;
2043     }
2044
2045     default_route_gateway = 0;
2046     return 1;
2047 }
2048
2049 /*
2050  * sifproxyarp - Make a proxy ARP entry for the peer.
2051  */
2052 int
2053 sifproxyarp(unit, hisaddr)
2054     int unit;
2055     u_int32_t hisaddr;
2056 {
2057     struct arpreq arpreq;
2058
2059     memset(&arpreq, 0, sizeof(arpreq));
2060     if (!get_ether_addr(hisaddr, &arpreq.arp_ha))
2061         return 0;
2062
2063     arpreq.arp_pa.sa_family = AF_INET;
2064     INET_ADDR(arpreq.arp_pa) = hisaddr;
2065     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
2066     if (ioctl(ipfd, SIOCSARP, (caddr_t) &arpreq) < 0) {
2067         error("Couldn't set proxy ARP entry: %m");
2068         return 0;
2069     }
2070
2071     proxy_arp_addr = hisaddr;
2072     return 1;
2073 }
2074
2075 /*
2076  * cifproxyarp - Delete the proxy ARP entry for the peer.
2077  */
2078 int
2079 cifproxyarp(unit, hisaddr)
2080     int unit;
2081     u_int32_t hisaddr;
2082 {
2083     struct arpreq arpreq;
2084
2085     memset(&arpreq, 0, sizeof(arpreq));
2086     arpreq.arp_pa.sa_family = AF_INET;
2087     INET_ADDR(arpreq.arp_pa) = hisaddr;
2088     if (ioctl(ipfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
2089         error("Couldn't delete proxy ARP entry: %m");
2090         return 0;
2091     }
2092
2093     proxy_arp_addr = 0;
2094     return 1;
2095 }
2096
2097 /*
2098  * get_ether_addr - get the hardware address of an interface on the
2099  * the same subnet as ipaddr.
2100  */
2101 #define MAX_IFS         32
2102
2103 static int
2104 get_ether_addr(ipaddr, hwaddr)
2105     u_int32_t ipaddr;
2106     struct sockaddr *hwaddr;
2107 {
2108     struct ifreq *ifr, *ifend, ifreq;
2109     int nif;
2110     struct ifconf ifc;
2111     u_int32_t ina, mask;
2112
2113     /*
2114      * Scan through the system's network interfaces.
2115      */
2116 #ifdef SIOCGIFNUM
2117     if (ioctl(ipfd, SIOCGIFNUM, &nif) < 0)
2118 #endif
2119         nif = MAX_IFS;
2120     ifc.ifc_len = nif * sizeof(struct ifreq);
2121     ifc.ifc_buf = (caddr_t) malloc(ifc.ifc_len);
2122     if (ifc.ifc_buf == 0)
2123         return 0;
2124     if (ioctl(ipfd, SIOCGIFCONF, &ifc) < 0) {
2125         warn("Couldn't get system interface list: %m");
2126         free(ifc.ifc_buf);
2127         return 0;
2128     }
2129     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
2130     for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
2131         if (ifr->ifr_addr.sa_family != AF_INET)
2132             continue;
2133         /*
2134          * Check that the interface is up, and not point-to-point or loopback.
2135          */
2136         strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
2137         if (ioctl(ipfd, SIOCGIFFLAGS, &ifreq) < 0)
2138             continue;
2139         if ((ifreq.ifr_flags &
2140              (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
2141             != (IFF_UP|IFF_BROADCAST))
2142             continue;
2143         /*
2144          * Get its netmask and check that it's on the right subnet.
2145          */
2146         if (ioctl(ipfd, SIOCGIFNETMASK, &ifreq) < 0)
2147             continue;
2148         ina = INET_ADDR(ifr->ifr_addr);
2149         mask = INET_ADDR(ifreq.ifr_addr);
2150         if ((ipaddr & mask) == (ina & mask))
2151             break;
2152     }
2153
2154     if (ifr >= ifend) {
2155         warn("No suitable interface found for proxy ARP");
2156         free(ifc.ifc_buf);
2157         return 0;
2158     }
2159
2160     info("found interface %s for proxy ARP", ifr->ifr_name);
2161     if (!get_hw_addr(ifr->ifr_name, ina, hwaddr)) {
2162         error("Couldn't get hardware address for %s", ifr->ifr_name);
2163         free(ifc.ifc_buf);
2164         return 0;
2165     }
2166
2167     free(ifc.ifc_buf);
2168     return 1;
2169 }
2170
2171 /*
2172  * get_hw_addr_dlpi - obtain the hardware address using DLPI
2173  */
2174 static int
2175 get_hw_addr_dlpi(name, hwaddr)
2176     char *name;
2177     struct sockaddr *hwaddr;
2178 {
2179     char *p, *q;
2180     int unit, iffd, adrlen;
2181     unsigned char *adrp;
2182     char ifdev[24];
2183     struct {
2184         union DL_primitives prim;
2185         char space[64];
2186     } reply;
2187
2188     /*
2189      * We have to open the device and ask it for its hardware address.
2190      * First split apart the device name and unit.
2191      */
2192     slprintf(ifdev, sizeof(ifdev), "/dev/%s", name);
2193     for (q = ifdev + strlen(ifdev); --q >= ifdev; )
2194         if (!isdigit(*q))
2195             break;
2196     unit = atoi(q+1);
2197     q[1] = 0;
2198
2199     /*
2200      * Open the device and do a DLPI attach and phys_addr_req.
2201      */
2202     iffd = open(ifdev, O_RDWR);
2203     if (iffd < 0) {
2204         error("Can't open %s: %m", ifdev);
2205         return 0;
2206     }
2207     if (dlpi_attach(iffd, unit) < 0
2208         || dlpi_get_reply(iffd, &reply.prim, DL_OK_ACK, sizeof(reply)) < 0
2209         || dlpi_info_req(iffd) < 0
2210         || dlpi_get_reply(iffd, &reply.prim, DL_INFO_ACK, sizeof(reply)) < 0) {
2211         close(iffd);
2212         return 0;
2213     }
2214
2215     adrlen = reply.prim.info_ack.dl_addr_length;
2216     adrp = (unsigned char *)&reply + reply.prim.info_ack.dl_addr_offset;
2217
2218 #if DL_CURRENT_VERSION >= 2
2219     if (reply.prim.info_ack.dl_sap_length < 0)
2220         adrlen += reply.prim.info_ack.dl_sap_length;
2221     else
2222         adrp += reply.prim.info_ack.dl_sap_length;
2223 #endif
2224
2225     hwaddr->sa_family = AF_UNSPEC;
2226     memcpy(hwaddr->sa_data, adrp, adrlen);
2227
2228     return 1;
2229 }
2230 /*
2231  * get_hw_addr - obtain the hardware address for a named interface.
2232  */
2233 static int
2234 get_hw_addr(name, ina, hwaddr)
2235     char *name;
2236     u_int32_t ina;
2237     struct sockaddr *hwaddr;
2238 {
2239     /* New way - get the address by doing an arp request. */
2240     int s;
2241     struct arpreq req;
2242
2243     s = socket(AF_INET, SOCK_DGRAM, 0);
2244     if (s < 0)
2245         return 0;
2246     memset(&req, 0, sizeof(req));
2247     req.arp_pa.sa_family = AF_INET;
2248     INET_ADDR(req.arp_pa) = ina;
2249     if (ioctl(s, SIOCGARP, &req) < 0) {
2250         error("Couldn't get ARP entry for %s: %m", ip_ntoa(ina));
2251         return 0;
2252     }
2253     *hwaddr = req.arp_ha;
2254     hwaddr->sa_family = AF_UNSPEC;
2255
2256     return 1;
2257 }
2258
2259 static int
2260 dlpi_attach(fd, ppa)
2261     int fd, ppa;
2262 {
2263     dl_attach_req_t req;
2264     struct strbuf buf;
2265
2266     req.dl_primitive = DL_ATTACH_REQ;
2267     req.dl_ppa = ppa;
2268     buf.len = sizeof(req);
2269     buf.buf = (void *) &req;
2270     return putmsg(fd, &buf, NULL, RS_HIPRI);
2271 }
2272
2273 static int
2274 dlpi_info_req(fd)
2275     int fd;
2276 {
2277     dl_info_req_t req;
2278     struct strbuf buf;
2279
2280     req.dl_primitive = DL_INFO_REQ;
2281     buf.len = sizeof(req);
2282     buf.buf = (void *) &req;
2283     return putmsg(fd, &buf, NULL, RS_HIPRI);
2284 }
2285
2286 static int
2287 dlpi_get_reply(fd, reply, expected_prim, maxlen)
2288     union DL_primitives *reply;
2289     int fd, expected_prim, maxlen;
2290 {
2291     struct strbuf buf;
2292     int flags, n;
2293     struct pollfd pfd;
2294
2295     /*
2296      * Use poll to wait for a message with a timeout.
2297      */
2298     pfd.fd = fd;
2299     pfd.events = POLLIN | POLLPRI;
2300     do {
2301         n = poll(&pfd, 1, 1000);
2302     } while (n == -1 && errno == EINTR);
2303     if (n <= 0)
2304         return -1;
2305
2306     /*
2307      * Get the reply.
2308      */
2309     buf.maxlen = maxlen;
2310     buf.buf = (void *) reply;
2311     flags = 0;
2312     if (getmsg(fd, &buf, NULL, &flags) < 0)
2313         return -1;
2314
2315     if (buf.len < sizeof(ulong)) {
2316         if (debug)
2317             dbglog("dlpi response short (len=%d)\n", buf.len);
2318         return -1;
2319     }
2320
2321     if (reply->dl_primitive == expected_prim)
2322         return 0;
2323
2324     if (debug) {
2325         if (reply->dl_primitive == DL_ERROR_ACK) {
2326             dbglog("dlpi error %d (unix errno %d) for prim %x\n",
2327                    reply->error_ack.dl_errno, reply->error_ack.dl_unix_errno,
2328                    reply->error_ack.dl_error_primitive);
2329         } else {
2330             dbglog("dlpi unexpected response prim %x\n",
2331                    reply->dl_primitive);
2332         }
2333     }
2334
2335     return -1;
2336 }
2337
2338 /*
2339  * Return user specified netmask, modified by any mask we might determine
2340  * for address `addr' (in network byte order).
2341  * Here we scan through the system's list of interfaces, looking for
2342  * any non-point-to-point interfaces which might appear to be on the same
2343  * network as `addr'.  If we find any, we OR in their netmask to the
2344  * user-specified netmask.
2345  */
2346 u_int32_t
2347 GetMask(addr)
2348     u_int32_t addr;
2349 {
2350     u_int32_t mask, nmask, ina;
2351     struct ifreq *ifr, *ifend, ifreq;
2352     int nif;
2353     struct ifconf ifc;
2354
2355     addr = ntohl(addr);
2356     if (IN_CLASSA(addr))        /* determine network mask for address class */
2357         nmask = IN_CLASSA_NET;
2358     else if (IN_CLASSB(addr))
2359         nmask = IN_CLASSB_NET;
2360     else
2361         nmask = IN_CLASSC_NET;
2362     /* class D nets are disallowed by bad_ip_adrs */
2363     mask = netmask | htonl(nmask);
2364
2365     /*
2366      * Scan through the system's network interfaces.
2367      */
2368 #ifdef SIOCGIFNUM
2369     if (ioctl(ipfd, SIOCGIFNUM, &nif) < 0)
2370 #endif
2371         nif = MAX_IFS;
2372     ifc.ifc_len = nif * sizeof(struct ifreq);
2373     ifc.ifc_buf = (caddr_t) malloc(ifc.ifc_len);
2374     if (ifc.ifc_buf == 0)
2375         return mask;
2376     if (ioctl(ipfd, SIOCGIFCONF, &ifc) < 0) {
2377         warn("Couldn't get system interface list: %m");
2378         free(ifc.ifc_buf);
2379         return mask;
2380     }
2381     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
2382     for (ifr = ifc.ifc_req; ifr < ifend; ++ifr) {
2383         /*
2384          * Check the interface's internet address.
2385          */
2386         if (ifr->ifr_addr.sa_family != AF_INET)
2387             continue;
2388         ina = INET_ADDR(ifr->ifr_addr);
2389         if ((ntohl(ina) & nmask) != (addr & nmask))
2390             continue;
2391         /*
2392          * Check that the interface is up, and not point-to-point or loopback.
2393          */
2394         strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
2395         if (ioctl(ipfd, SIOCGIFFLAGS, &ifreq) < 0)
2396             continue;
2397         if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
2398             != IFF_UP)
2399             continue;
2400         /*
2401          * Get its netmask and OR it into our mask.
2402          */
2403         if (ioctl(ipfd, SIOCGIFNETMASK, &ifreq) < 0)
2404             continue;
2405         mask |= INET_ADDR(ifreq.ifr_addr);
2406     }
2407
2408     free(ifc.ifc_buf);
2409     return mask;
2410 }
2411
2412 /*
2413  * logwtmp - write an accounting record to the /var/adm/wtmp file.
2414  */
2415 void
2416 logwtmp(line, name, host)
2417     const char *line, *name, *host;
2418 {
2419     static struct utmpx utmpx;
2420
2421     if (name[0] != 0) {
2422         /* logging in */
2423         strncpy(utmpx.ut_user, name, sizeof(utmpx.ut_user));
2424         strncpy(utmpx.ut_id, ifname, sizeof(utmpx.ut_id));
2425         strncpy(utmpx.ut_line, line, sizeof(utmpx.ut_line));
2426         utmpx.ut_pid = getpid();
2427         utmpx.ut_type = USER_PROCESS;
2428     } else {
2429         utmpx.ut_type = DEAD_PROCESS;
2430     }
2431     gettimeofday(&utmpx.ut_tv, NULL);
2432     updwtmpx("/var/adm/wtmpx", &utmpx);
2433 }
2434
2435 /*
2436  * get_host_seed - return the serial number of this machine.
2437  */
2438 int
2439 get_host_seed()
2440 {
2441     char buf[32];
2442
2443     if (sysinfo(SI_HW_SERIAL, buf, sizeof(buf)) < 0) {
2444         error("sysinfo: %m");
2445         return 0;
2446     }
2447     return (int) strtoul(buf, NULL, 16);
2448 }
2449
2450 static int
2451 strioctl(fd, cmd, ptr, ilen, olen)
2452     int fd, cmd, ilen, olen;
2453     void *ptr;
2454 {
2455     struct strioctl str;
2456
2457     str.ic_cmd = cmd;
2458     str.ic_timout = 0;
2459     str.ic_len = ilen;
2460     str.ic_dp = ptr;
2461     if (ioctl(fd, I_STR, &str) == -1)
2462         return -1;
2463     if (str.ic_len != olen)
2464         dbglog("strioctl: expected %d bytes, got %d for cmd %x\n",
2465                olen, str.ic_len, cmd);
2466     return 0;
2467 }
2468
2469 #if 0
2470 /*
2471  * lock - create a lock file for the named lock device
2472  */
2473
2474 #define LOCK_PREFIX     "/var/spool/locks/LK."
2475 static char lock_file[40];      /* name of lock file created */
2476
2477 int
2478 lock(dev)
2479     char *dev;
2480 {
2481     int n, fd, pid;
2482     struct stat sbuf;
2483     char ascii_pid[12];
2484
2485     if (stat(dev, &sbuf) < 0) {
2486         error("Can't get device number for %s: %m", dev);
2487         return -1;
2488     }
2489     if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
2490         error("Can't lock %s: not a character device", dev);
2491         return -1;
2492     }
2493     slprintf(lock_file, sizeof(lock_file), "%s%03d.%03d.%03d",
2494              LOCK_PREFIX, major(sbuf.st_dev),
2495              major(sbuf.st_rdev), minor(sbuf.st_rdev));
2496
2497     while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
2498         if (errno == EEXIST
2499             && (fd = open(lock_file, O_RDONLY, 0)) >= 0) {
2500             /* Read the lock file to find out who has the device locked */
2501             n = read(fd, ascii_pid, 11);
2502             if (n <= 0) {
2503                 error("Can't read pid from lock file %s", lock_file);
2504                 close(fd);
2505             } else {
2506                 ascii_pid[n] = 0;
2507                 pid = atoi(ascii_pid);
2508                 if (pid > 0 && kill(pid, 0) == -1 && errno == ESRCH) {
2509                     /* pid no longer exists - remove the lock file */
2510                     if (unlink(lock_file) == 0) {
2511                         close(fd);
2512                         notice("Removed stale lock on %s (pid %d)",
2513                                dev, pid);
2514                         continue;
2515                     } else
2516                         warn("Couldn't remove stale lock on %s",
2517                                dev);
2518                 } else
2519                     notice("Device %s is locked by pid %d",
2520                            dev, pid);
2521             }
2522             close(fd);
2523         } else
2524             error("Can't create lock file %s: %m", lock_file);
2525         lock_file[0] = 0;
2526         return -1;
2527     }
2528
2529     slprintf(ascii_pid, sizeof(ascii_pid), "%10d\n", getpid());
2530     write(fd, ascii_pid, 11);
2531
2532     close(fd);
2533     return 1;
2534 }
2535
2536 /*
2537  * unlock - remove our lockfile
2538  */
2539 void
2540 unlock()
2541 {
2542     if (lock_file[0]) {
2543         unlink(lock_file);
2544         lock_file[0] = 0;
2545     }
2546 }
2547 #endif
2548
2549 /*
2550  * cifroute - delete a route through the addresses given.
2551  */
2552 int
2553 cifroute(u, our, his)
2554     int u;
2555     u_int32_t our, his;
2556 {
2557     struct rtentry rt;
2558
2559     memset(&rt, 0, sizeof(rt));
2560     rt.rt_dst.sa_family = AF_INET;
2561     INET_ADDR(rt.rt_dst) = his;
2562     rt.rt_gateway.sa_family = AF_INET;
2563     INET_ADDR(rt.rt_gateway) = our;
2564     rt.rt_flags = RTF_HOST;
2565
2566     if (ioctl(ipfd, SIOCDELRT, &rt) < 0) {
2567         error("Can't delete route: %m");
2568         return 0;
2569     }
2570
2571     return 1;
2572 }
2573
2574 /*
2575  * have_route_to - determine if the system has a route to the specified
2576  * IP address.  Returns 0 if not, 1 if so, -1 if we can't tell.
2577  * `addr' is in network byte order.
2578  * For demand mode to work properly, we have to ignore routes
2579  * through our own interface.
2580  */
2581 #ifndef T_CURRENT               /* needed for Solaris 2.5 */
2582 #define T_CURRENT       MI_T_CURRENT
2583 #endif
2584
2585 int
2586 have_route_to(addr)
2587     u_int32_t addr;
2588 {
2589 #ifdef SOL2
2590     int fd, r, flags, i;
2591     struct {
2592         struct T_optmgmt_req req;
2593         struct opthdr hdr;
2594     } req;
2595     union {
2596         struct T_optmgmt_ack ack;
2597         unsigned char space[64];
2598     } ack;
2599     struct opthdr *rh;
2600     struct strbuf cbuf, dbuf;
2601     int nroutes;
2602     mib2_ipRouteEntry_t routes[8];
2603     mib2_ipRouteEntry_t *rp;
2604
2605     fd = open(mux_dev_name, O_RDWR);
2606     if (fd < 0) {
2607         warn("have_route_to: couldn't open %s: %m", mux_dev_name);
2608         return -1;
2609     }
2610
2611     req.req.PRIM_type = T_OPTMGMT_REQ;
2612     req.req.OPT_offset = (char *) &req.hdr - (char *) &req;
2613     req.req.OPT_length = sizeof(req.hdr);
2614     req.req.MGMT_flags = T_CURRENT;
2615
2616     req.hdr.level = MIB2_IP;
2617     req.hdr.name = 0;
2618     req.hdr.len = 0;
2619
2620     cbuf.buf = (char *) &req;
2621     cbuf.len = sizeof(req);
2622
2623     if (putmsg(fd, &cbuf, NULL, 0) == -1) {
2624         warn("have_route_to: putmsg: %m");
2625         close(fd);
2626         return -1;
2627     }
2628
2629     for (;;) {
2630         cbuf.buf = (char *) &ack;
2631         cbuf.maxlen = sizeof(ack);
2632         dbuf.buf = (char *) routes;
2633         dbuf.maxlen = sizeof(routes);
2634         flags = 0;
2635         r = getmsg(fd, &cbuf, &dbuf, &flags);
2636         if (r == -1) {
2637             warn("have_route_to: getmsg: %m");
2638             close(fd);
2639             return -1;
2640         }
2641
2642         if (cbuf.len < sizeof(struct T_optmgmt_ack)
2643             || ack.ack.PRIM_type != T_OPTMGMT_ACK
2644             || ack.ack.MGMT_flags != T_SUCCESS
2645             || ack.ack.OPT_length < sizeof(struct opthdr)) {
2646             dbglog("have_route_to: bad message len=%d prim=%d",
2647                    cbuf.len, ack.ack.PRIM_type);
2648             close(fd);
2649             return -1;
2650         }
2651
2652         rh = (struct opthdr *) ((char *)&ack + ack.ack.OPT_offset);
2653         if (rh->level == 0 && rh->name == 0)
2654             break;
2655         if (rh->level != MIB2_IP || rh->name != MIB2_IP_21) {
2656             while (r == MOREDATA)
2657                 r = getmsg(fd, NULL, &dbuf, &flags);
2658             continue;
2659         }
2660
2661         for (;;) {
2662             nroutes = dbuf.len / sizeof(mib2_ipRouteEntry_t);
2663             for (rp = routes, i = 0; i < nroutes; ++i, ++rp) {
2664                 if (rp->ipRouteMask != ~0) {
2665                     dbglog("have_route_to: dest=%x gw=%x mask=%x\n",
2666                            rp->ipRouteDest, rp->ipRouteNextHop,
2667                            rp->ipRouteMask);
2668                     if (((addr ^ rp->ipRouteDest) & rp->ipRouteMask) == 0
2669                         && rp->ipRouteNextHop != remote_addr)
2670                         return 1;
2671                 }
2672             }
2673             if (r == 0)
2674                 break;
2675             r = getmsg(fd, NULL, &dbuf, &flags);
2676         }
2677     }
2678     close(fd);
2679     return 0;
2680 #else
2681     return -1;
2682 #endif /* SOL2 */
2683 }
2684
2685 /*
2686  * get_pty - get a pty master/slave pair and chown the slave side to
2687  * the uid given.  Assumes slave_name points to MAXPATHLEN bytes of space.
2688  */
2689 int
2690 get_pty(master_fdp, slave_fdp, slave_name, uid)
2691     int *master_fdp;
2692     int *slave_fdp;
2693     char *slave_name;
2694     int uid;
2695 {
2696     int mfd, sfd;
2697     char *pty_name;
2698     struct termios tios;
2699
2700     mfd = open("/dev/ptmx", O_RDWR);
2701     if (mfd < 0) {
2702         error("Couldn't open pty master: %m");
2703         return 0;
2704     }
2705
2706     pty_name = ptsname(mfd);
2707     if (pty_name == NULL) {
2708         error("Couldn't get name of pty slave");
2709         close(mfd);
2710         return 0;
2711     }
2712     if (chown(pty_name, uid, -1) < 0)
2713         warn("Couldn't change owner of pty slave: %m");
2714     if (chmod(pty_name, S_IRUSR | S_IWUSR) < 0)
2715         warn("Couldn't change permissions on pty slave: %m");
2716     if (unlockpt(mfd) < 0)
2717         warn("Couldn't unlock pty slave: %m");
2718
2719     sfd = open(pty_name, O_RDWR);
2720     if (sfd < 0) {
2721         error("Couldn't open pty slave %s: %m", pty_name);
2722         close(mfd);
2723         return 0;
2724     }
2725     if (ioctl(sfd, I_PUSH, "ptem") < 0)
2726         warn("Couldn't push ptem module on pty slave: %m");
2727
2728     dbglog("Using %s", pty_name);
2729     strlcpy(slave_name, pty_name, MAXPATHLEN);
2730     *master_fdp = mfd;
2731     *slave_fdp = sfd;
2732
2733     return 1;
2734 }