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