diff options
author | brian <brian@FreeBSD.org> | 1998-05-21 21:49:08 +0000 |
---|---|---|
committer | brian <brian@FreeBSD.org> | 1998-05-21 21:49:08 +0000 |
commit | 56df88b778aee0e60678672b107a48a8ea05cb48 (patch) | |
tree | 13b88ca17b38e787c84b0cd242677b3c3c0b93c3 /usr.sbin/ppp/ipcp.c | |
parent | e077fa331b8a428923ded3a95d0b8d47084cf670 (diff) | |
download | FreeBSD-src-56df88b778aee0e60678672b107a48a8ea05cb48.zip FreeBSD-src-56df88b778aee0e60678672b107a48a8ea05cb48.tar.gz |
MFMP: Make ppp multilink capable.
See the file README.changes, and re-read the man page.
Diffstat (limited to 'usr.sbin/ppp/ipcp.c')
-rw-r--r-- | usr.sbin/ppp/ipcp.c | 1166 |
1 files changed, 786 insertions, 380 deletions
diff --git a/usr.sbin/ppp/ipcp.c b/usr.sbin/ppp/ipcp.c index 72c8eb1..015da50 100644 --- a/usr.sbin/ppp/ipcp.c +++ b/usr.sbin/ppp/ipcp.c @@ -17,7 +17,7 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: ipcp.c,v 1.49 1998/01/20 22:47:38 brian Exp $ + * $Id: ipcp.c,v 1.50.2.54 1998/05/21 01:26:08 brian Exp $ * * TODO: * o More RFC1772 backwoard compatibility @@ -29,10 +29,16 @@ #include <arpa/inet.h> #include <sys/socket.h> #include <netdb.h> +#include <net/if.h> +#include <sys/sockio.h> +#include <sys/un.h> -#include <stdio.h> +#include <fcntl.h> +#include <resolv.h> #include <stdlib.h> #include <string.h> +#include <sys/errno.h> +#include <termios.h> #include <unistd.h> #include "command.h" @@ -44,62 +50,61 @@ #include "lcpproto.h" #include "lcp.h" #include "iplist.h" -#include "ipcp.h" +#include "throughput.h" #include "slcompress.h" -#include "os.h" -#include "phase.h" +#include "ipcp.h" +#include "filter.h" +#include "descriptor.h" #include "loadalias.h" -#include "vars.h" #include "vjcomp.h" -#include "ip.h" -#include "throughput.h" +#include "lqr.h" +#include "hdlc.h" +#include "async.h" +#include "ccp.h" +#include "link.h" +#include "physical.h" +#include "mp.h" +#include "bundle.h" +#include "id.h" +#include "arp.h" +#include "systems.h" +#include "prompt.h" #include "route.h" -#include "filter.h" -#ifndef NOMSEXT -struct in_addr ns_entries[2]; -struct in_addr nbns_entries[2]; -#endif +#undef REJECTED +#define REJECTED(p, x) ((p)->peer_reject & (1<<(x))) +#define issep(ch) ((ch) == ' ' || (ch) == '\t') +#define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.') -struct ipcpstate IpcpInfo; -struct in_range DefMyAddress; -struct in_range DefHisAddress; -struct iplist DefHisChoice; -struct in_addr TriggerAddress; -int HaveTriggerAddress; +struct compreq { + u_short proto; + u_char slots; + u_char compcid; +}; -static void IpcpSendConfigReq(struct fsm *); -static void IpcpSendTerminateAck(struct fsm *); -static void IpcpSendTerminateReq(struct fsm *); -static void IpcpDecodeConfig(u_char *, int, int); +static int IpcpLayerUp(struct fsm *); +static void IpcpLayerDown(struct fsm *); static void IpcpLayerStart(struct fsm *); static void IpcpLayerFinish(struct fsm *); -static void IpcpLayerUp(struct fsm *); -static void IpcpLayerDown(struct fsm *); static void IpcpInitRestartCounter(struct fsm *); +static void IpcpSendConfigReq(struct fsm *); +static void IpcpSentTerminateReq(struct fsm *); +static void IpcpSendTerminateAck(struct fsm *, u_char); +static void IpcpDecodeConfig(struct fsm *, u_char *, int, int, + struct fsm_decode *); -struct fsm IpcpFsm = { - "IPCP", - PROTO_IPCP, - IPCP_MAXCODE, - 0, - ST_INITIAL, - 0, 0, 0, - - {0, 0, 0, NULL, NULL, NULL}, /* FSM timer */ - {0, 0, 0, NULL, NULL, NULL}, /* Open timer */ - {0, 0, 0, NULL, NULL, NULL}, /* Stopped timer */ - LogIPCP, - +static struct fsm_callbacks ipcp_Callbacks = { IpcpLayerUp, IpcpLayerDown, IpcpLayerStart, IpcpLayerFinish, IpcpInitRestartCounter, IpcpSendConfigReq, - IpcpSendTerminateReq, + IpcpSentTerminateReq, IpcpSendTerminateAck, IpcpDecodeConfig, + fsm_NullRecvResetReq, + fsm_NullRecvResetAck }; static const char *cftypes[] = { @@ -123,93 +128,200 @@ static const char *cftypes128[] = { #define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0]) -static struct pppThroughput throughput; - void -IpcpAddInOctets(int n) +ipcp_AddInOctets(struct ipcp *ipcp, int n) { - throughput_addin(&throughput, n); + throughput_addin(&ipcp->throughput, n); } void -IpcpAddOutOctets(int n) +ipcp_AddOutOctets(struct ipcp *ipcp, int n) { - throughput_addout(&throughput, n); + throughput_addout(&ipcp->throughput, n); } -int -ReportIpcpStatus(struct cmdargs const *arg) +static void +getdns(struct ipcp *ipcp, struct in_addr addr[2]) { - struct fsm *fp = &IpcpFsm; - - if (!VarTerm) - return 1; - fprintf(VarTerm, "%s [%s]\n", fp->name, StateNames[fp->state]); - if (IpcpFsm.state == ST_OPENED) { - fprintf(VarTerm, " his side: %s, %s\n", - inet_ntoa(IpcpInfo.his_ipaddr), vj2asc(IpcpInfo.his_compproto)); - fprintf(VarTerm, " my side: %s, %s\n", - inet_ntoa(IpcpInfo.want_ipaddr), vj2asc(IpcpInfo.want_compproto)); - } - - fprintf(VarTerm, "Defaults:\n"); - fprintf(VarTerm, " My Address: %s/%d\n", - inet_ntoa(DefMyAddress.ipaddr), DefMyAddress.width); - if (iplist_isvalid(&DefHisChoice)) - fprintf(VarTerm, " His Address: %s\n", DefHisChoice.src); - else - fprintf(VarTerm, " His Address: %s/%d\n", - inet_ntoa(DefHisAddress.ipaddr), DefHisAddress.width); - if (HaveTriggerAddress) - fprintf(VarTerm, " Negotiation(trigger): %s\n", inet_ntoa(TriggerAddress)); - else - fprintf(VarTerm, " Negotiation(trigger): MYADDR\n"); + FILE *fp; - fprintf(VarTerm, "\n"); - throughput_disp(&throughput, VarTerm); + addr[0].s_addr = addr[1].s_addr = INADDR_ANY; + if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { + char buf[LINE_LEN], *cp, *end; + int n; - return 0; + n = 0; + buf[sizeof buf - 1] = '\0'; + while (fgets(buf, sizeof buf - 1, fp)) { + if (!strncmp(buf, "nameserver", 10) && issep(buf[10])) { + for (cp = buf + 11; issep(*cp); cp++) + ; + for (end = cp; isip(*end); end++) + ; + *end = '\0'; + if (inet_aton(cp, addr+n) && ++n == 2) + break; + } + } + if (n == 1) + addr[1] = addr[0]; + fclose(fp); + } } -void -IpcpDefAddress() +static int +setdns(struct ipcp *ipcp, struct in_addr addr[2]) { - struct hostent *hp; - char name[200]; + FILE *fp; + char wbuf[LINE_LEN + 54]; + int wlen; - memset(&DefMyAddress, '\0', sizeof DefMyAddress); - memset(&DefHisAddress, '\0', sizeof DefHisAddress); - TriggerAddress.s_addr = 0; - HaveTriggerAddress = 0; - if (gethostname(name, sizeof name) == 0) { - hp = gethostbyname(name); - if (hp && hp->h_addrtype == AF_INET) { - memcpy(&DefMyAddress.ipaddr.s_addr, hp->h_addr, hp->h_length); + if (addr[0].s_addr == INADDR_ANY || addr[1].s_addr == INADDR_ANY) { + struct in_addr old[2]; + + getdns(ipcp, old); + if (addr[0].s_addr == INADDR_ANY) + addr[0] = old[0]; + if (addr[1].s_addr == INADDR_ANY) + addr[1] = old[1]; + } + + if (addr[0].s_addr == INADDR_ANY && addr[1].s_addr == INADDR_ANY) { + log_Printf(LogWARN, "%s not modified: All nameservers NAKd\n", + _PATH_RESCONF); + return 0; + } + + wlen = 0; + if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { + char buf[LINE_LEN]; + int len; + + buf[sizeof buf - 1] = '\0'; + while (fgets(buf, sizeof buf - 1, fp)) { + if (strncmp(buf, "nameserver", 10) || !issep(buf[10])) { + len = strlen(buf); + if (len > sizeof wbuf - wlen) { + log_Printf(LogWARN, "%s: Can only cope with max file size %d\n", + _PATH_RESCONF, LINE_LEN); + fclose(fp); + return 0; + } + memcpy(wbuf + wlen, buf, len); + wlen += len; + } + } + fclose(fp); + } + + if (addr[0].s_addr != INADDR_ANY) { + snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n", + inet_ntoa(addr[0])); + log_Printf(LogIPCP, "Primary nameserver set to %s", wbuf + wlen + 11); + wlen += strlen(wbuf + wlen); + } + + if (addr[1].s_addr != INADDR_ANY && addr[1].s_addr != addr[0].s_addr) { + snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n", + inet_ntoa(addr[1])); + log_Printf(LogIPCP, "Secondary nameserver set to %s", wbuf + wlen + 11); + wlen += strlen(wbuf + wlen); + } + + if (wlen) { + int fd; + + if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_CREAT, 0644)) != -1) { + if (write(fd, wbuf, wlen) != wlen) { + log_Printf(LogERROR, "setdns: write(): %s\n", strerror(errno)); + close(fd); + return 0; + } + if (ftruncate(fd, wlen) == -1) { + log_Printf(LogERROR, "setdns: truncate(): %s\n", strerror(errno)); + close(fd); + return 0; + } + close(fd); + } else { + log_Printf(LogERROR, "setdns: open(): %s\n", strerror(errno)); + return 0; } } + + return 1; } -static int VJInitSlots = MAX_STATES; -static int VJInitComp = 1; +int +ipcp_Show(struct cmdargs const *arg) +{ + struct ipcp *ipcp = &arg->bundle->ncp.ipcp; + + prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name, + State2Nam(ipcp->fsm.state)); + if (ipcp->fsm.state == ST_OPENED) { + prompt_Printf(arg->prompt, " His side: %s, %s\n", + inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto)); + prompt_Printf(arg->prompt, " My side: %s, %s\n", + inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto)); + } + + if (ipcp->route) { + prompt_Printf(arg->prompt, "\n"); + route_ShowSticky(arg->prompt, ipcp->route); + } + + prompt_Printf(arg->prompt, "\nDefaults:\n"); + prompt_Printf(arg->prompt, " My Address: %s/%d", + inet_ntoa(ipcp->cfg.my_range.ipaddr), ipcp->cfg.my_range.width); + + if (ipcp->cfg.HaveTriggerAddress) + prompt_Printf(arg->prompt, " (trigger with %s)", + inet_ntoa(ipcp->cfg.TriggerAddress)); + prompt_Printf(arg->prompt, "\n VJ compression: %s (%d slots %s slot " + "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg), + ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without"); + + if (iplist_isvalid(&ipcp->cfg.peer_list)) + prompt_Printf(arg->prompt, " His Address: %s\n", + ipcp->cfg.peer_list.src); + else + prompt_Printf(arg->prompt, " His Address: %s/%d\n", + inet_ntoa(ipcp->cfg.peer_range.ipaddr), + ipcp->cfg.peer_range.width); + + prompt_Printf(arg->prompt, " DNS: %s, ", + inet_ntoa(ipcp->cfg.ns.dns[0])); + prompt_Printf(arg->prompt, "%s, %s\n", inet_ntoa(ipcp->cfg.ns.dns[1]), + command_ShowNegval(ipcp->cfg.ns.dns_neg)); + prompt_Printf(arg->prompt, " NetBIOS NS: %s, ", + inet_ntoa(ipcp->cfg.ns.nbns[0])); + prompt_Printf(arg->prompt, "%s\n", inet_ntoa(ipcp->cfg.ns.nbns[1])); + + prompt_Printf(arg->prompt, "\n"); + throughput_disp(&ipcp->throughput, arg->prompt); + + return 0; +} int -SetInitVJ(struct cmdargs const *args) +ipcp_vjset(struct cmdargs const *arg) { - if (args->argc != 2) + if (arg->argc != arg->argn+2) return -1; - if (!strcasecmp(args->argv[0], "slots")) { + if (!strcasecmp(arg->argv[arg->argn], "slots")) { int slots; - slots = atoi(args->argv[1]); + slots = atoi(arg->argv[arg->argn+1]); if (slots < 4 || slots > 16) return 1; - VJInitSlots = slots; + arg->bundle->ncp.ipcp.cfg.vj.slots = slots; return 0; - } else if (!strcasecmp(args->argv[0], "slotcomp")) { - if (!strcasecmp(args->argv[1], "on")) - VJInitComp = 1; - else if (!strcasecmp(args->argv[1], "off")) - VJInitComp = 0; + } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) { + if (!strcasecmp(arg->argv[arg->argn+1], "on")) + arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1; + else if (!strcasecmp(arg->argv[arg->argn+1], "off")) + arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0; else return 2; return 0; @@ -217,199 +329,453 @@ SetInitVJ(struct cmdargs const *args) return -1; } -int -ShowInitVJ(struct cmdargs const *args) +void +ipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l, + const struct fsm_parent *parent) { - if (VarTerm) { - fprintf(VarTerm, "Initial slots: %d\n", VJInitSlots); - fprintf(VarTerm, "Initial compression: %s\n", VJInitComp ? "on" : "off"); + struct hostent *hp; + char name[MAXHOSTNAMELEN]; + static const char *timer_names[] = + {"IPCP restart", "IPCP openmode", "IPCP stopped"}; + + fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, 10, LogIPCP, + bundle, l, parent, &ipcp_Callbacks, timer_names); + + ipcp->route = NULL; + ipcp->cfg.vj.slots = DEF_VJ_STATES; + ipcp->cfg.vj.slotcomp = 1; + memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range); + if (gethostname(name, sizeof name) == 0) { + hp = gethostbyname(name); + if (hp && hp->h_addrtype == AF_INET) { + memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length); + ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; + ipcp->cfg.peer_range.width = 32; + } } - return 0; + ipcp->cfg.netmask.s_addr = INADDR_ANY; + memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); + iplist_setsrc(&ipcp->cfg.peer_list, ""); + ipcp->cfg.HaveTriggerAddress = 0; + + ipcp->cfg.ns.dns[0].s_addr = INADDR_ANY; + ipcp->cfg.ns.dns[1].s_addr = INADDR_ANY; + ipcp->cfg.ns.dns_neg = 0; + ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY; + ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY; + + ipcp->cfg.fsmretry = DEF_FSMRETRY; + ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED; + + memset(&ipcp->vj, '\0', sizeof ipcp->vj); + + ipcp->my_ifip.s_addr = INADDR_ANY; + ipcp->peer_ifip.s_addr = INADDR_ANY; + + throughput_init(&ipcp->throughput); + ipcp_Setup(ipcp); } void -IpcpInit() +ipcp_SetLink(struct ipcp *ipcp, struct link *l) { - if (iplist_isvalid(&DefHisChoice)) - iplist_setrandpos(&DefHisChoice); - FsmInit(&IpcpFsm); - memset(&IpcpInfo, '\0', sizeof IpcpInfo); - if ((mode & MODE_DEDICATED) && !GetLabel()) { - IpcpInfo.want_ipaddr.s_addr = IpcpInfo.his_ipaddr.s_addr = 0; - } else { - IpcpInfo.want_ipaddr.s_addr = DefMyAddress.ipaddr.s_addr; - IpcpInfo.his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr; + ipcp->fsm.link = l; +} + +void +ipcp_Setup(struct ipcp *ipcp) +{ + int pos; + + ipcp->fsm.open_mode = 0; + ipcp->fsm.maxconfig = 10; + + if (iplist_isvalid(&ipcp->cfg.peer_list)) { + if (ipcp->my_ifip.s_addr != INADDR_ANY && + (pos = iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->my_ifip)) != -1) + ipcp->cfg.peer_range.ipaddr = iplist_setcurpos(&ipcp->cfg.peer_list, pos); + else + ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list); + ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; + ipcp->cfg.peer_range.width = 32; } - /* - * Some implementations of PPP require that we send a - * *special* value as our address, even though the rfc specifies - * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0"). - */ - if (HaveTriggerAddress) { - IpcpInfo.want_ipaddr.s_addr = TriggerAddress.s_addr; - LogPrintf(LogIPCP, "Using trigger address %s\n", inet_ntoa(TriggerAddress)); + ipcp->heis1172 = 0; + + ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr; + ipcp->peer_compproto = 0; + + if (ipcp->cfg.HaveTriggerAddress) { + /* + * Some implementations of PPP require that we send a + * *special* value as our address, even though the rfc specifies + * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0"). + */ + ipcp->my_ip = ipcp->cfg.TriggerAddress; + log_Printf(LogIPCP, "Using trigger address %s\n", + inet_ntoa(ipcp->cfg.TriggerAddress)); + } else if ((ipcp->my_ifip.s_addr & ipcp->cfg.my_range.mask.s_addr) == + (ipcp->cfg.my_range.ipaddr.s_addr & + ipcp->cfg.my_range.mask.s_addr)) + /* + * Otherwise, if we've been assigned an IP number before, we really + * want to keep the same IP number so that we can keep any existing + * connections that are bound to that IP. + */ + ipcp->my_ip = ipcp->my_ifip; + else + ipcp->my_ip = ipcp->cfg.my_range.ipaddr; + + if (IsEnabled(ipcp->cfg.vj.neg)) + ipcp->my_compproto = (PROTO_VJCOMP << 16) + + ((ipcp->cfg.vj.slots - 1) << 8) + + ipcp->cfg.vj.slotcomp; + else + ipcp->my_compproto = 0; + sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1); + + ipcp->peer_reject = 0; + ipcp->my_reject = 0; + + throughput_stop(&ipcp->throughput); + throughput_init(&ipcp->throughput); +} + +static int +ipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr, + struct in_addr hisaddr, int silent) +{ + struct sockaddr_in *sock_in; + int s; + u_long mask, addr; + struct ifaliasreq ifra; + + /* If given addresses are alreay set, then ignore this request */ + if (bundle->ncp.ipcp.my_ifip.s_addr == myaddr.s_addr && + bundle->ncp.ipcp.peer_ifip.s_addr == hisaddr.s_addr) + return 0; + + ipcp_CleanInterface(&bundle->ncp.ipcp); + + s = ID0socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + log_Printf(LogERROR, "SetIpDevice: socket(): %s\n", strerror(errno)); + return (-1); } - if (Enabled(ConfVjcomp)) - IpcpInfo.want_compproto = (PROTO_VJCOMP << 16) | ((VJInitSlots - 1) << 8) | - VJInitComp; + + memset(&ifra, '\0', sizeof ifra); + strncpy(ifra.ifra_name, bundle->ifp.Name, sizeof ifra.ifra_name - 1); + ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; + + /* Set interface address */ + sock_in = (struct sockaddr_in *)&ifra.ifra_addr; + sock_in->sin_family = AF_INET; + sock_in->sin_addr = myaddr; + sock_in->sin_len = sizeof *sock_in; + + /* Set destination address */ + sock_in = (struct sockaddr_in *)&ifra.ifra_broadaddr; + sock_in->sin_family = AF_INET; + sock_in->sin_addr = hisaddr; + sock_in->sin_len = sizeof *sock_in; + + addr = ntohl(myaddr.s_addr); + if (IN_CLASSA(addr)) + mask = IN_CLASSA_NET; + else if (IN_CLASSB(addr)) + mask = IN_CLASSB_NET; else - IpcpInfo.want_compproto = 0; - IpcpInfo.heis1172 = 0; - IpcpFsm.maxconfig = 10; - throughput_init(&throughput); + mask = IN_CLASSC_NET; + + /* if subnet mask is given, use it instead of class mask */ + if (bundle->ncp.ipcp.cfg.netmask.s_addr != INADDR_ANY && + (ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr) & mask) == mask) + mask = ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr); + + sock_in = (struct sockaddr_in *)&ifra.ifra_mask; + sock_in->sin_family = AF_INET; + sock_in->sin_addr.s_addr = htonl(mask); + sock_in->sin_len = sizeof *sock_in; + + if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) { + if (!silent) + log_Printf(LogERROR, "SetIpDevice: ioctl(SIOCAIFADDR): %s\n", + strerror(errno)); + close(s); + return (-1); + } + + if (Enabled(bundle, OPT_SROUTES)) + route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr); + + bundle->ncp.ipcp.peer_ifip.s_addr = hisaddr.s_addr; + bundle->ncp.ipcp.my_ifip.s_addr = myaddr.s_addr; + + if (Enabled(bundle, OPT_PROXY)) + arp_SetProxy(bundle, bundle->ncp.ipcp.peer_ifip, s); + + close(s); + return (0); +} + +static struct in_addr +ChooseHisAddr(struct bundle *bundle, const struct in_addr gw) +{ + struct in_addr try; + int f; + + for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) { + try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list); + log_Printf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n", + f, inet_ntoa(try)); + if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) { + log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try)); + break; + } + } + + if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) { + log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n"); + try.s_addr = INADDR_ANY; + } + + return try; } static void IpcpInitRestartCounter(struct fsm * fp) { - fp->FsmTimer.load = VarRetryTimeout * SECTICKS; + /* Set fsm timer load */ + struct ipcp *ipcp = fsm2ipcp(fp); + + fp->FsmTimer.load = ipcp->cfg.fsmretry * SECTICKS; fp->restart = 5; } static void -IpcpSendConfigReq(struct fsm * fp) +IpcpSendConfigReq(struct fsm *fp) { - u_char *cp; - struct lcp_opt o; - - cp = ReqBuff; - LogPrintf(LogIPCP, "IpcpSendConfigReq\n"); - if (!DEV_IS_SYNC || !REJECTED(&IpcpInfo, TY_IPADDR)) { - o.id = TY_IPADDR; - o.len = 6; - *(u_long *)o.data = IpcpInfo.want_ipaddr.s_addr; - cp += LcpPutConf(LogIPCP, cp, &o, cftypes[o.id], - inet_ntoa(IpcpInfo.want_ipaddr)); + /* Send config REQ please */ + struct physical *p = link2physical(fp->link); + struct ipcp *ipcp = fsm2ipcp(fp); + u_char buff[24]; + struct lcp_opt *o; + + o = (struct lcp_opt *)buff; + + if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) { + *(u_int32_t *)o->data = ipcp->my_ip.s_addr; + INC_LCP_OPT(TY_IPADDR, 6, o); } - if (IpcpInfo.want_compproto && !REJECTED(&IpcpInfo, TY_COMPPROTO)) { - const char *args; - o.id = TY_COMPPROTO; - if (IpcpInfo.heis1172) { - o.len = 4; - *(u_short *)o.data = htons(PROTO_VJCOMP); - args = ""; + if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) { + if (ipcp->heis1172) { + *(u_short *)o->data = htons(PROTO_VJCOMP); + INC_LCP_OPT(TY_COMPPROTO, 4, o); } else { - o.len = 6; - *(u_long *)o.data = htonl(IpcpInfo.want_compproto); - args = vj2asc(IpcpInfo.want_compproto); + *(u_long *)o->data = htonl(ipcp->my_compproto); + INC_LCP_OPT(TY_COMPPROTO, 6, o); } - cp += LcpPutConf(LogIPCP, cp, &o, cftypes[o.id], args); } - FsmOutput(fp, CODE_CONFIGREQ, fp->reqid++, ReqBuff, cp - ReqBuff); + + if (IsEnabled(ipcp->cfg.ns.dns_neg) && + !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) && + !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) { + struct in_addr dns[2]; + getdns(ipcp, dns); + *(u_int32_t *)o->data = dns[0].s_addr; + INC_LCP_OPT(TY_PRIMARY_DNS, 6, o); + *(u_int32_t *)o->data = dns[1].s_addr; + INC_LCP_OPT(TY_SECONDARY_DNS, 6, o); + } + + fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff); } static void -IpcpSendTerminateReq(struct fsm * fp) +IpcpSentTerminateReq(struct fsm * fp) { - /* XXX: No code yet */ + /* Term REQ just sent by FSM */ } static void -IpcpSendTerminateAck(struct fsm * fp) +IpcpSendTerminateAck(struct fsm *fp, u_char id) { - LogPrintf(LogIPCP, "IpcpSendTerminateAck\n"); - FsmOutput(fp, CODE_TERMACK, fp->reqid++, NULL, 0); + /* Send Term ACK please */ + fsm_Output(fp, CODE_TERMACK, id, NULL, 0); } static void IpcpLayerStart(struct fsm * fp) { - LogPrintf(LogIPCP, "IpcpLayerStart.\n"); + /* We're about to start up ! */ + log_Printf(LogIPCP, "%s: IpcpLayerStart.\n", fp->link->name); + + /* This is where we should be setting up the interface in DEMAND mode */ } static void -IpcpLayerFinish(struct fsm * fp) +IpcpLayerFinish(struct fsm *fp) { - LogPrintf(LogIPCP, "IpcpLayerFinish.\n"); - reconnect(RECON_FALSE); - LcpClose(); - NewPhase(PHASE_TERMINATE); + /* We're now down */ + log_Printf(LogIPCP, "%s: IpcpLayerFinish.\n", fp->link->name); } -static void -IpcpLayerDown(struct fsm * fp) +void +ipcp_CleanInterface(struct ipcp *ipcp) { - LogPrintf(LogIPCP, "IpcpLayerDown.\n"); - throughput_stop(&throughput); - throughput_log(&throughput, LogIPCP, NULL); + struct ifaliasreq ifra; + struct sockaddr_in *me, *peer; + int s; + + s = ID0socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) { + log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n", strerror(errno)); + return; + } + + route_Clean(ipcp->fsm.bundle, ipcp->route); + + if (Enabled(ipcp->fsm.bundle, OPT_PROXY)) + arp_ClearProxy(ipcp->fsm.bundle, ipcp->peer_ifip, s); + + if (ipcp->my_ifip.s_addr != INADDR_ANY || + ipcp->peer_ifip.s_addr != INADDR_ANY) { + memset(&ifra, '\0', sizeof ifra); + strncpy(ifra.ifra_name, ipcp->fsm.bundle->ifp.Name, + sizeof ifra.ifra_name - 1); + ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; + me = (struct sockaddr_in *)&ifra.ifra_addr; + peer = (struct sockaddr_in *)&ifra.ifra_broadaddr; + me->sin_family = peer->sin_family = AF_INET; + me->sin_len = peer->sin_len = sizeof(struct sockaddr_in); + me->sin_addr = ipcp->my_ifip; + peer->sin_addr = ipcp->peer_ifip; + if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) + log_Printf(LogERROR, "ipcp_CleanInterface: ioctl(SIOCDIFADDR): %s\n", + strerror(errno)); + ipcp->my_ifip.s_addr = ipcp->peer_ifip.s_addr = INADDR_ANY; + } + + close(s); } -/* - * Called when IPCP has reached to OPEN state - */ static void -IpcpLayerUp(struct fsm * fp) +IpcpLayerDown(struct fsm *fp) { - char tbuff[100]; + /* About to come down */ + struct ipcp *ipcp = fsm2ipcp(fp); + const char *s; - Prompt(); - LogPrintf(LogIPCP, "IpcpLayerUp(%d).\n", fp->state); - snprintf(tbuff, sizeof tbuff, "myaddr = %s ", - inet_ntoa(IpcpInfo.want_ipaddr)); + s = inet_ntoa(ipcp->peer_ifip); + log_Printf(LogIPCP, "%s: IpcpLayerDown: %s\n", fp->link->name, s); - if (IpcpInfo.his_compproto >> 16 == PROTO_VJCOMP) - VjInit((IpcpInfo.his_compproto >> 8) & 255); + throughput_stop(&ipcp->throughput); + throughput_log(&ipcp->throughput, LogIPCP, NULL); + /* + * XXX this stuff should really live in the FSM. Our config should + * associate executable sections in files with events. + */ + if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL) < 0) { + if (bundle_GetLabel(fp->bundle)) { + if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), + LINKDOWNFILE, NULL) < 0) + system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL); + } else + system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL); + } - LogPrintf(LogIsKept(LogIPCP) ? LogIPCP : LogLINK, " %s hisaddr = %s\n", - tbuff, inet_ntoa(IpcpInfo.his_ipaddr)); - if (OsSetIpaddress(IpcpInfo.want_ipaddr, IpcpInfo.his_ipaddr) < 0) { - if (VarTerm) - LogPrintf(LogERROR, "IpcpLayerUp: unable to set ip address\n"); - return; + if (!(ipcp->fsm.bundle->phys_type & PHYS_DEMAND)) + ipcp_CleanInterface(ipcp); +} + +int +ipcp_InterfaceUp(struct ipcp *ipcp) +{ + if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) { + log_Printf(LogERROR, "IpcpLayerUp: unable to set ip address\n"); + return 0; } + #ifndef NOALIAS - if (mode & MODE_ALIAS) - VarPacketAliasSetAddress(IpcpInfo.want_ipaddr); + if (alias_IsEnabled()) + (*PacketAlias.SetAddress)(ipcp->my_ip); #endif - OsLinkup(); - throughput_start(&throughput); - StartIdleTimer(); -} -void -IpcpUp() -{ - FsmUp(&IpcpFsm); - LogPrintf(LogIPCP, "IPCP Up event!!\n"); + return 1; } -void -IpcpOpen() +static int +IpcpLayerUp(struct fsm *fp) { - FsmOpen(&IpcpFsm); + /* We're now up */ + struct ipcp *ipcp = fsm2ipcp(fp); + char tbuff[100]; + + log_Printf(LogIPCP, "%s: IpcpLayerUp.\n", fp->link->name); + snprintf(tbuff, sizeof tbuff, "myaddr = %s ", inet_ntoa(ipcp->my_ip)); + log_Printf(LogIPCP, " %s hisaddr = %s\n", tbuff, inet_ntoa(ipcp->peer_ip)); + + if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP) + sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255); + + if (!ipcp_InterfaceUp(ipcp)) + return 0; + + /* + * XXX this stuff should really live in the FSM. Our config should + * associate executable sections in files with events. + */ + if (system_Select(fp->bundle, inet_ntoa(ipcp->my_ifip), LINKUPFILE, NULL) + < 0) { + if (bundle_GetLabel(fp->bundle)) { + if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle), + LINKUPFILE, NULL) < 0) + system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL); + } else + system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL); + } + + throughput_start(&ipcp->throughput, "IPCP throughput", + Enabled(fp->bundle, OPT_THROUGHPUT)); + bundle_DisplayPrompt(fp->bundle); + return 1; } static int -AcceptableAddr(struct in_range * prange, struct in_addr ipaddr) +AcceptableAddr(struct in_range *prange, struct in_addr ipaddr) { - LogPrintf(LogDEBUG, "requested = %x\n", htonl(ipaddr.s_addr)); - LogPrintf(LogDEBUG, "range = %x\n", htonl(prange->ipaddr.s_addr)); - LogPrintf(LogDEBUG, "/%x\n", htonl(prange->mask.s_addr)); - LogPrintf(LogDEBUG, "%x, %x\n", htonl(prange->ipaddr.s_addr & prange-> - mask.s_addr), htonl(ipaddr.s_addr & prange->mask.s_addr)); + /* Is the given IP in the given range ? */ return (prange->ipaddr.s_addr & prange->mask.s_addr) == (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr; } static void -IpcpDecodeConfig(u_char * cp, int plen, int mode_type) +IpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type, + struct fsm_decode *dec) { + /* Deal with incoming PROTO_IPCP */ + struct ipcp *ipcp = fsm2ipcp(fp); int type, length; - u_long *lp, compproto; + u_int32_t compproto; struct compreq *pcomp; - struct in_addr ipaddr, dstipaddr, dnsstuff, ms_info_req; - char tbuff[100]; - char tbuff2[100]; + struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2]; + char tbuff[100], tbuff2[100]; + int gotdns, gotdnsnak; - ackp = AckBuff; - nakp = NakBuff; - rejp = RejBuff; + gotdns = 0; + gotdnsnak = 0; + dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY; while (plen >= sizeof(struct fsmconfig)) { type = *cp; length = cp[1]; + + if (length == 0) { + log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name); + break; + } + if (type < NCFTYPES) snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length); else if (type > 128 && type < 128 + NCFTYPES128) @@ -419,288 +785,328 @@ IpcpDecodeConfig(u_char * cp, int plen, int mode_type) switch (type) { case TY_IPADDR: /* RFC1332 */ - lp = (u_long *) (cp + 2); - ipaddr.s_addr = *lp; - LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); + ipaddr.s_addr = *(u_int32_t *)(cp + 2); + log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); switch (mode_type) { case MODE_REQ: - if (iplist_isvalid(&DefHisChoice)) { + if (iplist_isvalid(&ipcp->cfg.peer_list)) { if (ipaddr.s_addr == INADDR_ANY || - iplist_ip2pos(&DefHisChoice, ipaddr) < 0 || - OsTrySetIpaddress(DefMyAddress.ipaddr, ipaddr) != 0) { - LogPrintf(LogIPCP, "%s: Address invalid or already in use\n", + iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 || + ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr, + ipaddr, 1)) { + log_Printf(LogIPCP, "%s: Address invalid or already in use\n", inet_ntoa(ipaddr)); - IpcpInfo.his_ipaddr = ChooseHisAddr(DefMyAddress.ipaddr); - if (IpcpInfo.his_ipaddr.s_addr == INADDR_ANY) { - memcpy(rejp, cp, length); - rejp += length; + if (iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->peer_ifip) >= 0) + /* + * If we've already got a valid address configured for the peer + * (in DEMAND mode), try NAKing with that so that we don't + * have to upset things too much. + */ + ipcp->peer_ip = ipcp->peer_ifip; + else + /* Just pick an IP number from our list */ + ipcp->peer_ip = ChooseHisAddr + (fp->bundle, ipcp->cfg.my_range.ipaddr); + + if (ipcp->peer_ip.s_addr == INADDR_ANY) { + memcpy(dec->rejend, cp, length); + dec->rejend += length; } else { - memcpy(nakp, cp, 2); - memcpy(nakp+2, &IpcpInfo.his_ipaddr.s_addr, length - 2); - nakp += length; + memcpy(dec->nakend, cp, 2); + memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2); + dec->nakend += length; } break; } - } else if (!AcceptableAddr(&DefHisAddress, ipaddr)) { + } else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) { /* - * If destination address is not acceptable, insist to use what we + * If destination address is not acceptable, NAK with what we * want to use. */ - memcpy(nakp, cp, 2); - memcpy(nakp+2, &IpcpInfo.his_ipaddr.s_addr, length - 2); - nakp += length; + memcpy(dec->nakend, cp, 2); + if ((ipcp->peer_ifip.s_addr & ipcp->cfg.peer_range.mask.s_addr) == + (ipcp->cfg.peer_range.ipaddr.s_addr & + ipcp->cfg.peer_range.mask.s_addr)) + /* We prefer the already-configured address */ + memcpy(dec->nakend+2, &ipcp->peer_ifip.s_addr, length - 2); + else + memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2); + dec->nakend += length; break; } - IpcpInfo.his_ipaddr = ipaddr; - memcpy(ackp, cp, length); - ackp += length; + ipcp->peer_ip = ipaddr; + memcpy(dec->ackend, cp, length); + dec->ackend += length; break; case MODE_NAK: - if (AcceptableAddr(&DefMyAddress, ipaddr)) { + if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) { /* Use address suggested by peer */ snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff, - inet_ntoa(IpcpInfo.want_ipaddr)); - LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); - IpcpInfo.want_ipaddr = ipaddr; + inet_ntoa(ipcp->my_ip)); + log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); + ipcp->my_ip = ipaddr; } else { - LogPrintf(LogIPCP, "%s: Unacceptable address!\n", inet_ntoa(ipaddr)); - FsmClose(&IpcpFsm); + log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE, + "%s: Unacceptable address!\n", inet_ntoa(ipaddr)); + fsm_Close(&ipcp->fsm); } break; case MODE_REJ: - IpcpInfo.his_reject |= (1 << type); + ipcp->peer_reject |= (1 << type); break; } break; case TY_COMPPROTO: - lp = (u_long *) (cp + 2); - compproto = htonl(*lp); - LogPrintf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto)); + compproto = htonl(*(u_int32_t *)(cp + 2)); + log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto)); switch (mode_type) { case MODE_REQ: - if (!Acceptable(ConfVjcomp)) { - memcpy(rejp, cp, length); - rejp += length; + if (!IsAccepted(ipcp->cfg.vj.neg)) { + memcpy(dec->rejend, cp, length); + dec->rejend += length; } else { pcomp = (struct compreq *) (cp + 2); switch (length) { case 4: /* RFC1172 */ if (ntohs(pcomp->proto) == PROTO_VJCOMP) { - LogPrintf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n"); - IpcpInfo.heis1172 = 1; - IpcpInfo.his_compproto = compproto; - memcpy(ackp, cp, length); - ackp += length; + log_Printf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n"); + ipcp->heis1172 = 1; + ipcp->peer_compproto = compproto; + memcpy(dec->ackend, cp, length); + dec->ackend += length; } else { - memcpy(nakp, cp, 2); + memcpy(dec->nakend, cp, 2); pcomp->proto = htons(PROTO_VJCOMP); - memcpy(nakp+2, &pcomp, 2); - nakp += length; + memcpy(dec->nakend+2, &pcomp, 2); + dec->nakend += length; } break; case 6: /* RFC1332 */ if (ntohs(pcomp->proto) == PROTO_VJCOMP - && pcomp->slots < MAX_STATES && pcomp->slots > 2) { - IpcpInfo.his_compproto = compproto; - IpcpInfo.heis1172 = 0; - memcpy(ackp, cp, length); - ackp += length; + && pcomp->slots <= MAX_VJ_STATES + && pcomp->slots >= MIN_VJ_STATES) { + ipcp->peer_compproto = compproto; + ipcp->heis1172 = 0; + memcpy(dec->ackend, cp, length); + dec->ackend += length; } else { - memcpy(nakp, cp, 2); + memcpy(dec->nakend, cp, 2); pcomp->proto = htons(PROTO_VJCOMP); - pcomp->slots = MAX_STATES - 1; + pcomp->slots = DEF_VJ_STATES; pcomp->compcid = 0; - memcpy(nakp+2, &pcomp, sizeof pcomp); - nakp += length; + memcpy(dec->nakend+2, &pcomp, sizeof pcomp); + dec->nakend += length; } break; default: - memcpy(rejp, cp, length); - rejp += length; + memcpy(dec->rejend, cp, length); + dec->rejend += length; break; } } break; case MODE_NAK: - LogPrintf(LogIPCP, "%s changing compproto: %08x --> %08x\n", - tbuff, IpcpInfo.want_compproto, compproto); - IpcpInfo.want_compproto = compproto; + log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n", + tbuff, ipcp->my_compproto, compproto); + ipcp->my_compproto = compproto; break; case MODE_REJ: - IpcpInfo.his_reject |= (1 << type); + ipcp->peer_reject |= (1 << type); break; } break; case TY_IPADDRS: /* RFC1172 */ - lp = (u_long *) (cp + 2); - ipaddr.s_addr = *lp; - lp = (u_long *) (cp + 6); - dstipaddr.s_addr = *lp; + ipaddr.s_addr = *(u_int32_t *)(cp + 2); + dstipaddr.s_addr = *(u_int32_t *)(cp + 6); snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr)); - LogPrintf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr)); + log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr)); switch (mode_type) { case MODE_REQ: - IpcpInfo.his_ipaddr = ipaddr; - IpcpInfo.want_ipaddr = dstipaddr; - memcpy(ackp, cp, length); - ackp += length; + ipcp->peer_ip = ipaddr; + ipcp->my_ip = dstipaddr; + memcpy(dec->ackend, cp, length); + dec->ackend += length; break; case MODE_NAK: snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff, - inet_ntoa(IpcpInfo.want_ipaddr)); - LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); - IpcpInfo.want_ipaddr = ipaddr; - IpcpInfo.his_ipaddr = dstipaddr; + inet_ntoa(ipcp->my_ip)); + log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr)); + ipcp->my_ip = ipaddr; + ipcp->peer_ip = dstipaddr; break; case MODE_REJ: - IpcpInfo.his_reject |= (1 << type); + ipcp->peer_reject |= (1 << type); break; } break; - /* - * MS extensions for MS's PPP - */ - -#ifndef NOMSEXT - case TY_PRIMARY_DNS: /* MS PPP DNS negotiation hack */ + case TY_PRIMARY_DNS: /* DNS negotiation (rfc1877) */ case TY_SECONDARY_DNS: - if (!Enabled(ConfMSExt)) { - LogPrintf(LogIPCP, "MS NS req - rejected - msext disabled\n"); - IpcpInfo.my_reject |= (1 << type); - memcpy(rejp, cp, length); - rejp += length; - break; - } + ipaddr.s_addr = *(u_int32_t *)(cp + 2); + log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); + switch (mode_type) { case MODE_REQ: - lp = (u_long *) (cp + 2); - dnsstuff.s_addr = *lp; - ms_info_req.s_addr = ns_entries[((type - TY_PRIMARY_DNS) ? 1 : 0)].s_addr; - if (dnsstuff.s_addr != ms_info_req.s_addr) { + if (!IsAccepted(ipcp->cfg.ns.dns_neg)) { + ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); + memcpy(dec->rejend, cp, length); + dec->rejend += length; + break; + } + if (!gotdns) { + dns[0] = ipcp->cfg.ns.dns[0]; + dns[1] = ipcp->cfg.ns.dns[1]; + if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY) + getdns(ipcp, dns); + gotdns = 1; + } + have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1]; + if (ipaddr.s_addr != have_ip.s_addr) { /* - * So the client has got the DNS stuff wrong (first request) so + * The client has got the DNS stuff wrong (first request) so * we'll tell 'em how it is */ - memcpy(nakp, cp, 2); /* copy first two (type/length) */ - LogPrintf(LogIPCP, "MS NS req %d:%s->%s - nak\n", - type, - inet_ntoa(dnsstuff), - inet_ntoa(ms_info_req)); - memcpy(nakp+2, &ms_info_req, length); - nakp += length; - break; - } - - /* - * Otherwise they have it right (this time) so we send a ack packet - * back confirming it... end of story - */ - LogPrintf(LogIPCP, "MS NS req %d:%s ok - ack\n", - type, - inet_ntoa(ms_info_req)); - memcpy(ackp, cp, length); - ackp += length; + memcpy(dec->nakend, cp, 2); /* copy first two (type/length) */ + memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2); + dec->nakend += length; + } else { + /* + * Otherwise they have it right (this time) so we send a ack packet + * back confirming it... end of story + */ + memcpy(dec->ackend, cp, length); + dec->ackend += length; + } break; case MODE_NAK: /* what does this mean?? */ - LogPrintf(LogIPCP, "MS NS req %d - NAK??\n", type); + if (IsEnabled(ipcp->cfg.ns.dns_neg)) { + gotdnsnak = 1; + dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr = + *(u_int32_t *)(cp + 2); + } break; - case MODE_REJ: /* confused?? me to :) */ - LogPrintf(LogIPCP, "MS NS req %d - REJ??\n", type); + case MODE_REJ: /* Can't do much, stop asking */ + ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS)); break; } break; - case TY_PRIMARY_NBNS: /* MS PPP NetBIOS nameserver hack */ + case TY_PRIMARY_NBNS: /* M$ NetBIOS nameserver hack (rfc1877) */ case TY_SECONDARY_NBNS: - if (!Enabled(ConfMSExt)) { - LogPrintf(LogIPCP, "MS NBNS req - rejected - msext disabled\n"); - IpcpInfo.my_reject |= (1 << type); - memcpy(rejp, cp, length); - rejp += length; - break; - } + ipaddr.s_addr = *(u_int32_t *)(cp + 2); + log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr)); + switch (mode_type) { case MODE_REQ: - lp = (u_long *) (cp + 2); - dnsstuff.s_addr = *lp; - ms_info_req.s_addr = nbns_entries[((type - TY_PRIMARY_NBNS) ? 1 : 0)].s_addr; - if (dnsstuff.s_addr != ms_info_req.s_addr) { - memcpy(nakp, cp, 2); - memcpy(nakp+2, &ms_info_req.s_addr, length); - LogPrintf(LogIPCP, "MS NBNS req %d:%s->%s - nak\n", - type, - inet_ntoa(dnsstuff), - inet_ntoa(ms_info_req)); - nakp += length; + have_ip.s_addr = + ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr; + + if (have_ip.s_addr == INADDR_ANY) { + log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n"); + ipcp->my_reject |= (1 << (type - TY_ADJUST_NS)); + memcpy(dec->rejend, cp, length); + dec->rejend += length; break; - } - LogPrintf(LogIPCP, "MS NBNS req %d:%s ok - ack\n", - type, - inet_ntoa(ms_info_req)); - memcpy(ackp, cp, length); - ackp += length; + } + + if (ipaddr.s_addr != have_ip.s_addr) { + memcpy(dec->nakend, cp, 2); + memcpy(dec->nakend+2, &have_ip.s_addr, length); + dec->nakend += length; + } else { + memcpy(dec->ackend, cp, length); + dec->ackend += length; + } break; case MODE_NAK: - LogPrintf(LogIPCP, "MS NBNS req %d - NAK??\n", type); + log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type); break; case MODE_REJ: - LogPrintf(LogIPCP, "MS NBNS req %d - REJ??\n", type); + log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type); break; } break; -#endif - default: - IpcpInfo.my_reject |= (1 << type); - memcpy(rejp, cp, length); - rejp += length; + if (mode_type != MODE_NOP) { + ipcp->my_reject |= (1 << type); + memcpy(dec->rejend, cp, length); + dec->rejend += length; + } break; } plen -= length; cp += length; } + + if (gotdnsnak) + if (!setdns(ipcp, dnsnak)) { + ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS)); + ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS)); + } + + if (mode_type != MODE_NOP) { + if (dec->rejend != dec->rej) { + /* rejects are preferred */ + dec->ackend = dec->ack; + dec->nakend = dec->nak; + } else if (dec->nakend != dec->nak) + /* then NAKs */ + dec->ackend = dec->ack; + } } void -IpcpInput(struct mbuf * bp) +ipcp_Input(struct ipcp *ipcp, struct bundle *bundle, struct mbuf *bp) { - FsmInput(&IpcpFsm, bp); + /* Got PROTO_IPCP from link */ + if (bundle_Phase(bundle) == PHASE_NETWORK) + fsm_Input(&ipcp->fsm, bp); + else { + if (bundle_Phase(bundle) < PHASE_NETWORK) + log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n", + ipcp->fsm.link->name, bundle_PhaseName(bundle)); + mbuf_Free(bp); + } } int -UseHisaddr(const char *hisaddr, int setaddr) +ipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr) { - memset(&DefHisAddress, '\0', sizeof DefHisAddress); - iplist_reset(&DefHisChoice); + struct ipcp *ipcp = &bundle->ncp.ipcp; + + /* Use `hisaddr' for the peers address (set iface if `setaddr') */ + memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range); + iplist_reset(&ipcp->cfg.peer_list); if (strpbrk(hisaddr, ",-")) { - iplist_setsrc(&DefHisChoice, hisaddr); - if (iplist_isvalid(&DefHisChoice)) { - iplist_setrandpos(&DefHisChoice); - IpcpInfo.his_ipaddr = ChooseHisAddr(IpcpInfo.want_ipaddr); - if (IpcpInfo.his_ipaddr.s_addr == INADDR_ANY) { - LogPrintf(LogWARN, "%s: None available !\n", DefHisChoice.src); + iplist_setsrc(&ipcp->cfg.peer_list, hisaddr); + if (iplist_isvalid(&ipcp->cfg.peer_list)) { + iplist_setrandpos(&ipcp->cfg.peer_list); + ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip); + if (ipcp->peer_ip.s_addr == INADDR_ANY) { + log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src); return(0); } - DefHisAddress.ipaddr.s_addr = IpcpInfo.his_ipaddr.s_addr; - DefHisAddress.mask.s_addr = 0xffffffff; - DefHisAddress.width = 32; + ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr; + ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST; + ipcp->cfg.peer_range.width = 32; } else { - LogPrintf(LogWARN, "%s: Invalid range !\n", hisaddr); + log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr); return 0; } - } else if (ParseAddr(1, &hisaddr, &DefHisAddress.ipaddr, - &DefHisAddress.mask, &DefHisAddress.width) != 0) { - IpcpInfo.his_ipaddr.s_addr = DefHisAddress.ipaddr.s_addr; + } else if (ParseAddr(ipcp, 1, &hisaddr, &ipcp->cfg.peer_range.ipaddr, + &ipcp->cfg.peer_range.mask, + &ipcp->cfg.peer_range.width) != 0) { + ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr; - if (setaddr && OsSetIpaddress - (DefMyAddress.ipaddr, DefHisAddress.ipaddr) < 0) { - DefMyAddress.ipaddr.s_addr = DefHisAddress.ipaddr.s_addr = 0L; + if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, + ipcp->cfg.peer_range.ipaddr, 0) < 0) { + ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY; + ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY; return 0; } } else |