Initial revision
[ppp.git] / pppd / sys-ultrix.c
1 /*
2  * sys-ultrix.c - System-dependent procedures for setting up
3  * PPP interfaces on Ultrix systems.
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 #ifndef lint
22 static char rcsid[] = "$Id: sys-ultrix.c,v 1.1 1994/04/18 04:11:11 paulus Exp $";
23 #endif
24
25 /*
26  * TODO:
27  */
28
29 #include <syslog.h>
30 #include <sys/ioctl.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/time.h>
34 #include <sys/errno.h>
35
36 #include <net/if.h>
37
38 #include <net/if_ppp.h>
39 #include <net/route.h>
40 #include <netinet/in.h>
41
42 #include "pppd.h"
43 #include "ppp.h"
44
45 static int initdisc = -1;               /* Initial TTY discipline */
46
47
48 /*
49  * establish_ppp - Turn the serial port into a ppp interface.
50  */
51 void
52 establish_ppp()
53 {
54     int pppdisc = PPPDISC;
55
56     if (ioctl(fd, TIOCGETD, &initdisc) < 0) {
57         syslog(LOG_ERR, "ioctl(TIOCGETD): %m");
58         die(1);
59     }
60     if (ioctl(fd, TIOCSETD, &pppdisc) < 0) {
61         syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
62         die(1);
63     }
64
65     /*
66      * Find out which interface we were given.
67      */
68     if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {  
69         syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
70         die(1);
71     }
72
73     /*
74      * Enable debug in the driver if requested.
75      */
76     if (kdebugflag) {
77         if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
78             syslog(LOG_WARNING, "ioctl (PPPIOCGFLAGS): %m");
79         } else {
80             x |= (kdebugflag & 0xFF) * SC_DEBUG;
81             if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
82                 syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %m");
83         }
84     }
85 }
86
87
88 /*
89  * disestablish_ppp - Restore the serial port to normal operation.
90  * This shouldn't call die() because it's called from die().
91  */
92 void
93 disestablish_ppp()
94 {
95     int x;
96     char *s;
97
98     if (initdisc >= 0) {
99         /*
100          * Check whether the link seems not to be 8-bit clean.
101          */
102         if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
103             s = NULL;
104             switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
105             case SC_RCV_B7_0:
106                 s = "bit 7 set to 1";
107                 break;
108             case SC_RCV_B7_1:
109                 s = "bit 7 set to 0";
110                 break;
111             case SC_RCV_EVNP:
112                 s = "odd parity";
113                 break;
114             case SC_RCV_ODDP:
115                 s = "even parity";
116                 break;
117             }
118             if (s != NULL) {
119                 syslog(LOG_WARNING, "Serial link is not 8-bit clean:");
120                 syslog(LOG_WARNING, "All received characters had %s", s);
121             }
122         }
123         if (ioctl(fd, TIOCSETD, &initdisc) < 0)
124             syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
125     }
126 }
127
128
129 /*
130  * output - Output PPP packet.
131  */
132 void
133 output(unit, p, len)
134     int unit;
135     u_char *p;
136     int len;
137 {
138     if (unit != 0)
139         MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
140     if (debug)
141         log_packet(p, len, "sent ");
142
143     if (write(fd, p, len) < 0) {
144         syslog(LOG_ERR, "write: %m");
145         die(1);
146     }
147 }
148
149
150 /*
151  * read_packet - get a PPP packet from the serial device.
152  */
153 int
154 read_packet(buf)
155     u_char *buf;
156 {
157     int len;
158
159     if ((len = read(fd, buf, MTU + DLLHEADERLEN)) < 0) {
160         if (errno == EWOULDBLOCK) {
161             MAINDEBUG((LOG_DEBUG, "read(fd): EWOULDBLOCK"));
162             return -1;
163         }
164         syslog(LOG_ERR, "read(fd): %m");
165         die(1);
166     }
167     return len;
168 }
169
170
171 /*
172  * ppp_send_config - configure the transmit characteristics of
173  * the ppp interface.
174  */
175 void
176 ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
177     int unit, mtu;
178     u_long asyncmap;
179     int pcomp, accomp;
180 {
181     u_int x;
182     struct ifreq ifr;
183
184     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
185     ifr.ifr_mtu = mtu;
186     if (ioctl(s, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
187         syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
188         quit();
189     }
190
191     if (ioctl(fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0) {
192         syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %m");
193         quit();
194     }
195
196     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
197         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
198         quit();
199     }
200     x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
201     x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
202     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
203         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
204         quit();
205     }
206 }
207
208
209 /*
210  * ppp_set_xaccm - set the extended transmit ACCM for the interface.
211  */
212 void
213 ppp_set_xaccm(unit, accm)
214     int unit;
215     ext_accm accm;
216 {
217     if (ioctl(fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY)
218         syslog(LOG_WARNING, "ioctl(set extended ACCM): %m");
219 }
220
221
222 /*
223  * ppp_recv_config - configure the receive-side characteristics of
224  * the ppp interface.
225  */
226 void
227 ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
228     int unit, mru;
229     u_long asyncmap;
230     int pcomp, accomp;
231 {
232     int x;
233
234     if (ioctl(fd, PPPIOCSMRU, (caddr_t) &mru) < 0) {
235         syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m");
236         quit();
237     }
238     if (ioctl(fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0) {
239         syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %m");
240         quit();
241     }
242     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
243         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
244         quit();
245     }
246     x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
247     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
248         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
249         quit();
250     }
251 }
252
253 /*
254  * sifvjcomp - config tcp header compression
255  */
256 int
257 sifvjcomp(u, vjcomp, cidcomp, maxcid)
258     int u, vjcomp, cidcomp, maxcid;
259 {
260     u_int x;
261
262     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
263         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
264         return 0;
265     }
266     x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
267     x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
268     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
269         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
270         return 0;
271     }
272     if (ioctl(fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
273         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
274         return 0;
275     }
276     return 1;
277 }
278
279 /*
280  * sifup - Config the interface up and enable IP packets to pass.
281  */
282 int
283 sifup(u)
284 {
285     struct ifreq ifr;
286     u_int x;
287
288     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
289     if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
290         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
291         return 0;
292     }
293     ifr.ifr_flags |= IFF_UP;
294     if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
295         syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
296         return 0;
297     }
298     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
299         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
300         return 0;
301     }
302     x |= SC_ENABLE_IP;
303     if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
304         syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
305         return 0;
306     }
307     return 1;
308 }
309
310 /*
311  * sifdown - Config the interface down and disable IP.
312  */
313 int
314 sifdown(u)
315 {
316     struct ifreq ifr;
317     u_int x;
318     int rv;
319
320     rv = 1;
321     if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
322         syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %m");
323         rv = 0;
324     } else {
325         x &= ~SC_ENABLE_IP;
326         if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
327             syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
328             rv = 0;
329         }
330     }
331     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
332     if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
333         syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
334         rv = 0;
335     } else {
336         ifr.ifr_flags &= ~IFF_UP;
337         if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
338             syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
339             rv = 0;
340         }
341     }
342     return rv;
343 }
344
345 /*
346  * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
347  * if it exists.
348  */
349 #define SET_SA_FAMILY(addr, family)             \
350     BZERO((char *) &(addr), sizeof(addr));      \
351     addr.sa_family = (family); 
352
353 /*
354  * sifaddr - Config the interface IP addresses and netmask.
355  */
356 int
357 sifaddr(u, o, h, m)
358 {
359     int ret;
360     struct ifreq ifr;
361
362     ret = 1;
363     strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
364     SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
365     ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o;
366     if (ioctl(s, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
367         syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m");
368         ret = 0;
369     }
370     ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h;
371     if (ioctl(s, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
372         syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m");
373         ret = 0;
374     }
375     if (m != 0) {
376         ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m;
377         syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m));
378         if (ioctl(s, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
379             syslog(LOG_ERR, "ioctl(SIOCSIFNETMASK): %m");
380             ret = 0;
381         }
382     }
383     return ret;
384 }
385
386 /*
387  * cifaddr - Clear the interface IP addresses, and delete routes
388  * through the interface if possible.
389  */
390 int
391 cifaddr(u, o, h)
392 {
393     struct rtentry rt;
394
395     SET_SA_FAMILY(rt.rt_dst, AF_INET);
396     ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h;
397     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
398     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o;
399     rt.rt_flags = RTF_HOST;
400     if (ioctl(s, SIOCDELRT, (caddr_t) &rt) < 0) {
401         syslog(LOG_ERR, "ioctl(SIOCDELRT): %m");
402         return 0;
403     }
404     return 1;
405 }
406
407 /*
408  * sifdefaultroute - assign a default route through the address given.
409  */
410 int
411 sifdefaultroute(u, g)
412 {
413     struct rtentry rt;
414
415     SET_SA_FAMILY(rt.rt_dst, AF_INET);
416     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
417     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
418     rt.rt_flags = RTF_GATEWAY;
419     if (ioctl(s, SIOCADDRT, &rt) < 0) {
420         syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m");
421         return 0;
422     }
423     return 1;
424 }
425
426 /*
427  * cifdefaultroute - delete a default route through the address given.
428  */
429 int
430 cifdefaultroute(u, g)
431 {
432     struct rtentry rt;
433
434     SET_SA_FAMILY(rt.rt_dst, AF_INET);
435     SET_SA_FAMILY(rt.rt_gateway, AF_INET);
436     ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
437     rt.rt_flags = RTF_GATEWAY;
438     if (ioctl(s, SIOCDELRT, &rt) < 0)
439         syslog(LOG_WARNING, "default route ioctl(SIOCDELRT): %m");
440 }
441
442 /*
443  * sifproxyarp - Make a proxy ARP entry for the peer.
444  */
445 int
446 sifproxyarp(unit, hisaddr)
447     int unit;
448     u_long hisaddr;
449 {
450     struct arpreq arpreq;
451
452     BZERO(&arpreq, sizeof(arpreq));
453
454     /*
455      * Get the hardware address of an interface on the same subnet
456      * as our local address.
457      */
458     if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
459         syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
460         return 0;
461     }
462
463     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
464     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
465     arpreq.arp_flags = ATF_PERM | ATF_PUBL;
466     if (ioctl(s, SIOCSARP, (caddr_t)&arpreq) < 0) {
467         syslog(LOG_ERR, "ioctl(SIOCSARP): %m");
468         return 0;
469     }
470
471     return 1;
472 }
473
474 /*
475  * cifproxyarp - Delete the proxy ARP entry for the peer.
476  */
477 int
478 cifproxyarp(unit, hisaddr)
479     int unit;
480     u_long hisaddr;
481 {
482     struct arpreq arpreq;
483
484     BZERO(&arpreq, sizeof(arpreq));
485     SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
486     ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
487     if (ioctl(s, SIOCDARP, (caddr_t)&arpreq) < 0) {
488         syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
489         return 0;
490     }
491     return 1;
492 }
493
494 /*
495  * get_ether_addr - get the hardware address of an interface on the
496  * the same subnet as ipaddr.
497  */
498 #define MAX_IFS         32
499
500 int
501 get_ether_addr(ipaddr, hwaddr)
502     u_long ipaddr;
503     struct sockaddr *hwaddr;
504 {
505     struct ifreq *ifr, *ifend, *ifp;
506     u_long ina, mask;
507     struct sockaddr_dl *dla;
508     struct ifreq ifreq;
509     struct ifconf ifc;
510     struct ifreq ifs[MAX_IFS];
511
512     ifc.ifc_len = sizeof(ifs);
513     ifc.ifc_req = ifs;
514     if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
515         syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
516         return 0;
517     }
518
519     /*
520      * Scan through looking for an interface with an Internet
521      * address on the same subnet as `ipaddr'.
522      */
523     ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
524     for (ifr = ifc.ifc_req; ifr < ifend; ) {
525         if (ifr->ifr_addr.sa_family == AF_INET) {
526             ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
527             strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
528             /*
529              * Check that the interface is up, and not point-to-point
530              * or loopback.
531              */
532             if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
533                 continue;
534             if ((ifreq.ifr_flags &
535                  (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
536                  != (IFF_UP|IFF_BROADCAST))
537                 continue;
538             /*
539              * Get its netmask and check that it's on the right subnet.
540              */
541             if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0)
542                 continue;
543             mask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
544             if ((ipaddr & mask) != (ina & mask))
545                 continue;
546
547             break;
548         }
549         ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + sizeof(struct sockaddr)
550 );
551     }
552
553     if (ifr >= ifend)
554         return 0;
555     syslog(LOG_DEBUG, "found interface %s for proxy arp", ifr->ifr_name);
556
557     /*
558      * Now scan through again looking for a link-level address
559      * for this interface.
560      */
561     ifp = ifr;
562     for (ifr = ifc.ifc_req; ifr < ifend; ) {
563         if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
564             && ifr->ifr_addr.sa_family == AF_DLI) {
565 /*          && ifr->ifr_addr.sa_family == AF_LINK) { Per! Kolla !!! ROHACK */
566             /*
567              * Found the link-level address - copy it out
568              */
569             dla = (struct sockaddr_dl *)&ifr->ifr_addr;
570             hwaddr->sa_family = AF_UNSPEC;
571             BCOPY(dla, hwaddr->sa_data, sizeof(hwaddr->sa_data));
572             return 1;
573         }
574         ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + sizeof(struct sockaddr)
575 );
576     }
577
578     return 0;
579 }
580
581
582 /*
583  * ppp_available - check whether the system has any ppp interfaces
584  * (in fact we check whether we can do an ioctl on ppp0).
585  */
586
587 int
588 ppp_available()
589 {
590     int s, ok;
591     struct ifreq ifr;
592
593     if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
594         return 1;               /* can't tell - maybe we're not root */
595
596     strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
597     ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
598     close(s);
599
600     return ok;
601 }
602
603
604 /*
605   Seems like strdup() is not part of string package in Ultrix.
606   If I understood the man-page on the sun this should work.
607
608   Robert Olsson
609 */
610
611 char *strdup( in ) char *in;
612 {
613   char* dup;
614   if(! (dup = (char *) malloc( strlen( in ) +1 ))) return NULL;
615   (void) strcpy( dup, in );
616   return dup;
617 }