X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fipcp.c;h=2566fc82e0ddc1663bbc300a15c94bae16969399;hp=08befff160c13c809de89ff479719d7d550ce486;hb=dee72905271845128ad26cff5cf770c433f3f4a7;hpb=0b63a24d54ba4708c88e31bdd74b0145956c1478 diff --git a/pppd/ipcp.c b/pppd/ipcp.c index 08befff..2566fc8 100644 --- a/pppd/ipcp.c +++ b/pppd/ipcp.c @@ -18,59 +18,49 @@ */ #ifndef lint -static char rcsid[] = "$Id: ipcp.c,v 1.1 1993/11/11 03:54:25 paulus Exp $"; +static char rcsid[] = "$Id: ipcp.c,v 1.21 1995/08/17 11:57:12 paulus Exp $"; #endif /* * TODO: - * Fix IP address negotiation (wantoptions or hisoptions). - * Don't set zero IP addresses. */ #include +#include #include -#include #include #include -#include - -#include -#include -#include #include -#include - #include "pppd.h" -#include "ppp.h" #include "fsm.h" #include "ipcp.h" - +#include "pathnames.h" /* global vars */ -ipcp_options ipcp_wantoptions[NPPP]; /* Options that we want to request */ -ipcp_options ipcp_gotoptions[NPPP]; /* Options that peer ack'd */ -ipcp_options ipcp_allowoptions[NPPP]; /* Options we allow peer to request */ -ipcp_options ipcp_hisoptions[NPPP]; /* Options that we ack'd */ +ipcp_options ipcp_wantoptions[NUM_PPP]; /* Options that we want to request */ +ipcp_options ipcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ +ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ +ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */ /* local vars */ -static int cis_received[NPPP]; /* # Conf-Reqs received */ +static int cis_received[NUM_PPP]; /* # Conf-Reqs received */ /* * Callbacks for fsm code. (CI = Configuration Information) */ -static void ipcp_resetci __ARGS((fsm *)); /* Reset our CI */ -static int ipcp_cilen __ARGS((fsm *)); /* Return length of our CI */ -static void ipcp_addci __ARGS((fsm *, u_char *, int *)); /* Add our CI */ -static int ipcp_ackci __ARGS((fsm *, u_char *, int)); /* Peer ack'd our CI */ -static int ipcp_nakci __ARGS((fsm *, u_char *, int)); /* Peer nak'd our CI */ -static int ipcp_rejci __ARGS((fsm *, u_char *, int)); /* Peer rej'd our CI */ -static int ipcp_reqci __ARGS((fsm *, u_char *, int *, int)); /* Rcv CI */ -static void ipcp_up __ARGS((fsm *)); /* We're UP */ -static void ipcp_down __ARGS((fsm *)); /* We're DOWN */ - - -fsm ipcp_fsm[NPPP]; /* IPCP fsm structure */ +static void ipcp_resetci __P((fsm *)); /* Reset our CI */ +static int ipcp_cilen __P((fsm *)); /* Return length of our CI */ +static void ipcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */ +static int ipcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */ +static int ipcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */ +static int ipcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */ +static int ipcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */ +static void ipcp_up __P((fsm *)); /* We're UP */ +static void ipcp_down __P((fsm *)); /* We're DOWN */ +static void ipcp_script __P((fsm *, char *)); /* Run an up/down script */ + +fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */ static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ ipcp_resetci, /* Reset our Configuration Information */ @@ -109,7 +99,7 @@ static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ */ char * ip_ntoa(ipaddr) -u_long ipaddr; +u_int32_t ipaddr; { static char b[64]; @@ -136,7 +126,7 @@ ipcp_init(unit) ipcp_options *ao = &ipcp_allowoptions[unit]; f->unit = unit; - f->protocol = IPCP; + f->protocol = PPP_IPCP; f->callbacks = &ipcp_callbacks; fsm_init(&ipcp_fsm[unit]); @@ -159,6 +149,13 @@ ipcp_init(unit) ao->neg_vj = 1; ao->maxslotindex = MAX_STATES - 1; ao->cflag = 1; + + /* + * XXX These control whether the user may use the proxyarp + * and defaultroute options. + */ + ao->proxy_arp = 1; + ao->default_route = 1; } @@ -242,6 +239,10 @@ ipcp_resetci(f) ipcp_options *wo = &ipcp_wantoptions[f->unit]; wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr; + if (wo->ouraddr == 0) + wo->accept_local = 1; + if (wo->hisaddr == 0) + wo->accept_remote = 1; ipcp_gotoptions[f->unit] = *wo; cis_received[f->unit] = 0; } @@ -298,7 +299,7 @@ ipcp_addci(f, ucp, lenp) if (neg) { \ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \ if (len >= addrlen) { \ - u_long l; \ + u_int32_t l; \ PUTCHAR(opt, ucp); \ PUTCHAR(addrlen, ucp); \ l = ntohl(val1); \ @@ -361,7 +362,7 @@ ipcp_ackci(f, p, len) { ipcp_options *go = &ipcp_gotoptions[f->unit]; u_short cilen, citype, cishort; - u_long cilong; + u_int32_t cilong; u_char cimaxslotindex, cicflag; /* @@ -396,7 +397,7 @@ ipcp_ackci(f, p, len) #define ACKCIADDR(opt, neg, old, val1, val2) \ if (neg) { \ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \ - u_long l; \ + u_int32_t l; \ if ((len -= addrlen) < 0) \ goto bad; \ GETCHAR(citype, p); \ @@ -453,7 +454,7 @@ ipcp_nakci(f, p, len) u_char cimaxslotindex, cicflag; u_char citype, cilen, *next; u_short cishort; - u_long ciaddr1, ciaddr2, l; + u_int32_t ciaddr1, ciaddr2, l; ipcp_options no; /* options we've seen Naks for */ ipcp_options try; /* options to request next time */ @@ -492,26 +493,22 @@ ipcp_nakci(f, p, len) len -= cilen; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ - if (cilen == CILEN_VJ) { \ - GETCHAR(cimaxslotindex, p); \ - GETCHAR(cicflag, p); \ - } \ no.neg = 1; \ code \ } /* - * Accept the peer's idea of our address if we don't know it. - * Accept the peer's idea of his address if he knows it. + * Accept the peer's idea of {our,his} address, if different + * from our idea, only if the accept_{local,remote} flag is set. */ - NAKCIADDR(CI_ADDR, neg_addr, go->old_addrs, - if (!go->ouraddr && ciaddr1) { /* Do we know our address? */ - go->ouraddr = ciaddr1; + NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs, + if (go->accept_local && ciaddr1) { /* Do we know our address? */ + try.ouraddr = ciaddr1; IPCPDEBUG((LOG_INFO, "local IP address %s", ip_ntoa(ciaddr1))); } - if (ciaddr2) { /* Does he know his? */ - go->hisaddr = ciaddr2; + if (go->accept_remote && ciaddr2) { /* Does he know his? */ + try.hisaddr = ciaddr2; IPCPDEBUG((LOG_INFO, "remote IP address %s", ip_ntoa(ciaddr2))); } @@ -525,6 +522,8 @@ ipcp_nakci(f, p, len) */ NAKCIVJ(CI_COMPRESSTYPE, neg_vj, if (cilen == CILEN_VJ) { + GETCHAR(cimaxslotindex, p); + GETCHAR(cicflag, p); if (cishort == IPCP_VJ_COMP) { try.old_vj = 0; if (cimaxslotindex < go->maxslotindex) @@ -572,27 +571,26 @@ ipcp_nakci(f, p, len) try.old_addrs = 1; GETLONG(l, p); ciaddr1 = htonl(l); - if (ciaddr1) + if (ciaddr1 && go->accept_local) try.ouraddr = ciaddr1; GETLONG(l, p); ciaddr2 = htonl(l); - if (ciaddr2) + if (ciaddr2 && go->accept_remote) try.hisaddr = ciaddr2; no.old_addrs = 1; break; case CI_ADDR: if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR) goto bad; - try.neg_addr = 1; try.old_addrs = 0; GETLONG(l, p); ciaddr1 = htonl(l); - if (ciaddr1) + if (ciaddr1 && go->accept_local) try.ouraddr = ciaddr1; + if (try.ouraddr != 0) + try.neg_addr = 1; no.neg_addr = 1; break; - default: - goto bad; } p = next; } @@ -627,7 +625,7 @@ ipcp_rejci(f, p, len) ipcp_options *go = &ipcp_gotoptions[f->unit]; u_char cimaxslotindex, ciflag, cilen; u_short cishort; - u_long cilong; + u_int32_t cilong; ipcp_options try; /* options to request next time */ try = *go; @@ -641,7 +639,7 @@ ipcp_rejci(f, p, len) len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \ p[1] == cilen && \ p[0] == opt) { \ - u_long l; \ + u_int32_t l; \ len -= cilen; \ INCPTR(2, p); \ GETLONG(l, p); \ @@ -726,7 +724,7 @@ ipcp_reqci(f, inp, len, reject_if_disagree) u_char *cip, *next; /* Pointer to current and next CIs */ u_short cilen, citype; /* Parsed len, type */ u_short cishort; /* Parsed short value */ - u_long tl, ciaddr1, ciaddr2;/* Parsed address values */ + u_int32_t tl, ciaddr1, ciaddr2;/* Parsed address values */ int rc = CONFACK; /* Final packet return code */ int orc; /* Individual option return code */ u_char *p; /* Pointer to next char to parse */ @@ -778,13 +776,21 @@ ipcp_reqci(f, inp, len, reject_if_disagree) GETLONG(tl, p); /* Parse source address (his) */ ciaddr1 = htonl(tl); IPCPDEBUG((LOG_INFO, "(%s:", ip_ntoa(ciaddr1))); - if (wo->hisaddr && ciaddr1 != wo->hisaddr) { + if (ciaddr1 != wo->hisaddr + && (ciaddr1 == 0 || !wo->accept_remote)) { orc = CONFNAK; if (!reject_if_disagree) { - DECPTR(sizeof (long), p); + DECPTR(sizeof(u_int32_t), p); tl = ntohl(wo->hisaddr); PUTLONG(tl, p); } + } else if (ciaddr1 == 0 && wo->hisaddr == 0) { + /* + * If neither we nor he knows his address, reject the option. + */ + orc = CONFREJ; + wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ + break; } /* @@ -794,16 +800,18 @@ ipcp_reqci(f, inp, len, reject_if_disagree) GETLONG(tl, p); /* Parse desination address (ours) */ ciaddr2 = htonl(tl); IPCPDEBUG((LOG_INFO, "%s)", ip_ntoa(ciaddr2))); - if (wo->ouraddr && ciaddr2 != wo->ouraddr) { - orc = CONFNAK; - if (!reject_if_disagree) { - DECPTR(sizeof (long), p); - tl = ntohl(wo->ouraddr); - PUTLONG(tl, p); + if (ciaddr2 != wo->ouraddr) { + if (ciaddr2 == 0 || !wo->accept_local) { + orc = CONFNAK; + if (!reject_if_disagree) { + DECPTR(sizeof(u_int32_t), p); + tl = ntohl(wo->ouraddr); + PUTLONG(tl, p); + } + } else { + go->ouraddr = ciaddr2; /* accept peer's idea */ } } - if (orc == CONFNAK) - break; ho->neg_addr = 1; ho->old_addrs = 1; @@ -829,18 +837,23 @@ ipcp_reqci(f, inp, len, reject_if_disagree) GETLONG(tl, p); /* Parse source address (his) */ ciaddr1 = htonl(tl); IPCPDEBUG((LOG_INFO, "(%s)", ip_ntoa(ciaddr1))); - if (wo->hisaddr && ciaddr1 != wo->hisaddr) { + if (ciaddr1 != wo->hisaddr + && (ciaddr1 == 0 || !wo->accept_remote)) { orc = CONFNAK; if (!reject_if_disagree) { - DECPTR(sizeof (long), p); + DECPTR(sizeof(u_int32_t), p); tl = ntohl(wo->hisaddr); PUTLONG(tl, p); } + } else if (ciaddr1 == 0 && wo->hisaddr == 0) { + /* + * Don't ACK an address of 0.0.0.0 - reject it instead. + */ + orc = CONFREJ; + wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ + break; } - if (orc == CONFNAK) - break; - ho->neg_addr = 1; ho->hisaddr = ciaddr1; break; @@ -880,10 +893,12 @@ ipcp_reqci(f, inp, len, reject_if_disagree) PUTCHAR(wo->cflag, p); } } - if (orc == CONFNAK) - break; ho->maxslotindex = maxslotindex; - ho->cflag = wo->cflag; + ho->cflag = cflag; + } else { + ho->old_vj = 1; + ho->maxslotindex = MAX_STATES - 1; + ho->cflag = 1; } break; @@ -961,7 +976,7 @@ static void ipcp_up(f) fsm *f; { - u_long mask; + u_int32_t mask; ipcp_options *ho = &ipcp_hisoptions[f->unit]; ipcp_options *go = &ipcp_gotoptions[f->unit]; @@ -972,7 +987,7 @@ ipcp_up(f) /* * We must have a non-zero IP address for both ends of the link. */ - if (ho->hisaddr == 0) + if (!ho->neg_addr) ho->hisaddr = ipcp_wantoptions[f->unit].hisaddr; if (ho->hisaddr == 0) { @@ -987,7 +1002,7 @@ ipcp_up(f) } /* - * Check that the peer is allowed to use the IP address he wants. + * Check that the peer is allowed to use the IP address it wants. */ if (!auth_ip_addr(f->unit, ho->hisaddr)) { syslog(LOG_ERR, "Peer is not authorized to use remote address %s", @@ -1010,7 +1025,7 @@ ipcp_up(f) } /* set tcp compression */ - sifvjcomp(f->unit, ho->neg_vj, ho->cflag); + sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex); /* bring the interface up for IP */ if (!sifup(f->unit)) { @@ -1028,6 +1043,13 @@ ipcp_up(f) if (ipcp_wantoptions[f->unit].proxy_arp) if (sifproxyarp(f->unit, ho->hisaddr)) go->proxy_arp = 1; + + /* + * Execute the ip-up script, like this: + * /etc/ppp/ip-up interface tty speed local-IP remote-IP + */ + ipcp_script(f, _PATH_IPUP); + } @@ -1041,7 +1063,7 @@ static void ipcp_down(f) fsm *f; { - u_long ouraddr, hisaddr; + u_int32_t ouraddr, hisaddr; IPCPDEBUG((LOG_INFO, "ipcp: down")); @@ -1053,4 +1075,139 @@ ipcp_down(f) cifdefaultroute(f->unit, hisaddr); sifdown(f->unit); cifaddr(f->unit, ouraddr, hisaddr); + + /* Execute the ip-down script */ + ipcp_script(f, _PATH_IPDOWN); +} + + +/* + * ipcp_script - Execute a script with arguments + * interface-name tty-name speed local-IP remote-IP. + */ +static void +ipcp_script(f, script) + fsm *f; + char *script; +{ + char strspeed[32], strlocal[32], strremote[32]; + char *argv[8]; + + sprintf(strspeed, "%d", baud_rate); + strcpy(strlocal, ip_ntoa(ipcp_gotoptions[f->unit].ouraddr)); + strcpy(strremote, ip_ntoa(ipcp_hisoptions[f->unit].hisaddr)); + + argv[0] = script; + argv[1] = ifname; + argv[2] = devnam; + argv[3] = strspeed; + argv[4] = strlocal; + argv[5] = strremote; + argv[6] = ipparam; + argv[7] = NULL; + run_program(script, argv, 0); +} + +/* + * ipcp_printpkt - print the contents of an IPCP packet. + */ +char *ipcp_codenames[] = { + "ConfReq", "ConfAck", "ConfNak", "ConfRej", + "TermReq", "TermAck", "CodeRej" +}; + +int +ipcp_printpkt(p, plen, printer, arg) + u_char *p; + int plen; + void (*printer)(); + void *arg; +{ + int code, id, len, olen; + u_char *pstart, *optend; + u_short cishort; + u_int32_t cilong; + + if (plen < HEADERLEN) + return 0; + pstart = p; + GETCHAR(code, p); + GETCHAR(id, p); + GETSHORT(len, p); + if (len < HEADERLEN || len > plen) + return 0; + + if (code >= 1 && code <= sizeof(ipcp_codenames) / sizeof(char *)) + printer(arg, " %s", ipcp_codenames[code-1]); + else + printer(arg, " code=0x%x", code); + printer(arg, " id=0x%x", id); + len -= HEADERLEN; + switch (code) { + case CONFREQ: + case CONFACK: + case CONFNAK: + case CONFREJ: + /* print option list */ + while (len >= 2) { + GETCHAR(code, p); + GETCHAR(olen, p); + p -= 2; + if (olen < 2 || olen > len) { + break; + } + printer(arg, " <"); + len -= olen; + optend = p + olen; + switch (code) { + case CI_ADDRS: + if (olen == CILEN_ADDRS) { + p += 2; + GETLONG(cilong, p); + printer(arg, "addrs %s", ip_ntoa(htonl(cilong))); + GETLONG(cilong, p); + printer(arg, " %s", ip_ntoa(htonl(cilong))); + } + break; + case CI_COMPRESSTYPE: + if (olen >= CILEN_COMPRESS) { + p += 2; + GETSHORT(cishort, p); + printer(arg, "compress "); + switch (cishort) { + case IPCP_VJ_COMP: + printer(arg, "VJ"); + break; + case IPCP_VJ_COMP_OLD: + printer(arg, "old-VJ"); + break; + default: + printer(arg, "0x%x", cishort); + } + } + break; + case CI_ADDR: + if (olen == CILEN_ADDR) { + p += 2; + GETLONG(cilong, p); + printer(arg, "addr %s", ip_ntoa(htonl(cilong))); + } + break; + } + while (p < optend) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + printer(arg, ">"); + } + break; + } + + /* print the rest of the bytes in the packet */ + for (; len > 0; --len) { + GETCHAR(code, p); + printer(arg, " %.2x", code); + } + + return p - pstart; }