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