pcomp = (struct compreq *) (cp + 2);
IpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type,                 struct fsm_decode *dec){  /* Deal with incoming PROTO_IPCP */  struct iface *iface = fp->bundle->iface;  struct ipcp *ipcp = fsm2ipcp(fp);  int type, length, gotdns, gotdnsnak, n;  u_int32_t compproto;  struct compreq *pcomp;  struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2];  char tbuff[100], tbuff2[100];  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)      snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length);    else      snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length);    switch (type) {    case TY_IPADDR:		/* RFC1332 */      memcpy(&ipaddr.s_addr, cp + 2, 4);      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));      switch (mode_type) {      case MODE_REQ:        if (iplist_isvalid(&ipcp->cfg.peer_list)) {          if (ipaddr.s_addr == INADDR_ANY ||              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));            /*             * If we've already had a valid address configured for the peer,             * try NAKing with that so that we don't have to upset things             * too much.             */            for (n = 0; n < iface->in_addrs; n++)              if (iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd)                  >=0) {                ipcp->peer_ip = iface->in_addr[n].brd;                break;              }            if (n == iface->in_addrs)              /* 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(dec->nakend, cp, 2);	      memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2);	      dec->nakend += length;            }	    break;          }	} else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) {	  /*	   * If destination address is not acceptable, NAK with what we	   * want to use.	   */	  memcpy(dec->nakend, cp, 2);          for (n = 0; n < iface->in_addrs; n++)            if ((iface->in_addr[n].brd.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, &iface->in_addr[n].brd.s_addr,                     length - 2);              break;            }          if (n == iface->in_addrs)	    memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2);	  dec->nakend += length;	  break;	}	ipcp->peer_ip = ipaddr;	memcpy(dec->ackend, cp, length);	dec->ackend += length;	break;      case MODE_NAK:	if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) {	  /* Use address suggested by peer */	  snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,		   inet_ntoa(ipcp->my_ip));	  log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));	  ipcp->my_ip = ipaddr;	} else {	  log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE,                    "%s: Unacceptable address!\n", inet_ntoa(ipaddr));          fsm_Close(&ipcp->fsm);	}	break;      case MODE_REJ:	ipcp->peer_reject |= (1 << type);	break;      }      break;    case TY_COMPPROTO:      memcpy(&compproto, cp + 2, 4);      log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));      switch (mode_type) {      case MODE_REQ:	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) {	      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(dec->nakend, cp, 2);	      pcomp->proto = htons(PROTO_VJCOMP);	      memcpy(dec->nakend+2, &pcomp, 2);	      dec->nakend += length;	    }	    break;	  case 6:		/* RFC1332 */	    if (ntohs(pcomp->proto) == PROTO_VJCOMP		&& 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(dec->nakend, cp, 2);	      pcomp->proto = htons(PROTO_VJCOMP);	      pcomp->slots = DEF_VJ_STATES;	      pcomp->compcid = 0;	      memcpy(dec->nakend+2, &pcomp, sizeof pcomp);	      dec->nakend += length;	    }	    break;	  default:	    memcpy(dec->rejend, cp, length);	    dec->rejend += length;	    break;	  }	}	break;      case MODE_NAK:	log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n",		  tbuff, ipcp->my_compproto, compproto);	ipcp->my_compproto = compproto;	break;      case MODE_REJ:	ipcp->peer_reject |= (1 << type);	break;      }      break;    case TY_IPADDRS:		/* RFC1172 */      memcpy(&ipaddr.s_addr, cp + 2, 4);      memcpy(&dstipaddr.s_addr, cp + 6, 4);      snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));      log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));      switch (mode_type) {      case MODE_REQ:	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(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:	ipcp->peer_reject |= (1 << type);	break;      }      break;    case TY_PRIMARY_DNS:	/* DNS negotiation (rfc1877) */    case TY_SECONDARY_DNS:      memcpy(&ipaddr.s_addr, cp + 2, 4);      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));      switch (mode_type) {      case MODE_REQ:        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) {	  /*	   * The client has got the DNS stuff wrong (first request) so	   * we'll tell 'em how it is	   */	  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?? */        if (IsEnabled(ipcp->cfg.ns.dns_neg)) {          gotdnsnak = 1;          memcpy(&dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr, cp + 2, 4);	}	break;      case MODE_REJ:		/* Can't do much, stop asking */        ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS));	break;      }      break;    case TY_PRIMARY_NBNS:	/* M$ NetBIOS nameserver hack (rfc1877) */    case TY_SECONDARY_NBNS:      memcpy(&ipaddr.s_addr, cp + 2, 4);      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));      switch (mode_type) {      case MODE_REQ:	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;        }	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:	log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type);	break;      case MODE_REJ:	log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type);	break;      }      break;    default:      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;  }}