static void
chap_Read_old(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
{
    struct chap *chap = descriptor2chap(d);
    int got;

    got = read(chap->child.fd, chap->child.buf.ptr + chap->child.buf.len,
               sizeof chap->child.buf.ptr - chap->child.buf.len - 1);
    if (got == -1) {
        log_Printf(LogERROR, "Chap: Read: %s\n", strerror(errno));
        chap_Cleanup(chap, SIGTERM);
    } else if (got == 0) {
        log_Printf(LogWARN, "Chap: Read: Child terminated connection\n");
        chap_Cleanup(chap, SIGTERM);
    } else {
        char *name, *key, *end;

        chap->child.buf.len += got;
        chap->child.buf.ptr[chap->child.buf.len] = '\0';
        name = chap->child.buf.ptr;
        name += strspn(name, " \t");
        if ((key = strchr(name, '\n')) == NULL)
            end = NULL;
        else
            end = strchr(++key, '\n');

        if (end == NULL) {
            if (chap->child.buf.len == sizeof chap->child.buf.ptr - 1) {
                log_Printf(LogWARN, "Chap: Read: Input buffer overflow\n");
                chap_Cleanup(chap, SIGTERM);
            }
        } else {
#ifdef HAVE_DES
            int lanman = chap->auth.physical->link.lcp.his_authtype == 0x80 &&
                         ((chap->NTRespSent &&
                           IsAccepted(chap->auth.physical->link.lcp.cfg.chap80lm)) ||
                          !IsAccepted(chap->auth.physical->link.lcp.cfg.chap80nt));
#endif

            while (end >= name && strchr(" \t\r\n", *end))
                *end-- = '\0';
            end = key - 1;
            while (end >= name && strchr(" \t\r\n", *end))
                *end-- = '\0';
            key += strspn(key, " \t");

            chap_Respond(chap, name, key, chap->auth.physical->link.lcp.his_authtype
#ifdef HAVE_DES
                         , lanman
#endif
                        );
            chap_Cleanup(chap, 0);
        }
    }
}
struct mbuf *
chap_Input_old(struct bundle *bundle, struct link *l, struct mbuf *bp)
{
    struct physical *p = link2physical(l);
    struct chap *chap = &p->dl->chap;
    char *name, *key, *ans;
    int len, nlen;
    u_char alen;
#ifdef HAVE_DES
    int lanman;
#endif

    if (p == NULL) {
        log_Printf(LogERROR, "chap_Input: Not a physical link - dropped\n");
        m_freem(bp);
        return NULL;
    }

    if (bundle_Phase(bundle) != PHASE_NETWORK &&
            bundle_Phase(bundle) != PHASE_AUTHENTICATE) {
        log_Printf(LogPHASE, "Unexpected chap input - dropped !\n");
        m_freem(bp);
        return NULL;
    }

    m_settype(bp, MB_CHAPIN);
    if ((bp = auth_ReadHeader(&chap->auth, bp)) == NULL &&
            ntohs(chap->auth.in.hdr.length) == 0)
        log_Printf(LogWARN, "Chap Input: Truncated header !\n");
    else if (chap->auth.in.hdr.code == 0 || chap->auth.in.hdr.code > MAXCHAPCODE)
        log_Printf(LogPHASE, "Chap Input: %d: Bad CHAP code !\n",
                   chap->auth.in.hdr.code);
    else {
        len = m_length(bp);
        ans = NULL;

        if (chap->auth.in.hdr.code != CHAP_CHALLENGE &&
                chap->auth.id != chap->auth.in.hdr.id &&
                Enabled(bundle, OPT_IDCHECK)) {
            /* Wrong conversation dude ! */
            log_Printf(LogPHASE, "Chap Input: %s dropped (got id %d, not %d)\n",
                       chapcodes[chap->auth.in.hdr.code], chap->auth.in.hdr.id,
                       chap->auth.id);
            m_freem(bp);
            return NULL;
        }
        chap->auth.id = chap->auth.in.hdr.id;	/* We respond with this id */

#ifdef HAVE_DES
        lanman = 0;
#endif
        switch (chap->auth.in.hdr.code) {
        case CHAP_CHALLENGE:
            bp = mbuf_Read(bp, &alen, 1);
            len -= alen + 1;    /* len -= (alen + 1); */
            if (len < 0) {
                log_Printf(LogERROR, "Chap Input: Truncated challenge !\n");
                m_freem(bp);
                return NULL;
            }
            *chap->challenge.peer = alen;
            bp = mbuf_Read(bp, chap->challenge.peer + 1, alen);
            bp = auth_ReadName(&chap->auth, bp, len);
#ifdef HAVE_DES
            lanman = p->link.lcp.his_authtype == 0x80 &&
                     ((chap->NTRespSent && IsAccepted(p->link.lcp.cfg.chap80lm)) ||
                      !IsAccepted(p->link.lcp.cfg.chap80nt));
#endif
            break;

        case CHAP_RESPONSE:
            auth_StopTimer(&chap->auth);
            bp = mbuf_Read(bp, &alen, 1);    /* read HASH-Size */
            len -= alen + 1;    /* len -= (alen + 1);, len is length of Name Field */
            if (len < 0) {
                log_Printf(LogERROR, "Chap Input: Truncated response !\n");
                m_freem(bp);
                return NULL;
            }
            if ((ans = malloc(alen + 2)) == NULL) {
                log_Printf(LogERROR, "Chap Input: Out of memory !\n");
                m_freem(bp);
                return NULL;
            }
            *ans = chap->auth.id;
            bp = mbuf_Read(bp, ans + 1, alen);    /* cut HASH value */
            ans[alen+1] = '\0';    /* ans is (id, HASH, \0)*/
            bp = auth_ReadName(&chap->auth, bp, len);
#ifdef HAVE_DES
            lanman = alen == 49 && ans[alen] == 0;
#endif
            break;

        case CHAP_SUCCESS:
        case CHAP_FAILURE:
            /* chap->auth.in.name is already set up at CHALLENGE time */
            if ((ans = malloc(len + 1)) == NULL) {
                log_Printf(LogERROR, "Chap Input: Out of memory !\n");
                m_freem(bp);
                return NULL;
            }
            bp = mbuf_Read(bp, ans, len);
            ans[len] = '\0';
            break;
        }

        switch (chap->auth.in.hdr.code) {
        case CHAP_CHALLENGE:
        case CHAP_RESPONSE:
            if (*chap->auth.in.name)
                log_Printf(LogPHASE, "Chap Input: %s (%d bytes from %s%s)\n",
                           chapcodes[chap->auth.in.hdr.code], alen,
                           chap->auth.in.name,
#ifdef HAVE_DES
                           lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
                           " - lanman" :
#endif
                           "");
            else
                log_Printf(LogPHASE, "Chap Input: %s (%d bytes%s)\n",
                           chapcodes[chap->auth.in.hdr.code], alen,
#ifdef HAVE_DES
                           lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
                           " - lanman" :
#endif
                           "");
            break;

        case CHAP_SUCCESS:
        case CHAP_FAILURE:
            if (*ans)
                log_Printf(LogPHASE, "Chap Input: %s (%s)\n",
                           chapcodes[chap->auth.in.hdr.code], ans);
            else
                log_Printf(LogPHASE, "Chap Input: %s\n",
                           chapcodes[chap->auth.in.hdr.code]);
            break;
        }

        switch (chap->auth.in.hdr.code) {
        case CHAP_CHALLENGE:
            if (*bundle->cfg.auth.key == '!' && bundle->cfg.auth.key[1] != '!')
                chap_StartChild(chap, bundle->cfg.auth.key + 1,
                                bundle->cfg.auth.name);
            else
                chap_Respond(chap, bundle->cfg.auth.name, bundle->cfg.auth.key +
                             (*bundle->cfg.auth.key == '!' ? 1 : 0),
                             p->link.lcp.his_authtype
#ifdef HAVE_DES
                             , lanman
#endif
                            );
            break;

        case CHAP_RESPONSE:
            name = chap->auth.in.name;
            nlen = strlen(name);
#ifndef NORADIUS
            if (*bundle->radius.cfg.file) {
                u_char end;

                end = chap->challenge.local[*chap->challenge.local+1];
                chap->challenge.local[*chap->challenge.local+1] = '\0';
                radius_Authenticate(&bundle->radius, &chap->auth,
                                    chap->auth.in.name, ans,
                                    chap->challenge.local + 1);
                chap->challenge.local[*chap->challenge.local+1] = end;
            } else
#endif
            {
                key = auth_GetSecret(bundle, name, nlen, p);
                if (key) {
                    char *myans;
#ifdef HAVE_DES
                    if (lanman && !IsEnabled(p->link.lcp.cfg.chap80lm)) {
                        log_Printf(LogPHASE, "Auth failure: LANMan not enabled\n");
                        if (chap_HaveAnotherGo(chap))
                            break;
                        key = NULL;
                    } else if (!lanman && !IsEnabled(p->link.lcp.cfg.chap80nt) &&
                               p->link.lcp.want_authtype == 0x80) {
                        log_Printf(LogPHASE, "Auth failure: mschap not enabled\n");
                        if (chap_HaveAnotherGo(chap))
                            break;
                        key = NULL;
                    } else
#endif
                    {
                        myans = chap_BuildAnswer(name, key, chap->auth.id,
                                                 chap->challenge.local,
                                                 p->link.lcp.want_authtype
#ifdef HAVE_DES
                                                 , lanman
#endif
                                                );
                        if (myans == NULL)
                            key = NULL;
                        else {
                            if (!chap_Cmp(p->link.lcp.want_authtype, myans + 1, *myans,
                                          ans + 1, alen
#ifdef HAVE_DES
                                          , lanman
#endif
                                         ))
                                key = NULL;
                            free(myans);
                        }
                    }
                }

                if (key)
                    chap_Success(&chap->auth);
                else
                    chap_Failure(&chap->auth);
            }

            break;

        case CHAP_SUCCESS:
            if (p->link.lcp.auth_iwait == PROTO_CHAP) {
                p->link.lcp.auth_iwait = 0;
                if (p->link.lcp.auth_ineed == 0)
                    /*
                     * We've succeeded in our ``login''
                     * If we're not expecting  the peer to authenticate (or he already
                     * has), proceed to network phase.
                     */
                    datalink_AuthOk(p->dl);
            }
            break;

        case CHAP_FAILURE:
            datalink_AuthNotOk(p->dl);
            break;
        }
        free(ans);
    }

    m_freem(bp);
    return NULL;
}
Exemple #3
0
struct mbuf *
chap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
{
  struct physical *p = link2physical(l);
  struct chap *chap = &p->dl->chap;
  char *name, *key, *ans;
  int len, nlen;
  u_char alen;
#ifndef NODES
  int lanman;
#endif

  if (p == NULL) {
    log_Printf(LogERROR, "chap_Input: Not a physical link - dropped\n");
    m_freem(bp);
    return NULL;
  }

  if (bundle_Phase(bundle) != PHASE_NETWORK &&
      bundle_Phase(bundle) != PHASE_AUTHENTICATE) {
    log_Printf(LogPHASE, "Unexpected chap input - dropped !\n");
    m_freem(bp);
    return NULL;
  }

  m_settype(bp, MB_CHAPIN);
  if ((bp = auth_ReadHeader(&chap->auth, bp)) == NULL &&
      ntohs(chap->auth.in.hdr.length) == 0)
    log_Printf(LogWARN, "Chap Input: Truncated header !\n");
  else if (chap->auth.in.hdr.code == 0 || chap->auth.in.hdr.code > MAXCHAPCODE)
    log_Printf(LogPHASE, "Chap Input: %d: Bad CHAP code !\n",
               chap->auth.in.hdr.code);
  else {
    len = m_length(bp);
    ans = NULL;

    if (chap->auth.in.hdr.code != CHAP_CHALLENGE &&
        chap->auth.id != chap->auth.in.hdr.id &&
        Enabled(bundle, OPT_IDCHECK)) {
      /* Wrong conversation dude ! */
      log_Printf(LogPHASE, "Chap Input: %s dropped (got id %d, not %d)\n",
                 chapcodes[chap->auth.in.hdr.code], chap->auth.in.hdr.id,
                 chap->auth.id);
      m_freem(bp);
      return NULL;
    }
    chap->auth.id = chap->auth.in.hdr.id;	/* We respond with this id */

#ifndef NODES
    lanman = 0;
#endif
    switch (chap->auth.in.hdr.code) {
      case CHAP_CHALLENGE:
        bp = mbuf_Read(bp, &alen, 1);
        len -= alen + 1;
        if (len < 0) {
          log_Printf(LogERROR, "Chap Input: Truncated challenge !\n");
          m_freem(bp);
          return NULL;
        }
        *chap->challenge.peer = alen;
        bp = mbuf_Read(bp, chap->challenge.peer + 1, alen);
        bp = auth_ReadName(&chap->auth, bp, len);
#ifndef NODES
        lanman = p->link.lcp.his_authtype == 0x80 &&
                 ((chap->NTRespSent && IsAccepted(p->link.lcp.cfg.chap80lm)) ||
                  !IsAccepted(p->link.lcp.cfg.chap80nt));

        /* Generate local challenge value */
        chap_ChallengeInit(&chap->auth);
#endif
        break;

      case CHAP_RESPONSE:
        auth_StopTimer(&chap->auth);
        bp = mbuf_Read(bp, &alen, 1);
        len -= alen + 1;
        if (len < 0) {
          log_Printf(LogERROR, "Chap Input: Truncated response !\n");
          m_freem(bp);
          return NULL;
        }
        if ((ans = malloc(alen + 1)) == NULL) {
          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
          m_freem(bp);
          return NULL;
        }
        *ans = chap->auth.id;
        bp = mbuf_Read(bp, ans + 1, alen);
        bp = auth_ReadName(&chap->auth, bp, len);
#ifndef NODES
        lanman = p->link.lcp.want_authtype == 0x80 &&
                 alen == 49 && ans[alen] == 0;
#endif
        break;

      case CHAP_SUCCESS:
      case CHAP_FAILURE:
        /* chap->auth.in.name is already set up at CHALLENGE time */
        if ((ans = malloc(len + 1)) == NULL) {
          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
          m_freem(bp);
          return NULL;
        }
        bp = mbuf_Read(bp, ans, len);
        ans[len] = '\0';
        break;
    }

    switch (chap->auth.in.hdr.code) {
      case CHAP_CHALLENGE:
      case CHAP_RESPONSE:
        if (*chap->auth.in.name)
          log_Printf(LogPHASE, "Chap Input: %s (%d bytes from %s%s)\n",
                     chapcodes[chap->auth.in.hdr.code], alen,
                     chap->auth.in.name,
#ifndef NODES
                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
                     " - lanman" :
#endif
                     "");
        else
          log_Printf(LogPHASE, "Chap Input: %s (%d bytes%s)\n",
                     chapcodes[chap->auth.in.hdr.code], alen,
#ifndef NODES
                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
                     " - lanman" :
#endif
                     "");
        break;

      case CHAP_SUCCESS:
      case CHAP_FAILURE:
        if (*ans)
          log_Printf(LogPHASE, "Chap Input: %s (%s)\n",
                     chapcodes[chap->auth.in.hdr.code], ans);
        else
          log_Printf(LogPHASE, "Chap Input: %s\n",
                     chapcodes[chap->auth.in.hdr.code]);
        break;
    }

    switch (chap->auth.in.hdr.code) {
      case CHAP_CHALLENGE:
        if (*bundle->cfg.auth.key == '!' && bundle->cfg.auth.key[1] != '!')
          chap_StartChild(chap, bundle->cfg.auth.key + 1,
                          bundle->cfg.auth.name);
        else
          chap_Respond(chap, bundle->cfg.auth.name, bundle->cfg.auth.key +
                       (*bundle->cfg.auth.key == '!' ? 1 : 0),
                       p->link.lcp.his_authtype
#ifndef NODES
                       , lanman
#endif
                      );
        break;

      case CHAP_RESPONSE:
        name = chap->auth.in.name;
        nlen = strlen(name);
#ifndef NODES
        if (p->link.lcp.want_authtype == 0x81) {
          struct MSCHAPv2_resp *resp = (struct MSCHAPv2_resp *)(ans + 1);

          chap->challenge.peer[0] = sizeof resp->PeerChallenge;
          memcpy(chap->challenge.peer + 1, resp->PeerChallenge,
                 sizeof resp->PeerChallenge);
        }
#endif

#ifndef NORADIUS
        if (*bundle->radius.cfg.file) {
          if (!radius_Authenticate(&bundle->radius, &chap->auth,
                                   chap->auth.in.name, ans, alen + 1,
                                   chap->challenge.local + 1,
                                   *chap->challenge.local))
            chap_Failure(&chap->auth);
        } else
#endif
        {
          if (p->link.lcp.want_authtype == 0x81 && ans[alen] != '\0' &&
              alen == sizeof(struct MSCHAPv2_resp)) {
            struct MSCHAPv2_resp *resp = (struct MSCHAPv2_resp *)(ans + 1);

            log_Printf(LogWARN, "%s: Compensating for corrupt (Win98/WinME?) "
                       "CHAP81 RESPONSE\n", l->name);
            resp->Flags = '\0';	/* rfc2759 says it *MUST* be zero */
          }
          key = auth_GetSecret(bundle, name, nlen, p);
          if (key) {
#ifndef NODES
            if (p->link.lcp.want_authtype == 0x80 &&
                lanman && !IsEnabled(p->link.lcp.cfg.chap80lm)) {
              log_Printf(LogPHASE, "Auth failure: LANMan not enabled\n");
              if (chap_HaveAnotherGo(chap))
                break;
              key = NULL;
            } else if (p->link.lcp.want_authtype == 0x80 &&
                !lanman && !IsEnabled(p->link.lcp.cfg.chap80nt)) {
              log_Printf(LogPHASE, "Auth failure: mschap not enabled\n");
              if (chap_HaveAnotherGo(chap))
                break;
              key = NULL;
            } else if (p->link.lcp.want_authtype == 0x81 &&
                !IsEnabled(p->link.lcp.cfg.chap81)) {
              log_Printf(LogPHASE, "Auth failure: CHAP81 not enabled\n");
              key = NULL;
            } else
#endif
            {
              char *myans = chap_BuildAnswer(name, key, chap->auth.id,
                                             chap->challenge.local,
                                       p->link.lcp.want_authtype
#ifndef NODES
                                       , chap->challenge.peer,
                                       chap->authresponse, lanman);
              MPPE_IsServer = 1;		/* XXX Global ! */
#else
                                      );
#endif
              if (myans == NULL)
                key = NULL;
              else {
                if (!chap_Cmp(p->link.lcp.want_authtype, myans + 1, *myans,
                              ans + 1, alen
#ifndef NODES
                              , lanman
#endif
                             ))
                  key = NULL;
                free(myans);
              }
            }
          }

          if (key)
            chap_Success(&chap->auth);
          else
            chap_Failure(&chap->auth);
        }

        break;

      case CHAP_SUCCESS:
        if (p->link.lcp.auth_iwait == PROTO_CHAP) {
          p->link.lcp.auth_iwait = 0;
          if (p->link.lcp.auth_ineed == 0) {
#ifndef NODES
            if (p->link.lcp.his_authtype == 0x81) {
              if (strncasecmp(ans, chap->authresponse, 42)) {
                datalink_AuthNotOk(p->dl);
	        log_Printf(LogWARN, "CHAP81: AuthenticatorResponse: (%.42s)"
                           " != ans: (%.42s)\n", chap->authresponse, ans);

              } else {
                /* Successful login */
                MPPE_MasterKeyValid = 1;		/* XXX Global ! */
                datalink_AuthOk(p->dl);
              }
            } else
#endif
            /*
             * We've succeeded in our ``login''
             * If we're not expecting  the peer to authenticate (or he already
             * has), proceed to network phase.
             */
            datalink_AuthOk(p->dl);
          }
        }
        break;

      case CHAP_FAILURE:
        datalink_AuthNotOk(p->dl);
        break;
    }
    free(ans);
  }
Exemple #4
0
static void
CcpDecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type,
                struct fsm_decode *dec)
{
  /* Deal with incoming data */
  struct ccp *ccp = fsm2ccp(fp);
  int f;
  const char *disp;
  struct fsm_opt *opt;

  if (mode_type == MODE_REQ)
    ccp->in.algorithm = -1;	/* In case we've received two REQs in a row */

  while (end >= cp + sizeof(opt->hdr)) {
    if ((opt = fsm_readopt(&cp)) == NULL)
      break;

    for (f = NALGORITHMS-1; f > -1; f--)
      if (algorithm[f]->id == opt->hdr.id)
        break;

    disp = f == -1 ? "" : (*algorithm[f]->Disp)(opt);
    if (disp == NULL)
      disp = "";

    log_Printf(LogCCP, " %s[%d] %s\n", protoname(opt->hdr.id),
               opt->hdr.len, disp);

    if (f == -1) {
      /* Don't understand that :-( */
      if (mode_type == MODE_REQ) {
        ccp->my_reject |= (1 << opt->hdr.id);
        fsm_rej(dec, opt);
      }
    } else {
      struct ccp_opt *o;

      switch (mode_type) {
      case MODE_REQ:
        if (IsAccepted(ccp->cfg.neg[algorithm[f]->Neg]) &&
            (*algorithm[f]->Usable)(fp) &&
            ccp->in.algorithm == -1) {
          memcpy(&ccp->in.opt, opt, opt->hdr.len);
          switch ((*algorithm[f]->i.Set)(fp->bundle, &ccp->in.opt, &ccp->cfg)) {
          case MODE_REJ:
            fsm_rej(dec, &ccp->in.opt);
            break;
          case MODE_NAK:
            fsm_nak(dec, &ccp->in.opt);
            break;
          case MODE_ACK:
            fsm_ack(dec, &ccp->in.opt);
            ccp->his_proto = opt->hdr.id;
            ccp->in.algorithm = (int)f;		/* This one'll do :-) */
            break;
          }
        } else {
          fsm_rej(dec, opt);
        }
        break;
      case MODE_NAK:
        for (o = ccp->out.opt; o != NULL; o = o->next)
          if (o->val.hdr.id == opt->hdr.id)
            break;
        if (o == NULL)
          log_Printf(LogCCP, "%s: Warning: Ignoring peer NAK of unsent"
                     " option\n", fp->link->name);
        else {
          memcpy(&o->val, opt, opt->hdr.len);
          if ((*algorithm[f]->o.Set)(fp->bundle, &o->val, &ccp->cfg) ==
              MODE_ACK)
            ccp->my_proto = algorithm[f]->id;
          else {
            ccp->his_reject |= (1 << opt->hdr.id);
            ccp->my_proto = -1;
            if (algorithm[f]->Required(fp)) {
              log_Printf(LogWARN, "%s: Cannot understand peers (required)"
                         " %s negotiation\n", fp->link->name,
                         protoname(algorithm[f]->id));
              fsm_Close(&fp->link->lcp.fsm);
            }
          }
        }
        break;
      case MODE_REJ:
        ccp->his_reject |= (1 << opt->hdr.id);
        ccp->my_proto = -1;
        if (algorithm[f]->Required(fp)) {
          log_Printf(LogWARN, "%s: Peer rejected (required) %s negotiation\n",
                     fp->link->name, protoname(algorithm[f]->id));
          fsm_Close(&fp->link->lcp.fsm);
        }
        break;
      }
    }
  }

  if (mode_type != MODE_NOP) {
    fsm_opt_normalise(dec);
    if (dec->rejend != dec->rej || dec->nakend != dec->nak) {
      if (ccp->in.state == NULL) {
        ccp->his_proto = -1;
        ccp->in.algorithm = -1;
      }
    }
  }
}
Exemple #5
0
struct mbuf *
lqr_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
{
  struct physical *p = link2physical(l);
  struct lcp *lcp = p->hdlc.lqm.owner;
  int len;

  if (p == NULL) {
    log_Printf(LogERROR, "lqr_Input: Not a physical link - dropped\n");
    m_freem(bp);
    return NULL;
  }

  len = m_length(bp);
  if (len != sizeof(struct lqrdata))
    log_Printf(LogWARN, "lqr_Input: Got packet size %d, expecting %ld !\n",
              len, (long)sizeof(struct lqrdata));
  else if (!IsAccepted(l->lcp.cfg.lqr) && !(p->hdlc.lqm.method & LQM_LQR)) {
    bp = m_pullup(proto_Prepend(bp, PROTO_LQR, 0, 0));
    lcp_SendProtoRej(lcp, MBUF_CTOP(bp), bp->m_len);
  } else {
    struct lqrdata *lqr;

    bp = m_pullup(bp);
    lqr = (struct lqrdata *)MBUF_CTOP(bp);
    if (ntohl(lqr->MagicNumber) != lcp->his_magic)
      log_Printf(LogWARN, "lqr_Input: magic 0x%08lx is wrong,"
                 " expecting 0x%08lx\n",
		 (u_long)ntohl(lqr->MagicNumber), (u_long)lcp->his_magic);
    else {
      struct lqrdata lastlqr;
 
      memcpy(&lastlqr, &p->hdlc.lqm.lqr.peer, sizeof lastlqr);
      lqr_ChangeOrder(lqr, &p->hdlc.lqm.lqr.peer);
      lqr_Dump(l->name, "Input", &p->hdlc.lqm.lqr.peer);
      /* we have received an LQR from our peer */
      p->hdlc.lqm.lqr.resent = 0;

      /* Snapshot our state when the LQR packet was received */
      memcpy(&p->hdlc.lqm.lqr.prevSave, &p->hdlc.lqm.lqr.Save,
             sizeof p->hdlc.lqm.lqr.prevSave);
      p->hdlc.lqm.lqr.Save.InLQRs = ++p->hdlc.lqm.lqr.InLQRs;
      p->hdlc.lqm.lqr.Save.InPackets = p->hdlc.lqm.ifInUniPackets;
      p->hdlc.lqm.lqr.Save.InDiscards = p->hdlc.lqm.ifInDiscards;
      p->hdlc.lqm.lqr.Save.InErrors = p->hdlc.lqm.ifInErrors;
      p->hdlc.lqm.lqr.Save.InOctets = p->hdlc.lqm.lqr.InGoodOctets;

      lqr_Analyse(&p->hdlc, &lastlqr, &p->hdlc.lqm.lqr.peer);

      /*
       * Generate an LQR response if we're not running an LQR timer OR
       * two successive LQR's PeerInLQRs are the same.
       */
      if (p->hdlc.lqm.timer.load == 0 || !(p->hdlc.lqm.method & LQM_LQR) ||
          (lastlqr.PeerInLQRs &&
           lastlqr.PeerInLQRs == p->hdlc.lqm.lqr.peer.PeerInLQRs))
        SendLqrData(lcp);
    }
  }
  m_freem(bp);
  return NULL;
}