]> git.ozlabs.org Git - ppp.git/blob - pppd/sys-str.c
incorporate logwtmp in here
[ppp.git] / pppd / sys-str.c
1 /*
2  * sys-str.c - System-dependent procedures for setting up
3  * PPP interfaces on systems which use the STREAMS ppp interface.
4  *
5  * Copyright (c) 1989 Carnegie Mellon University.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by Carnegie Mellon University.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  */
20
21 /*
22  * TODO:
23  */
24
25 #include <stdio.h>
26 #include <errno.h>
27 #include <syslog.h>
28 #include <fcntl.h>
29 #include <string.h>
30 #include <time.h>
31 #include <file.h>
32 #include <utmp.h>
33 #include <sys/ioctl.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/time.h>
37 #include <sys/stream.h>
38 #include <sys/stropts.h>
39
40 #include <net/if.h>
41 #include <net/route.h>
42 #include <net/if_arp.h>
43 #include <netinet/in.h>
44
45 #include "pppd.h"
46 #include "ppp.h"
47 #include <net/if_ppp.h>
48 #include <net/ppp_str.h>
49
50 #ifndef ifr_mtu
51 #define ifr_mtu         ifr_metric
52 #endif
53
54 #define MAXMODULES      10      /* max number of module names to save */
55 static struct   modlist {
56     char        modname[FMNAMESZ+1];
57 } str_modules[MAXMODULES];
58 static int      str_module_count = 0;
59 static int      pushed_ppp;
60
61 extern int hungup;              /* has the physical layer been disconnected? */
62 extern int kdebugflag;
63
64 #define PAI_FLAGS_B7_0          0x100
65 #define PAI_FLAGS_B7_1          0x200
66 #define PAI_FLAGS_PAR_EVEN      0x400
67 #define PAI_FLAGS_PAR_ODD       0x800
68 #define PAI_FLAGS_HIBITS        0xF00
69
70 /*
71  * ppp_available - check if this kernel supports PPP.
72  */
73 int
74 ppp_available()
75 {
76     int fd, ret;
77
78     fd = open("/dev/tty", O_RDONLY, 0);
79     if (fd < 0)
80         return 1;               /* can't find out - assume we have ppp */
81     ret = ioctl(fd, I_FIND, "pppasync") >= 0;
82     close(fd);
83     return ret;
84 }
85
86
87 /*
88  * establish_ppp - Turn the serial port into a ppp interface.
89  */
90 void
91 establish_ppp()
92 {
93     /* go through and save the name of all the modules, then pop em */
94     for (;;) { 
95         if (ioctl(fd, I_LOOK, str_modules[str_module_count].modname) < 0 ||
96             ioctl(fd, I_POP, 0) < 0)
97             break;
98         MAINDEBUG((LOG_DEBUG, "popped stream module : %s",
99                    str_modules[str_module_count].modname));
100         str_module_count++;
101     }
102
103     /* now push the async/fcs module */
104     if (ioctl(fd, I_PUSH, "pppasync") < 0) {
105         syslog(LOG_ERR, "ioctl(I_PUSH, ppp_async): %m");
106         die(1);
107     }
108     /* finally, push the ppp_if module that actually handles the */
109     /* network interface */ 
110     if (ioctl(fd, I_PUSH, "pppif") < 0) {
111         syslog(LOG_ERR, "ioctl(I_PUSH, ppp_if): %m");
112         die(1);
113     }
114     pushed_ppp = 1;
115     if (ioctl(fd, I_SETSIG, S_INPUT) < 0) {
116         syslog(LOG_ERR, "ioctl(I_SETSIG, S_INPUT): %m");
117         die(1);
118     }
119     /* read mode, message non-discard mode */
120     if (ioctl(fd, I_SRDOPT, RMSGN) < 0) {
121         syslog(LOG_ERR, "ioctl(I_SRDOPT, RMSGN): %m");
122         die(1);
123     }
124     /* Flush any waiting messages, or we'll never get SIGPOLL */
125     if (ioctl(fd, I_FLUSH, FLUSHRW) < 0) {
126         syslog(LOG_ERR, "ioctl(I_FLUSH, FLUSHRW): %m");
127         die(1);
128     }
129     /*
130      * Find out which interface we were given.
131      * (ppp_if handles this ioctl)
132      */
133     if (ioctl(fd, SIOCGETU, &ifunit) < 0) {
134         syslog(LOG_ERR, "ioctl(SIOCGETU): %m");
135         die(1);
136     }
137
138     /* Set debug flags in driver */
139     if (ioctl(fd, SIOCSIFDEBUG, &kdebugflag) < 0) {
140         syslog(LOG_ERR, "ioctl(SIOCSIFDEBUG): %m");
141     }
142 }
143
144 /*
145  * disestablish_ppp - Restore the serial port to normal operation.
146  * It attempts to reconstruct the stream with the previously popped
147  * modules.  This shouldn't call die() because it's called from die().
148  */
149 void
150 disestablish_ppp()
151 {
152     int flags;
153     char *s;
154
155     if (hungup) {
156         /* we can't push or pop modules after the stream has hung up */
157         str_module_count = 0;
158         return;
159     }
160
161     if (pushed_ppp) {
162         /*
163          * Check whether the link seems not to be 8-bit clean.
164          */
165         if (ioctl(fd, SIOCGIFDEBUG, (caddr_t) &flags) == 0) {
166             s = NULL;
167             switch (~flags & PAI_FLAGS_HIBITS) {
168             case PAI_FLAGS_B7_0:
169                 s = "bit 7 set to 1";
170                 break;
171             case PAI_FLAGS_B7_1:
172                 s = "bit 7 set to 0";
173                 break;
174             case PAI_FLAGS_PAR_EVEN:
175                 s = "odd parity";
176                 break;
177             case PAI_FLAGS_PAR_ODD:
178                 s = "even parity";
179                 break;
180             }
181             if (s != NULL) {
182                 syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
183                 syslog(LOG_WARNING, "All received characters had %s", s);
184             }
185         }
186     }
187
188     while (ioctl(fd, I_POP, 0) == 0)    /* pop any we pushed */
189         ;
190     pushed_ppp = 0;
191   
192     for (; str_module_count > 0; str_module_count--) {
193         if (ioctl(fd, I_PUSH, str_modules[str_module_count-1].modname)) {
194             syslog(LOG_WARNING, "str_restore: couldn't push module %s: %m",
195                    str_modules[str_module_count-1].modname);
196         } else {
197             MAINDEBUG((LOG_INFO, "str_restore: pushed module %s",
198                        str_modules[str_module_count-1].modname));
199         }
200     }
201 }
202
203
204 /*
205  * output - Output PPP packet.
206  */
207 void
208 output(unit, p, len)
209     int unit;
210     u_char *p;
211     int len;
212 {
213     struct strbuf       str;
214
215     if (unit != 0)
216         MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
217     if (debug)
218         log_packet(p, len, "sent ");
219
220     str.len = len;
221     str.buf = (caddr_t) p;
222     if(putmsg(fd, NULL, &str, 0) < 0) {
223         syslog(LOG_ERR, "putmsg: %m");
224         die(1);
225     }
226 }
227
228
229 /*
230  * read_packet - get a PPP packet from the serial device.
231  */
232 int
233 read_packet(buf)
234     u_char *buf;
235 {
236     struct strbuf str;
237     int len, i;
238
239     str.maxlen = MTU+DLLHEADERLEN;
240     str.buf = (caddr_t) buf;
241     i = 0;
242     len = getmsg(fd, NULL, &str, &i);
243     if (len < 0) {
244         if (errno == EAGAIN || errno == EWOULDBLOCK) {
245             return -1;
246         }
247         syslog(LOG_ERR, "getmsg(fd) %m");
248         die(1);
249     }
250     if (len) 
251         MAINDEBUG((LOG_DEBUG, "getmsg returned 0x%x",len));
252
253     if (str.len < 0) {
254         MAINDEBUG((LOG_DEBUG, "getmsg short return length %d", str.len));
255         return -1;
256     }
257
258     return str.len;
259 }
260
261
262 /*
263  * ppp_send_config - configure the transmit characteristics of
264  * the ppp interface.
265  */
266 void
267 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
268     int unit, mtu;
269     u_long asyncmap;
270     int pcomp, accomp;
271 {
272     char c;
273     struct ifreq ifr;
274
275     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
276     ifr.ifr_mtu = mtu;
277     if (ioctl(s, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
278         syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
279         quit();
280     }
281
282     if(ioctl(fd, SIOCSIFASYNCMAP, (caddr_t) &asyncmap) < 0) {
283         syslog(LOG_ERR, "ioctl(SIOCSIFASYNCMAP): %m");
284         quit();
285     }
286
287     c = (pcomp? 1: 0);
288     if(ioctl(fd, SIOCSIFCOMPPROT, &c) < 0) {
289         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m");
290         quit();
291     }
292
293     c = (accomp? 1: 0);
294     if(ioctl(fd, SIOCSIFCOMPAC, &c) < 0) {
295         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m");
296         quit();
297     }
298 }
299
300
301 /*
302  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
303  */
304 void
305 ppp_set_xaccm(unit, accm)
306     int unit;
307     ext_accm accm;
308 {
309     if (ioctl(fd, SIOCSIFXASYNCMAP, accm) < 0 && errno != ENOTTY)
310         syslog(LOG_WARNING, "ioctl(set extended ACCM): %m");
311 }
312
313
314 /*
315  * ppp_recv_config - configure the receive-side characteristics of
316  * the ppp interface.
317  */
318 void
319 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
320     int unit, mru;
321     u_long asyncmap;
322     int pcomp, accomp;
323 {
324     char c;
325
326     if (ioctl(fd, SIOCSIFMRU, &mru) < 0) {
327         syslog(LOG_ERR, "ioctl(SIOCSIFMRU): %m");
328     }
329
330     if (ioctl(fd, SIOCSIFRASYNCMAP, (caddr_t) &asyncmap) < 0) {
331         syslog(LOG_ERR, "ioctl(SIOCSIFRASYNCMAP): %m");
332     }
333
334     c = 2 + (pcomp? 1: 0);
335     if(ioctl(fd, SIOCSIFCOMPPROT, &c) < 0) {
336         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m");
337     }
338
339     c = 2 + (accomp? 1: 0);
340     if (ioctl(fd, SIOCSIFCOMPAC, &c) < 0) {
341         syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m");
342     }
343 }
344
345 /*
346  * sifvjcomp - config tcp header compression
347  */
348 int
349 sifvjcomp(u, vjcomp, cidcomp, maxcid)
350     int u, vjcomp, cidcomp, maxcid;
351 {
352     char x;
353
354     x = (vjcomp? 1: 0) + (cidcomp? 0: 2) + (maxcid << 4);
355     if (ioctl(fd, SIOCSIFVJCOMP, (caddr_t) &x) < 0) {
356         syslog(LOG_ERR, "ioctl(SIOCSIFVJCOMP): %m");
357         return 0;
358     }
359     return 1;
360 }
361
362 /*
363  * sifup - Config the interface up.
364  */
365 int
366 sifup(u)
367 {
368     struct ifreq ifr;
369
370     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
371     if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
372         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
373         return 0;
374     }
375     ifr.ifr_flags |= IFF_UP;
376     if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
377         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
378         return 0;
379     }
380     return 1;
381 }
382
383 /*
384  * sifdown - Config the interface down.
385  */
386 int
387 sifdown(u)
388 {
389     struct ifreq ifr;
390     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
391     if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
392         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
393         return 0;
394     }
395     ifr.ifr_flags &= ~IFF_UP;
396     if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
397         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
398         return 0;
399     }
400     return 1;
401 }
402
403 /*
404  * SET_SA_FAMILY - initialize a struct sockaddr, setting the sa_family field.
405  */
406 #define SET_SA_FAMILY(addr, family)             \
407     BZERO((char *) &(addr), sizeof(addr));      \
408     addr.sa_family = (family);
409
410 /*
411  * sifaddr - Config the interface IP addresses and netmask.
412  */
413 int
414 sifaddr(u, o, h, m)
415 {
416     int ret;
417     struct ifreq ifr;
418
419     ret = 1;
420     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
421     SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
422     ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o;
423     if (ioctl(s, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
424         syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m");
425         ret = 0;
426     }
427     ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h;
428     if (ioctl(s, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
429         syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m");
430         ret = 0;
431     }
432     if (m != 0) {
433         ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m;
434         syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m));
435         if (ioctl(s, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
436             syslog(LOG_ERR, "ioctl(SIOCSIFNETMASK): %m");
437             ret = 0;
438         }
439     }
440     return ret;
441 }
442
443 /*
444  * cifaddr - Clear the interface IP addresses, and delete routes
445  * through the interface if possible.
446  */
447 int
448 cifaddr(u, o, h)
449 {
450     struct rtentry rt;
451
452     SET_SA_FAMILY(rt.rt_dst, AF_INET);
453     ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h;
454     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
455     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o;
456     rt.rt_flags = RTF_HOST;
457     if (ioctl(s, SIOCDELRT, (caddr_t) &rt) < 0) {
458         syslog(LOG_ERR, "ioctl(SIOCDELRT): %m");
459         return 0;
460     }
461     return 1;
462 }
463
464 /*
465  * sifdefaultroute - assign a default route through the address given.
466  */
467 int
468 sifdefaultroute(u, g)
469 {
470     struct rtentry rt;
471
472     SET_SA_FAMILY(rt.rt_dst, AF_INET);
473     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
474     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
475     rt.rt_flags = RTF_GATEWAY;
476     if (ioctl(s, SIOCADDRT, &rt) < 0) {
477         syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m");
478         return 0;
479     }
480     return 1;
481 }
482
483 /*
484  * cifdefaultroute - delete a default route through the address given.
485  */
486 int
487 cifdefaultroute(u, g)
488 {
489     struct rtentry rt;
490
491     SET_SA_FAMILY(rt.rt_dst, AF_INET);
492     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
493     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
494     rt.rt_flags = RTF_GATEWAY;
495     if (ioctl(s, SIOCDELRT, &rt) < 0) {
496         syslog(LOG_ERR, "default route ioctl(SIOCDELRT): %m");
497         return 0;
498     }
499     return 1;
500 }
501
502 /*
503  * sifproxyarp - Make a proxy ARP entry for the peer.
504  */
505 int
506 sifproxyarp(unit, hisaddr)
507     int unit;
508     u_long hisaddr;
509 {
510     struct arpreq arpreq;
511
512     BZERO(&arpreq, sizeof(arpreq));
513
514     /*
515      * Get the hardware address of an interface on the same subnet
516      * as our local address.
517      */
518     if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
519         syslog(LOG_WARNING, "Cannot determine ethernet address for proxy ARP");
520         return 0;
521     }
522
523     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
524     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
525     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
526     if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0) {
527         syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
528         return 0;
529     }
530
531     return 1;
532 }
533
534 /*
535  * cifproxyarp - Delete the proxy ARP entry for the peer.
536  */
537 int
538 cifproxyarp(unit, hisaddr)
539     int unit;
540     u_long hisaddr;
541 {
542     struct arpreq arpreq;
543
544     BZERO(&arpreq, sizeof(arpreq));
545     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
546     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
547     if (ioctl(s, SIOCDARP, (caddr_t)&arpreq) < 0) {
548         syslog(LOG_ERR, "ioctl(SIOCDARP): %m");
549         return 0;
550     }
551     return 1;
552 }
553
554 /*
555  * get_ether_addr - get the hardware address of an interface on the
556  * the same subnet as ipaddr.  Code borrowed from myetheraddr.c
557  * in the cslip-2.6 distribution, which is subject to the following
558  * copyright notice (which also applies to logwtmp below):
559  *
560  * Copyright (c) 1990, 1992 The Regents of the University of California.
561  * All rights reserved.
562  *
563  * Redistribution and use in source and binary forms, with or without
564  * modification, are permitted provided that: (1) source code distributions
565  * retain the above copyright notice and this paragraph in its entirety, (2)
566  * distributions including binary code include the above copyright notice and
567  * this paragraph in its entirety in the documentation or other materials
568  * provided with the distribution, and (3) all advertising materials mentioning
569  * features or use of this software display the following acknowledgement:
570  * ``This product includes software developed by the University of California,
571  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
572  * the University nor the names of its contributors may be used to endorse
573  * or promote products derived from this software without specific prior
574  * written permission.
575  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
576  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
577  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
578  */
579
580 #include <fcntl.h>
581 #include <nlist.h>
582 #include <kvm.h>
583 #include <arpa/inet.h>
584
585 /* XXX SunOS 4.1 defines this and 3.5 doesn't... */
586 #ifdef _nlist_h
587 #define SUNOS4
588 #endif
589
590 #ifdef SUNOS4
591 #include <netinet/in_var.h>
592 #endif
593 #include <netinet/if_ether.h>
594
595 /* Cast a struct sockaddr to a structaddr_in */
596 #define SATOSIN(sa) ((struct sockaddr_in *)(sa))
597
598 /* Determine if "bits" is set in "flag" */
599 #define ALLSET(flag, bits) (((flag) & (bits)) == (bits))
600
601 static struct nlist nl[] = {
602 #define N_IFNET 0
603         { "_ifnet" },
604         0
605 };
606
607 static void kread();
608
609 int
610 get_ether_addr(ipaddr, hwaddr)
611     u_long ipaddr;
612     struct sockaddr *hwaddr;
613 {
614     register kvm_t *kd;
615     register struct ifnet *ifp;
616     register struct arpcom *ac;
617     struct arpcom arpcom;
618     struct in_addr *inp;
619 #ifdef SUNOS4
620     register struct ifaddr *ifa;
621     register struct in_ifaddr *in;
622     union {
623         struct ifaddr ifa;
624         struct in_ifaddr in;
625     } ifaddr;
626 #endif
627     u_long addr, mask;
628
629     /* Open kernel memory for reading */
630     kd = kvm_open(0, 0, 0, O_RDONLY, NULL);
631     if (kd == 0) {
632         syslog(LOG_ERR, "kvm_open: %m");
633         return 0;
634     }
635
636     /* Fetch namelist */
637     if (kvm_nlist(kd, nl) != 0) {
638         syslog(LOG_ERR, "kvm_nlist failed");
639         return 0;
640     }
641
642     ac = &arpcom;
643     ifp = &arpcom.ac_if;
644 #ifdef SUNOS4
645     ifa = &ifaddr.ifa;
646     in = &ifaddr.in;
647 #endif
648
649     if (kvm_read(kd, nl[N_IFNET].n_value, (char *)&addr, sizeof(addr))
650         != sizeof(addr)) {
651         syslog(LOG_ERR, "error reading ifnet addr");
652         return 0;
653     }
654     for ( ; addr; addr = (u_long)ifp->if_next) {
655         if (kvm_read(kd, addr, (char *)ac, sizeof(*ac)) != sizeof(*ac)) {
656             syslog(LOG_ERR, "error reading ifnet");
657             return 0;
658         }
659
660         /* Only look at configured, broadcast interfaces */
661         if (!ALLSET(ifp->if_flags, IFF_UP | IFF_BROADCAST))
662             continue;
663 #ifdef SUNOS4
664         /* This probably can't happen... */
665         if (ifp->if_addrlist == 0)
666             continue;
667 #endif
668
669         /* Get interface ip address */
670 #ifdef SUNOS4
671         if (kvm_read(kd, (u_long)ifp->if_addrlist, (char *)&ifaddr,
672                      sizeof(ifaddr)) != sizeof(ifaddr)) {
673             syslog(LOG_ERR, "error reading ifaddr");
674             return 0;
675         }
676         inp = &SATOSIN(&ifa->ifa_addr)->sin_addr;
677 #else
678         inp = &SATOSIN(&ifp->if_addr)->sin_addr;
679 #endif
680
681         /* Check if this interface on the right subnet */
682 #ifdef SUNOS4
683         mask = in->ia_subnetmask;
684 #else
685         mask = ifp->if_subnetmask;
686 #endif
687         if ((ipaddr & mask) != (inp->s_addr & mask))
688             continue;
689
690         /* Copy out the local ethernet address */
691         hwaddr->sa_family = AF_UNSPEC;
692         BCOPY((caddr_t) &arpcom.ac_enaddr, hwaddr->sa_data,
693               sizeof(arpcom.ac_enaddr));
694         return 1;               /* success! */
695     }
696
697     /* couldn't find one */
698     return 0;
699 }
700
701 #define WTMPFILE        "/usr/adm/wtmp"
702
703 int
704 logwtmp(line, name, host)
705     char *line, *name, *host;
706 {
707     int fd;
708     struct stat buf;
709     struct utmp ut;
710
711     if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
712         return;
713     if (!fstat(fd, &buf)) {
714         (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
715         (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
716         (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
717         (void)time(&ut.ut_time);
718         if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp))
719             (void)ftruncate(fd, buf.st_size);
720     }
721     close(fd);
722 }