aboutsummaryrefslogtreecommitdiffstats
path: root/pythoneggs.py
diff options
context:
space:
mode:
authorNeal Gompa <ngompa13@gmail.com>2017-08-06 18:42:21 -0400
committerNeal Gompa <ngompa13@gmail.com>2017-08-06 18:42:21 -0400
commit6e742165fccbb74b26676429e84db4eb0b5329cb (patch)
tree12f39ef21817751a79ba025b0998d7814733a29a /pythoneggs.py
parent95f93ec49c824c780fd43e67b22190b8f0f818ac (diff)
downloadrpm-setup-6e742165fccbb74b26676429e84db4eb0b5329cb.tar
rpm-setup-6e742165fccbb74b26676429e84db4eb0b5329cb.tar.gz
rpm-setup-6e742165fccbb74b26676429e84db4eb0b5329cb.tar.bz2
rpm-setup-6e742165fccbb74b26676429e84db4eb0b5329cb.tar.xz
rpm-setup-6e742165fccbb74b26676429e84db4eb0b5329cb.zip
Remove pythoneggs.py in favor of using upstreamed pythondistdeps.py
Diffstat (limited to 'pythoneggs.py')
-rwxr-xr-xpythoneggs.py192
1 files changed, 0 insertions, 192 deletions
diff --git a/pythoneggs.py b/pythoneggs.py
deleted file mode 100755
index a1c819b..0000000
--- a/pythoneggs.py
+++ /dev/null
@@ -1,192 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright 2010 Per Øyvind Karlsen <peroyvind@mandriva.org>
-#
-# This program is free software. It may be redistributed and/or modified under
-# the terms of the LGPL version 2.1 (or later).
-#
-# RPM5 python (egg) dependency generator.
-#
-
-from getopt import getopt
-from os.path import basename, dirname, isdir, sep, splitext
-from sys import argv, stderr, stdin, version
-from distutils.sysconfig import get_python_lib
-
-
-opts, args = getopt(argv[1:], 'hPRSCOE',
- ['help', 'provides', 'requires', 'suggests', 'conflicts', 'obsoletes', 'extras'])
-
-Provides = False
-Requires = False
-Suggests = False
-Conflicts = False
-Obsoletes = False
-Extras = False
-
-for o, a in opts:
- if o in ('-h', '--help'):
- print '-h, --help\tPrint help'
- print '-P, --provides\tPrint Provides'
- print '-R, --requires\tPrint Requires'
- print '-S, --suggests\tPrint Suggests'
- print '-C, --conflicts\tPrint Conflicts'
- print '-O, --obsoletes\tPrint Obsoletes (unused)'
- print '-E, --extras\tPrint Extras '
- exit(1)
- elif o in ('-P', '--provides'):
- Provides = True
- elif o in ('-R', '--requires'):
- Requires = True
- elif o in ('-S', '--suggests'):
- Suggests = True
- elif o in ('-C', '--conflicts'):
- Conflicts = True
- elif o in ('-O', '--obsoletes'):
- Obsoletes = True
- elif o in ('-E', '--extras'):
- Extras = True
-
-if Requires:
- py_abi = True
-else:
- py_abi = False
-py_deps = {}
-if args:
- files = args
-else:
- files = stdin.readlines()
-for f in files:
- f = f.strip()
- lower = f.lower()
- name = 'python(abi)'
- # add dependency based on path, versioned if within versioned python directory
- if py_abi and (lower.endswith('.py') or lower.endswith('.pyc') or lower.endswith('.pyo')):
- if not name in py_deps:
- py_deps[name] = []
- purelib = get_python_lib(standard_lib=1, plat_specific=0).split(version[:3])[0]
- platlib = get_python_lib(standard_lib=1, plat_specific=1).split(version[:3])[0]
- for lib in (purelib, platlib):
- if lib in f:
- spec = ('==',f.split(lib)[1].split(sep)[0])
- if not spec in py_deps[name]:
- py_deps[name].append(spec)
- parent_name = dirname(f)
- # Determine provide, requires, conflicts & suggests based on egg metadata
- file_match = lower.endswith('.egg') or \
- lower.endswith('.egg-info') or \
- lower.endswith('.egg-link')
- dir_match = parent_name.endswith('.egg') or \
- parent_name.endswith('.egg-info') or \
- parent_name.endswith('.egg-link')
- if file_match or dir_match:
- # This import is very slow, so only do it if needed
- from pkg_resources import Distribution, FileMetadata, PathMetadata
- dist_name = basename(f)
- if dir_match:
- path_item = dirname(parent_name)
- metadata = PathMetadata(path_item, parent_name)
- else:
- path_item = f
- if isdir(f):
- metadata = PathMetadata(parent_name, f)
- else:
- metadata = FileMetadata(f)
- dist = Distribution.from_location(path_item, dist_name, metadata)
- if not dist.py_version:
- continue
- py_major = dist.py_version[:1]
- if Provides:
- # If egg metadata says package name is python, we provide python(abi)
- if dist.key == 'python':
- name = 'python(abi)'
- if not name in py_deps:
- py_deps[name] = []
- py_deps[name].append(('==', dist.py_version))
- name = 'pythonegg(%s)(%s)' % (py_major, dist.key)
- if not name in py_deps:
- py_deps[name] = []
- if dist.version:
- spec = ('==', dist.version)
- if not spec in py_deps[name]:
- py_deps[name].append(spec)
- if Requires or (Suggests and dist.extras):
- name = 'python(abi)'
- # If egg metadata says package name is python, we don't add dependency on python(abi)
- if dist.key == 'python':
- py_abi = False
- if name in py_deps:
- py_deps.pop(name)
- elif py_abi and dist.py_version:
- if not name in py_deps:
- py_deps[name] = []
- spec = ('==', dist.py_version)
- if not spec in py_deps[name]:
- py_deps[name].append(spec)
- deps = dist.requires()
- if Suggests:
- depsextras = dist.requires(extras=dist.extras)
- if not Requires:
- for dep in reversed(depsextras):
- if dep in deps:
- depsextras.remove(dep)
- deps = depsextras
- # add requires/suggests based on egg metadata
- for dep in deps:
- name = 'pythonegg(%s)(%s)' % (py_major, dep.key)
- for spec in dep.specs:
- if spec[0] != '!=':
- if not name in py_deps:
- py_deps[name] = []
- if not spec in py_deps[name]:
- py_deps[name].append(spec)
- if not dep.specs:
- py_deps[name] = []
- # Unused, for automatic sub-package generation based on 'extras' from egg metadata
- # TODO: implement in rpm later, or...?
- if Extras:
- deps = dist.requires()
- extras = dist.extras
- print extras
- for extra in extras:
- print '%%package\textras-%s' % extra
- print 'Summary:\t%s extra for %s python egg' % (extra, dist.key)
- print 'Group:\t\tDevelopment/Python'
- depsextras = dist.requires(extras=[extra])
- for dep in reversed(depsextras):
- if dep in deps:
- depsextras.remove(dep)
- deps = depsextras
- for dep in deps:
- for spec in dep.specs:
- if spec[0] == '!=':
- print 'Conflicts:\t%s %s %s' % (dep.key, '==', spec[1])
- else:
- print 'Requires:\t%s %s %s' % (dep.key, spec[0], spec[1])
- print '%%description\t%s' % extra
- print '%s extra for %s python egg' % (extra, dist.key)
- print '%%files\t\textras-%s\n' % extra
- if Conflicts:
- # Should we really add conflicts for extras?
- # Creating a meta package per extra with suggests on, which has
- # the requires/conflicts in stead might be a better solution...
- for dep in dist.requires(extras=dist.extras):
- name = dep.key
- for spec in dep.specs:
- if spec[0] == '!=':
- if not name in py_deps:
- py_deps[name] = []
- spec = ('==', spec[1])
- if not spec in py_deps[name]:
- py_deps[name].append(spec)
-names = py_deps.keys()
-names.sort()
-for name in names:
- if py_deps[name]:
- # Print out versioned provides, requires, suggests, conflicts
- for spec in py_deps[name]:
- print '%s %s %s' % (name, spec[0], spec[1])
- else:
- # Print out unversioned provides, requires, suggests, conflicts
- print name
'#n412'>412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762
/*
 * fsm.c - {Link, IP} Control Protocol Finite State Machine.
 *
 * Copyright (c) 1989 Carnegie Mellon University.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by Carnegie Mellon University.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#define RCSID	"$Id$"

/*
 * TODO:
 * Randomize fsm id on link/init.
 * Deal with variable outgoing MTU.
 */

#include <stdio.h>
#include <string.h>
#include <sys/types.h>

#include "pppd.h"
#include "fsm.h"

static const char rcsid[] = RCSID;

static void fsm_timeout __P((void *));
static void fsm_rconfreq __P((fsm *, int, u_char *, int));
static void fsm_rconfack __P((fsm *, int, u_char *, int));
static void fsm_rconfnakrej __P((fsm *, int, int, u_char *, int));
static void fsm_rtermreq __P((fsm *, int, u_char *, int));
static void fsm_rtermack __P((fsm *));
static void fsm_rcoderej __P((fsm *, u_char *, int));
static void fsm_sconfreq __P((fsm *, int));

#define PROTO_NAME(f)	((f)->callbacks->proto_name)

int peer_mru[NUM_PPP];


/*
 * fsm_init - Initialize fsm.
 *
 * Initialize fsm state.
 */
void
fsm_init(f)
    fsm *f;
{
    f->state = INITIAL;
    f->flags = 0;
    f->id = 0;				/* XXX Start with random id? */
    f->timeouttime = DEFTIMEOUT;
    f->maxconfreqtransmits = DEFMAXCONFREQS;
    f->maxtermtransmits = DEFMAXTERMREQS;
    f->maxnakloops = DEFMAXNAKLOOPS;
    f->term_reason_len = 0;
}


/*
 * fsm_lowerup - The lower layer is up.
 */
void
fsm_lowerup(f)
    fsm *f;
{
    switch( f->state ){
    case INITIAL:
	f->state = CLOSED;
	break;

    case STARTING:
	if( f->flags & OPT_SILENT )
	    f->state = STOPPED;
	else {
	    /* Send an initial configure-request */
	    fsm_sconfreq(f, 0);
	    f->state = REQSENT;
	}
	break;

    default:
	FSMDEBUG(("%s: Up event in state %d!", PROTO_NAME(f), f->state));
    }
}


/*
 * fsm_lowerdown - The lower layer is down.
 *
 * Cancel all timeouts and inform upper layers.
 */
void
fsm_lowerdown(f)
    fsm *f;
{
    switch( f->state ){
    case CLOSED:
	f->state = INITIAL;
	break;

    case STOPPED:
	f->state = STARTING;
	if( f->callbacks->starting )
	    (*f->callbacks->starting)(f);
	break;

    case CLOSING:
	f->state = INITIAL;
	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
	break;

    case STOPPING:
    case REQSENT:
    case ACKRCVD:
    case ACKSENT:
	f->state = STARTING;
	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
	break;

    case OPENED:
	if( f->callbacks->down )
	    (*f->callbacks->down)(f);
	f->state = STARTING;
	break;

    default:
	FSMDEBUG(("%s: Down event in state %d!", PROTO_NAME(f), f->state));
    }
}


/*
 * fsm_open - Link is allowed to come up.
 */
void
fsm_open(f)
    fsm *f;
{
    switch( f->state ){
    case INITIAL:
	f->state = STARTING;
	if( f->callbacks->starting )
	    (*f->callbacks->starting)(f);
	break;

    case CLOSED:
	if( f->flags & OPT_SILENT )
	    f->state = STOPPED;
	else {
	    /* Send an initial configure-request */
	    fsm_sconfreq(f, 0);
	    f->state = REQSENT;
	}
	break;

    case CLOSING:
	f->state = STOPPING;
	/* fall through */
    case STOPPED:
    case OPENED:
	if( f->flags & OPT_RESTART ){
	    fsm_lowerdown(f);
	    fsm_lowerup(f);
	}
	break;
    }
}


/*
 * fsm_close - Start closing connection.
 *
 * Cancel timeouts and either initiate close or possibly go directly to
 * the CLOSED state.
 */
void
fsm_close(f, reason)
    fsm *f;
    char *reason;
{
    f->term_reason = reason;
    f->term_reason_len = (reason == NULL? 0: strlen(reason));
    switch( f->state ){
    case STARTING:
	f->state = INITIAL;
	break;
    case STOPPED:
	f->state = CLOSED;
	break;
    case STOPPING:
	f->state = CLOSING;
	break;

    case REQSENT:
    case ACKRCVD:
    case ACKSENT:
    case OPENED:
	if( f->state != OPENED )
	    UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
	else if( f->callbacks->down )
	    (*f->callbacks->down)(f);	/* Inform upper layers we're down */

	/* Init restart counter, send Terminate-Request */
	f->retransmits = f->maxtermtransmits;
	fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
		  (u_char *) f->term_reason, f->term_reason_len);
	TIMEOUT(fsm_timeout, f, f->timeouttime);
	--f->retransmits;

	f->state = CLOSING;
	break;
    }
}


/*
 * fsm_timeout - Timeout expired.
 */
static void
fsm_timeout(arg)
    void *arg;
{
    fsm *f = (fsm *) arg;

    switch (f->state) {
    case CLOSING:
    case STOPPING:
	if( f->retransmits <= 0 ){
	    /*
	     * We've waited for an ack long enough.  Peer probably heard us.
	     */
	    f->state = (f->state == CLOSING)? CLOSED: STOPPED;
	    if( f->callbacks->finished )
		(*f->callbacks->finished)(f);
	} else {
	    /* Send Terminate-Request */
	    fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
		      (u_char *) f->term_reason, f->term_reason_len);
	    TIMEOUT(fsm_timeout, f, f->timeouttime);
	    --f->retransmits;
	}
	break;

    case REQSENT:
    case ACKRCVD:
    case ACKSENT:
	if (f->retransmits <= 0) {
	    warn("%s: timeout sending Config-Requests\n", PROTO_NAME(f));
	    f->state = STOPPED;
	    if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished )
		(*f->callbacks->finished)(f);

	} else {
	    /* Retransmit the configure-request */
	    if (f->callbacks->retransmit)
		(*f->callbacks->retransmit)(f);
	    fsm_sconfreq(f, 1);		/* Re-send Configure-Request */
	    if( f->state == ACKRCVD )
		f->state = REQSENT;
	}
	break;

    default:
	FSMDEBUG(("%s: Timeout event in state %d!", PROTO_NAME(f), f->state));
    }
}


/*
 * fsm_input - Input packet.
 */
void
fsm_input(f, inpacket, l)
    fsm *f;
    u_char *inpacket;
    int l;
{
    u_char *inp;
    u_char code, id;
    int len;

    /*
     * Parse header (code, id and length).
     * If packet too short, drop it.
     */
    inp = inpacket;
    if (l < HEADERLEN) {
	FSMDEBUG(("fsm_input(%x): Rcvd short header.", f->protocol));
	return;
    }
    GETCHAR(code, inp);
    GETCHAR(id, inp);
    GETSHORT(len, inp);
    if (len < HEADERLEN) {
	FSMDEBUG(("fsm_input(%x): Rcvd illegal length.", f->protocol));
	return;
    }
    if (len > l) {
	FSMDEBUG(("fsm_input(%x): Rcvd short packet.", f->protocol));
	return;
    }
    len -= HEADERLEN;		/* subtract header length */

    if( f->state == INITIAL || f->state == STARTING ){
	FSMDEBUG(("fsm_input(%x): Rcvd packet in state %d.",
		  f->protocol, f->state));
	return;
    }

    /*
     * Action depends on code.
     */
    switch (code) {
    case CONFREQ:
	fsm_rconfreq(f, id, inp, len);
	break;
    
    case CONFACK:
	fsm_rconfack(f, id, inp, len);
	break;
    
    case CONFNAK:
    case CONFREJ:
	fsm_rconfnakrej(f, code, id, inp, len);
	break;
    
    case TERMREQ:
	fsm_rtermreq(f, id, inp, len);
	break;
    
    case TERMACK:
	fsm_rtermack(f);
	break;
    
    case CODEREJ:
	fsm_rcoderej(f, inp, len);
	break;
    
    default:
	if( !f->callbacks->extcode
	   || !(*f->callbacks->extcode)(f, code, id, inp, len) )
	    fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
	break;
    }
}


/*
 * fsm_rconfreq - Receive Configure-Request.
 */
static void
fsm_rconfreq(f, id, inp, len)
    fsm *f;
    u_char id;
    u_char *inp;
    int len;
{
    int code, reject_if_disagree;

    switch( f->state ){
    case CLOSED:
	/* Go away, we're closed */
	fsm_sdata(f, TERMACK, id, NULL, 0);
	return;
    case CLOSING:
    case STOPPING:
	return;

    case OPENED:
	/* Go down and restart negotiation */
	if( f->callbacks->down )
	    (*f->callbacks->down)(f);	/* Inform upper layers */
	fsm_sconfreq(f, 0);		/* Send initial Configure-Request */
	break;

    case STOPPED:
	/* Negotiation started by our peer */
	fsm_sconfreq(f, 0);		/* Send initial Configure-Request */
	f->state = REQSENT;
	break;
    }

    /*
     * Pass the requested configuration options
     * to protocol-specific code for checking.
     */
    if (f->callbacks->reqci){		/* Check CI */
	reject_if_disagree = (f->nakloops >= f->maxnakloops);
	code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
    } else if (len)
	code = CONFREJ;			/* Reject all CI */
    else
	code = CONFACK;

    /* send the Ack, Nak or Rej to the peer */
    fsm_sdata(f, code, id, inp, len);

    if (code == CONFACK) {
	if (f->state == ACKRCVD) {
	    UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
	    f->state = OPENED;
	    if (f->callbacks->up)
		(*f->callbacks->up)(f);	/* Inform upper layers */
	} else
	    f->state = ACKSENT;
	f->nakloops = 0;

    } else {
	/* we sent CONFACK or CONFREJ */
	if (f->state != ACKRCVD)
	    f->state = REQSENT;
	if( code == CONFNAK )
	    ++f->nakloops;
    }
}


/*
 * fsm_rconfack - Receive Configure-Ack.
 */
static void
fsm_rconfack(f, id, inp, len)
    fsm *f;
    int id;
    u_char *inp;
    int len;
{
    if (id != f->reqid || f->seen_ack)		/* Expected id? */
	return;					/* Nope, toss... */
    if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len):
	  (len == 0)) ){
	/* Ack is bad - ignore it */
	error("Received bad configure-ack: %P", inp, len);
	return;
    }
    f->seen_ack = 1;

    switch (f->state) {
    case CLOSED:
    case STOPPED:
	fsm_sdata(f, TERMACK, id, NULL, 0);
	break;

    case REQSENT:
	f->state = ACKRCVD;
	f->retransmits = f->maxconfreqtransmits;
	break;

    case ACKRCVD:
	/* Huh? an extra valid Ack? oh well... */
	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
	fsm_sconfreq(f, 0);
	f->state = REQSENT;
	break;

    case ACKSENT:
	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
	f->state = OPENED;
	f->retransmits = f->maxconfreqtransmits;
	if (f->callbacks->up)
	    (*f->callbacks->up)(f);	/* Inform upper layers */
	break;

    case OPENED:
	/* Go down and restart negotiation */
	if (f->callbacks->down)
	    (*f->callbacks->down)(f);	/* Inform upper layers */
	fsm_sconfreq(f, 0);		/* Send initial Configure-Request */
	f->state = REQSENT;
	break;
    }
}


/*
 * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
 */
static void
fsm_rconfnakrej(f, code, id, inp, len)
    fsm *f;
    int code, id;
    u_char *inp;
    int len;
{
    int (*proc) __P((fsm *, u_char *, int));
    int ret;

    if (id != f->reqid || f->seen_ack)	/* Expected id? */
	return;				/* Nope, toss... */
    proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
    if (!proc || !(ret = proc(f, inp, len))) {
	/* Nak/reject is bad - ignore it */
	error("Received bad configure-nak/rej: %P", inp, len);
	return;
    }
    f->seen_ack = 1;

    switch (f->state) {
    case CLOSED:
    case STOPPED:
	fsm_sdata(f, TERMACK, id, NULL, 0);
	break;

    case REQSENT:
    case ACKSENT:
	/* They didn't agree to what we wanted - try another request */
	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
	if (ret < 0)
	    f->state = STOPPED;		/* kludge for stopping CCP */
	else
	    fsm_sconfreq(f, 0);		/* Send Configure-Request */
	break;

    case ACKRCVD:
	/* Got a Nak/reject when we had already had an Ack?? oh well... */
	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
	fsm_sconfreq(f, 0);
	f->state = REQSENT;
	break;

    case OPENED:
	/* Go down and restart negotiation */
	if (f->callbacks->down)
	    (*f->callbacks->down)(f);	/* Inform upper layers */
	fsm_sconfreq(f, 0);		/* Send initial Configure-Request */
	f->state = REQSENT;
	break;
    }
}


/*
 * fsm_rtermreq - Receive Terminate-Req.
 */
static void
fsm_rtermreq(f, id, p, len)
    fsm *f;
    int id;
    u_char *p;
    int len;
{
    switch (f->state) {
    case ACKRCVD:
    case ACKSENT:
	f->state = REQSENT;		/* Start over but keep trying */
	break;

    case OPENED:
	if (len > 0) {
	    info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p);
	} else
	    info("%s terminated by peer", PROTO_NAME(f));
	if (f->callbacks->down)
	    (*f->callbacks->down)(f);	/* Inform upper layers */
	f->retransmits = 0;
	f->state = STOPPING;
	TIMEOUT(fsm_timeout, f, f->timeouttime);
	break;
    }

    fsm_sdata(f, TERMACK, id, NULL, 0);
}


/*
 * fsm_rtermack - Receive Terminate-Ack.
 */
static void
fsm_rtermack(f)
    fsm *f;
{
    switch (f->state) {
    case CLOSING:
	UNTIMEOUT(fsm_timeout, f);
	f->state = CLOSED;
	if( f->callbacks->finished )
	    (*f->callbacks->finished)(f);
	break;
    case STOPPING:
	UNTIMEOUT(fsm_timeout, f);
	f->state = STOPPED;
	if( f->callbacks->finished )
	    (*f->callbacks->finished)(f);
	break;

    case ACKRCVD:
	f->state = REQSENT;
	break;

    case OPENED:
	if (f->callbacks->down)
	    (*f->callbacks->down)(f);	/* Inform upper layers */
	fsm_sconfreq(f, 0);
	break;
    }
}


/*
 * fsm_rcoderej - Receive an Code-Reject.
 */
static void
fsm_rcoderej(f, inp, len)
    fsm *f;
    u_char *inp;
    int len;
{
    u_char code, id;

    if (len < HEADERLEN) {
	FSMDEBUG(("fsm_rcoderej: Rcvd short Code-Reject packet!"));
	return;
    }
    GETCHAR(code, inp);
    GETCHAR(id, inp);
    warn("%s: Rcvd Code-Reject for code %d, id %d", PROTO_NAME(f), code, id);

    if( f->state == ACKRCVD )
	f->state = REQSENT;
}


/*
 * fsm_protreject - Peer doesn't speak this protocol.
 *
 * Treat this as a catastrophic error (RXJ-).
 */
void
fsm_protreject(f)
    fsm *f;
{
    switch( f->state ){
    case CLOSING:
	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
	/* fall through */
    case CLOSED:
	f->state = CLOSED;
	if( f->callbacks->finished )
	    (*f->callbacks->finished)(f);
	break;

    case STOPPING:
    case REQSENT:
    case ACKRCVD:
    case ACKSENT:
	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
	/* fall through */
    case STOPPED:
	f->state = STOPPED;
	if( f->callbacks->finished )
	    (*f->callbacks->finished)(f);
	break;

    case OPENED:
	if( f->callbacks->down )
	    (*f->callbacks->down)(f);

	/* Init restart counter, send Terminate-Request */
	f->retransmits = f->maxtermtransmits;
	fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
		  (u_char *) f->term_reason, f->term_reason_len);
	TIMEOUT(fsm_timeout, f, f->timeouttime);
	--f->retransmits;

	f->state = STOPPING;
	break;

    default:
	FSMDEBUG(("%s: Protocol-reject event in state %d!",
		  PROTO_NAME(f), f->state));
    }
}


/*
 * fsm_sconfreq - Send a Configure-Request.
 */
static void
fsm_sconfreq(f, retransmit)
    fsm *f;
    int retransmit;
{
    u_char *outp;
    int cilen;

    if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){
	/* Not currently negotiating - reset options */
	if( f->callbacks->resetci )
	    (*f->callbacks->resetci)(f);
	f->nakloops = 0;
    }

    if( !retransmit ){
	/* New request - reset retransmission counter, use new ID */
	f->retransmits = f->maxconfreqtransmits;
	f->reqid = ++f->id;
    }

    f->seen_ack = 0;

    /*
     * Make up the request packet
     */
    outp = outpacket_buf + PPP_HDRLEN + HEADERLEN;
    if( f->callbacks->cilen && f->callbacks->addci ){
	cilen = (*f->callbacks->cilen)(f);
	if( cilen > peer_mru[f->unit] - HEADERLEN )
	    cilen = peer_mru[f->unit] - HEADERLEN;
	if (f->callbacks->addci)
	    (*f->callbacks->addci)(f, outp, &cilen);
    } else
	cilen = 0;

    /* send the request to our peer */
    fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);

    /* start the retransmit timer */
    --f->retransmits;
    TIMEOUT(fsm_timeout, f, f->timeouttime);
}


/*
 * fsm_sdata - Send some data.
 *
 * Used for all packets sent to our peer by this module.
 */
void
fsm_sdata(f, code, id, data, datalen)
    fsm *f;
    u_char code, id;
    u_char *data;
    int datalen;
{
    u_char *outp;
    int outlen;

    /* Adjust length to be smaller than MTU */
    outp = outpacket_buf;
    if (datalen > peer_mru[f->unit] - HEADERLEN)
	datalen = peer_mru[f->unit] - HEADERLEN;
    if (datalen && data != outp + PPP_HDRLEN + HEADERLEN)
	BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
    outlen = datalen + HEADERLEN;
    MAKEHEADER(outp, f->protocol);
    PUTCHAR(code, outp);
    PUTCHAR(id, outp);
    PUTSHORT(outlen, outp);
    output(f->unit, outpacket_buf, outlen + PPP_HDRLEN);
}