summaryrefslogtreecommitdiffstats
path: root/perl-install/standalone/drakups
Commit message (Expand)AuthorAgeFilesLines
* adapt to new nut doc pathOlivier Blin2007-07-271-1/+1
* re-sync after the big svn lossPascal Rigaux2007-04-251-2/+4
* don't have a useless empty hash in wizards objects, use the wizards hashOlivier Blin2006-01-031-6/+4
* minimal changes to make me and perl_checker happyPascal Rigaux2005-06-031-3/+3
* embedding cleanups resulting in reusing main window icon in sub dialogsThierry Vignaud2005-05-021-1/+1
* (add_device_wizard) set extra parameters if presentThierry Vignaud2005-03-211-2/+3
* (add_device_wizard) fix device path when manually adding an UPS (#12290)Thierry Vignaud2005-03-181-1/+4
* perl_checker fixesThierry Vignaud2005-02-241-5/+5
* fix reading UPS db: some UPS have the same name but differes in theThierry Vignaud2005-02-241-4/+4
* adapt to new Libconf APIThierry Vignaud2005-02-241-2/+2
* fix the various transient on {rwindow} (or even {window} ?) not working anymo...Pascal Rigaux2005-01-221-2/+2
* perl_checker compliancePascal Rigaux2004-10-141-11/+11
* in manual adding:Thierry Vignaud2004-10-051-3/+3
* write config in pure wizard modeThierry Vignaud2004-10-051-3/+11
* (writeconf) restart upsd daemonThierry Vignaud2004-10-051-0/+3
* install nut earlierThierry Vignaud2004-10-051-1/+2
* fix installing nutThierry Vignaud2004-10-051-1/+1
* add --wizard option in order to directly run the wizardThierry Vignaud2004-10-011-1/+8
* do not show banner when embeddedThierry Vignaud2004-10-011-1/+1
* (add_device_wizard) refix list refreshing on UPS addingThierry Vignaud2004-09-241-0/+1
* (add_device_wizard) default to automatic detectionThierry Vignaud2004-09-201-1/+1
* perl_checker cleanupThierry Vignaud2004-09-171-1/+1
* remove debug message :-)Thierry Vignaud2004-09-171-2/+0
* refresh UPS list when adding a new UPS though the add wizardThierry Vignaud2004-09-171-3/+11
* (add_device_wizard) fix automatically detect/add an UPSThierry Vignaud2004-09-171-0/+1
* (add_device_wizard) fix device list in wizardThierry Vignaud2004-09-161-1/+1
* perl_checker cleanupsThierry Vignaud2004-09-161-7/+7
* typo fixThierry Vignaud2004-08-241-1/+1
* fixed English typoPablo Saratxaga2004-08-201-1/+1
* (add_device_wizard) fix string (Joe Brower)Thierry Vignaud2004-08-031-1/+1
* clean spacingThierry Vignaud2004-08-021-2/+2
* (add_device_wizard) fix stringThierry Vignaud2004-08-021-1/+1
* introduce ->ensure_binary_is_installed and use itPascal Rigaux2004-08-021-1/+1
* several typos fixFunda Wang2004-08-011-1/+1
* revert ugly code printing "This program cannot be run in console mode",Pascal Rigaux2004-07-011-10/+1
* Some standalone tools don't compile when run from consoleRafael Garcia-Suarez2004-06-241-1/+10
* corrected drakups against new libconf 0.32damien2004-04-071-3/+3
* use std bannerThierry Vignaud2004-03-171-1/+4
* use new $ugtk2::wm_icon for x11 iconThierry Vignaud2004-03-171-1/+1
* set x11 icoThierry Vignaud2004-03-161-0/+2
* fix wizard iconThierry Vignaud2004-03-021-1/+1
* reuse create_okcancel() in ordet to get some std button layoutThierry Vignaud2004-01-151-9/+10
* remove useless menu infrastuctureThierry Vignaud2004-01-151-18/+1
* only die if an error actually happened...Thierry Vignaud2004-01-051-1/+1
* use new wizards APIThierry Vignaud2004-01-051-1/+1
* get rid of val_refThierry Vignaud2004-01-051-7/+9
* wip (for strings & interfaces)Thierry Vignaud2003-12-221-15/+374
* upsdrvctl start will fail if section name contains spacesThierry Vignaud2003-11-261-0/+1
* - configure properly usb & serial connected mge devicesThierry Vignaud2003-11-261-49/+17
* - for now, check new devices against description (later with port too)Thierry Vignaud2003-10-311-9/+9
='n628' href='#n628'>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 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878
/*
 * ppp_ahdlc.c - STREAMS module for doing PPP asynchronous HDLC.
 *
 * Re-written by Adi Masputra <adi.masputra@sun.com>, based on 
 * the original ppp_ahdlc.c
 *
 * Copyright (c) 2000 by Sun Microsystems, Inc.
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation is hereby granted, provided that the above copyright
 * notice appears in all copies.  
 *
 * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT.  SUN SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
 *
 * Copyright (c) 1994 The Australian National University.
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation is hereby granted, provided that the above copyright
 * notice appears in all copies.  This software is provided without any
 * warranty, express or implied. The Australian National University
 * makes no representations about the suitability of this software for
 * any purpose.
 *
 * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 *
 * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
 * OR MODIFICATIONS.
 *
 * $Id$
 */

/*
 * This file is used under Solaris 2, SVR4, SunOS 4, and Digital UNIX.
 */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stream.h>
#include <sys/errno.h>

#ifdef SVR4
#include <sys/conf.h>
#include <sys/kmem.h>
#include <sys/cmn_err.h>
#include <sys/ddi.h>
#else
#include <sys/user.h>
#ifdef __osf__
#include <sys/cmn_err.h>
#endif
#endif /* SVR4 */

#include <net/ppp_defs.h>
#include <net/pppio.h>
#include "ppp_mod.h"

/*
 * Right now, mutex is only enabled for Solaris 2.x
 */
#if defined(SOL2)
#define USE_MUTEX
#endif /* SOL2 */

/*
 * intpointer_t and uintpointer_t are signed and unsigned integer types 
 * large enough to hold any data pointer; that is, data pointers can be 
 * assigned into or from these integer types without losing precision.
 * On recent Solaris releases, these types are defined in sys/int_types.h,
 * but not on SunOS 4.x or the earlier Solaris versions.
 */
#if defined(_LP64) || defined(_I32LPx)
typedef long                    intpointer_t;
typedef unsigned long           uintpointer_t;
#else
typedef int                     intpointer_t;
typedef unsigned int            uintpointer_t;
#endif

MOD_OPEN_DECL(ahdlc_open);
MOD_CLOSE_DECL(ahdlc_close);
static int ahdlc_wput __P((queue_t *, mblk_t *));
static int ahdlc_rput __P((queue_t *, mblk_t *));
static void ahdlc_encode __P((queue_t *, mblk_t *));
static void ahdlc_decode __P((queue_t *, mblk_t *));
static int msg_byte __P((mblk_t *, unsigned int));

#if defined(SOL2)
/*
 * Don't send HDLC start flag is last transmit is within 1.5 seconds -
 * FLAG_TIME is defined is microseconds
 */
#define FLAG_TIME   1500
#define ABS(x)	    (x >= 0 ? x : (-x))
#endif /* SOL2 */

/*
 * Extract byte i of message mp 
 */
#define MSG_BYTE(mp, i)	((i) < (mp)->b_wptr - (mp)->b_rptr? (mp)->b_rptr[i]: \
			 msg_byte((mp), (i)))

/* 
 * Is this LCP packet one we have to transmit using LCP defaults? 
 */
#define LCP_USE_DFLT(mp)	(1 <= (code = MSG_BYTE((mp), 4)) && code <= 7)

/*
 * Standard STREAMS declarations
 */
static struct module_info minfo = {
    0x7d23, "ppp_ahdl", 0, INFPSZ, 32768, 512
};

static struct qinit rinit = {
    ahdlc_rput, NULL, ahdlc_open, ahdlc_close, NULL, &minfo, NULL
};

static struct qinit winit = {
    ahdlc_wput, NULL, NULL, NULL, NULL, &minfo, NULL
};

#if defined(SVR4) && !defined(SOL2)
int phdldevflag = 0;
#define ppp_ahdlcinfo phdlinfo
#endif /* defined(SVR4) && !defined(SOL2) */

struct streamtab ppp_ahdlcinfo = {
    &rinit,			    /* ptr to st_rdinit */
    &winit,			    /* ptr to st_wrinit */
    NULL,			    /* ptr to st_muxrinit */
    NULL,			    /* ptr to st_muxwinit */
#if defined(SUNOS4)
    NULL			    /* ptr to ptr to st_modlist */
#endif /* SUNOS4 */
};

#if defined(SUNOS4)
int ppp_ahdlc_count = 0;	    /* open counter */
#endif /* SUNOS4 */

/*
 * Per-stream state structure
 */
typedef struct ahdlc_state {
#if defined(USE_MUTEX)
    kmutex_t	    lock;		    /* lock for this structure */
#endif /* USE_MUTEX */
    int		    flags;		    /* link flags */
    mblk_t	    *rx_buf;		    /* ptr to receive buffer */
    int		    rx_buf_size;	    /* receive buffer size */
    ushort_t	    infcs;		    /* calculated rx HDLC FCS */
    u_int32_t	    xaccm[8];		    /* 256-bit xmit ACCM */
    u_int32_t	    raccm;		    /* 32-bit rcv ACCM */
    int		    mtu;		    /* interface MTU */
    int		    mru;		    /* link MRU */
    int		    unit;		    /* current PPP unit number */
    struct pppstat  stats;		    /* statistic structure */
#if defined(SOL2)
    clock_t	    flag_time;		    /* time in usec between flags */
    clock_t	    lbolt;		    /* last updated lbolt */
#endif /* SOL2 */
} ahdlc_state_t;

/*
 * Values for flags 
 */
#define ESCAPED		0x100	/* last saw escape char on input */
#define IFLUSH		0x200	/* flushing input due to error */

/* 
 * RCV_B7_1, etc., defined in net/pppio.h, are stored in flags also. 
 */
#define RCV_FLAGS	(RCV_B7_1|RCV_B7_0|RCV_ODDP|RCV_EVNP)

/*
 * FCS lookup table as calculated by genfcstab.
 */
static u_short fcstab[256] = {
	0x0000,	0x1189,	0x2312,	0x329b,	0x4624,	0x57ad,	0x6536,	0x74bf,
	0x8c48,	0x9dc1,	0xaf5a,	0xbed3,	0xca6c,	0xdbe5,	0xe97e,	0xf8f7,
	0x1081,	0x0108,	0x3393,	0x221a,	0x56a5,	0x472c,	0x75b7,	0x643e,
	0x9cc9,	0x8d40,	0xbfdb,	0xae52,	0xdaed,	0xcb64,	0xf9ff,	0xe876,
	0x2102,	0x308b,	0x0210,	0x1399,	0x6726,	0x76af,	0x4434,	0x55bd,
	0xad4a,	0xbcc3,	0x8e58,	0x9fd1,	0xeb6e,	0xfae7,	0xc87c,	0xd9f5,
	0x3183,	0x200a,	0x1291,	0x0318,	0x77a7,	0x662e,	0x54b5,	0x453c,
	0xbdcb,	0xac42,	0x9ed9,	0x8f50,	0xfbef,	0xea66,	0xd8fd,	0xc974,
	0x4204,	0x538d,	0x6116,	0x709f,	0x0420,	0x15a9,	0x2732,	0x36bb,
	0xce4c,	0xdfc5,	0xed5e,	0xfcd7,	0x8868,	0x99e1,	0xab7a,	0xbaf3,
	0x5285,	0x430c,	0x7197,	0x601e,	0x14a1,	0x0528,	0x37b3,	0x263a,
	0xdecd,	0xcf44,	0xfddf,	0xec56,	0x98e9,	0x8960,	0xbbfb,	0xaa72,
	0x6306,	0x728f,	0x4014,	0x519d,	0x2522,	0x34ab,	0x0630,	0x17b9,
	0xef4e,	0xfec7,	0xcc5c,	0xddd5,	0xa96a,	0xb8e3,	0x8a78,	0x9bf1,
	0x7387,	0x620e,	0x5095,	0x411c,	0x35a3,	0x242a,	0x16b1,	0x0738,
	0xffcf,	0xee46,	0xdcdd,	0xcd54,	0xb9eb,	0xa862,	0x9af9,	0x8b70,
	0x8408,	0x9581,	0xa71a,	0xb693,	0xc22c,	0xd3a5,	0xe13e,	0xf0b7,
	0x0840,	0x19c9,	0x2b52,	0x3adb,	0x4e64,	0x5fed,	0x6d76,	0x7cff,
	0x9489,	0x8500,	0xb79b,	0xa612,	0xd2ad,	0xc324,	0xf1bf,	0xe036,
	0x18c1,	0x0948,	0x3bd3,	0x2a5a,	0x5ee5,	0x4f6c,	0x7df7,	0x6c7e,
	0xa50a,	0xb483,	0x8618,	0x9791,	0xe32e,	0xf2a7,	0xc03c,	0xd1b5,
	0x2942,	0x38cb,	0x0a50,	0x1bd9,	0x6f66,	0x7eef,	0x4c74,	0x5dfd,
	0xb58b,	0xa402,	0x9699,	0x8710,	0xf3af,	0xe226,	0xd0bd,	0xc134,
	0x39c3,	0x284a,	0x1ad1,	0x0b58,	0x7fe7,	0x6e6e,	0x5cf5,	0x4d7c,
	0xc60c,	0xd785,	0xe51e,	0xf497,	0x8028,	0x91a1,	0xa33a,	0xb2b3,
	0x4a44,	0x5bcd,	0x6956,	0x78df,	0x0c60,	0x1de9,	0x2f72,	0x3efb,
	0xd68d,	0xc704,	0xf59f,	0xe416,	0x90a9,	0x8120,	0xb3bb,	0xa232,
	0x5ac5,	0x4b4c,	0x79d7,	0x685e,	0x1ce1,	0x0d68,	0x3ff3,	0x2e7a,
	0xe70e,	0xf687,	0xc41c,	0xd595,	0xa12a,	0xb0a3,	0x8238,	0x93b1,
	0x6b46,	0x7acf,	0x4854,	0x59dd,	0x2d62,	0x3ceb,	0x0e70,	0x1ff9,
	0xf78f,	0xe606,	0xd49d,	0xc514,	0xb1ab,	0xa022,	0x92b9,	0x8330,
	0x7bc7,	0x6a4e,	0x58d5,	0x495c,	0x3de3,	0x2c6a,	0x1ef1,	0x0f78
};

static u_int32_t paritytab[8] =
{
	0x96696996, 0x69969669, 0x69969669, 0x96696996,
	0x69969669, 0x96696996, 0x96696996, 0x69969669
};

/*
 * STREAMS module open (entry) point
 */
MOD_OPEN(ahdlc_open)
{
    ahdlc_state_t   *state;

    /*
     * Return if it's already opened
     */
    if (q->q_ptr) {
	return 0;
    }

    /*
     * This can only be opened as a module
     */
    if (sflag != MODOPEN) {
	return 0;
    }

    state = (ahdlc_state_t *) ALLOC_NOSLEEP(sizeof(ahdlc_state_t));
    if (state == 0)
	OPEN_ERROR(ENOSR);
    bzero((caddr_t) state, sizeof(ahdlc_state_t));

    q->q_ptr	 = (caddr_t) state;
    WR(q)->q_ptr = (caddr_t) state;

#if defined(USE_MUTEX)
    mutex_init(&state->lock, NULL, MUTEX_DEFAULT, NULL);
    mutex_enter(&state->lock);
#endif /* USE_MUTEX */

    state->xaccm[0] = ~0;	    /* escape 0x00 through 0x1f */
    state->xaccm[3] = 0x60000000;   /* escape 0x7d and 0x7e */
    state->mru	    = PPP_MRU;	    /* default of 1500 bytes */
#if defined(SOL2)
    state->flag_time = drv_usectohz(FLAG_TIME);
#endif /* SOL2 */

#if defined(USE_MUTEX)
    mutex_exit(&state->lock);
#endif /* USE_MUTEX */	

#if defined(SUNOS4)
    ppp_ahdlc_count++;
#endif /* SUNOS4 */

    qprocson(q);
    
    return 0;
}

/*
 * STREAMS module close (exit) point
 */
MOD_CLOSE(ahdlc_close)
{
    ahdlc_state_t   *state;

    qprocsoff(q);

    state = (ahdlc_state_t *) q->q_ptr;

    if (state == 0) {
	DPRINT("state == 0 in ahdlc_close\n");
	return 0;
    }

#if defined(USE_MUTEX)
    mutex_enter(&state->lock);
#endif /* USE_MUTEX */

    if (state->rx_buf != 0) {
	freemsg(state->rx_buf);
	state->rx_buf = 0;
    }

#if defined(USE_MUTEX)
    mutex_exit(&state->lock);
    mutex_destroy(&state->lock);
#endif /* USE_MUTEX */

    FREE(q->q_ptr, sizeof(ahdlc_state_t));
    q->q_ptr	     = NULL;
    OTHERQ(q)->q_ptr = NULL;

#if defined(SUNOS4)
    if (ppp_ahdlc_count)
	ppp_ahdlc_count--;
#endif /* SUNOS4 */
    
    return 0;
}

/*
 * Write side put routine
 */
static int
ahdlc_wput(q, mp)
    queue_t	*q;
    mblk_t	*mp;
{
    ahdlc_state_t  	*state;
    struct iocblk  	*iop;
    int		   	error;
    mblk_t	   	*np;
    struct ppp_stats	*psp;

    state = (ahdlc_state_t *) q->q_ptr;
    if (state == 0) {
	DPRINT("state == 0 in ahdlc_wput\n");
	freemsg(mp);
	return 0;
    }

    switch (mp->b_datap->db_type) {
    case M_DATA:
	/*
	 * A data packet - do character-stuffing and FCS, and
	 * send it onwards.
	 */
	ahdlc_encode(q, mp);
	freemsg(mp);
	break;

    case M_IOCTL:
	iop = (struct iocblk *) mp->b_rptr;
	error = EINVAL;
	switch (iop->ioc_cmd) {
	case PPPIO_XACCM:
	    if ((iop->ioc_count < sizeof(u_int32_t)) || 
		(iop->ioc_count > sizeof(ext_accm))) {
		break;
	    }
	    if (mp->b_cont == 0) {
		DPRINT1("ahdlc_wput/%d: PPPIO_XACCM b_cont = 0!\n", state->unit);
		break;
	    }
#if defined(USE_MUTEX)
	    mutex_enter(&state->lock);
#endif /* USE_MUTEX */
	    bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)state->xaccm,
		  iop->ioc_count);
	    state->xaccm[2] &= ~0x40000000;	/* don't escape 0x5e */
	    state->xaccm[3] |= 0x60000000;	/* do escape 0x7d, 0x7e */
#if defined(USE_MUTEX)
	    mutex_exit(&state->lock);
#endif /* USE_MUTEX */
	    iop->ioc_count = 0;
	    error = 0;
	    break;

	case PPPIO_RACCM:
	    if (iop->ioc_count != sizeof(u_int32_t))
		break;
	    if (mp->b_cont == 0) {
		DPRINT1("ahdlc_wput/%d: PPPIO_RACCM b_cont = 0!\n", state->unit);
		break;
	    }
#if defined(USE_MUTEX)
	    mutex_enter(&state->lock);
#endif /* USE_MUTEX */
	    bcopy((caddr_t)mp->b_cont->b_rptr, (caddr_t)&state->raccm,
		  sizeof(u_int32_t));
#if defined(USE_MUTEX)
	    mutex_exit(&state->lock);
#endif /* USE_MUTEX */
	    iop->ioc_count = 0;
	    error = 0;
	    break;

	case PPPIO_GCLEAN:
	    np = allocb(sizeof(int), BPRI_HI);
	    if (np == 0) {
		error = ENOSR;
		break;
	    }
	    if (mp->b_cont != 0)
		freemsg(mp->b_cont);
	    mp->b_cont = np;
#if defined(USE_MUTEX)
	    mutex_enter(&state->lock);
#endif /* USE_MUTEX */
	    *(int *)np->b_wptr = state->flags & RCV_FLAGS;
#if defined(USE_MUTEX)
	    mutex_exit(&state->lock);
#endif /* USE_MUTEX */
	    np->b_wptr += sizeof(int);
	    iop->ioc_count = sizeof(int);
	    error = 0;
	    break;

	case PPPIO_GETSTAT:
	    np = allocb(sizeof(struct ppp_stats), BPRI_HI);
	    if (np == 0) {
		error = ENOSR;
		break;
	    }
	    if (mp->b_cont != 0)
		freemsg(mp->b_cont);
	    mp->b_cont = np;
	    psp = (struct ppp_stats *) np->b_wptr;
	    np->b_wptr += sizeof(struct ppp_stats);
	    bzero((caddr_t)psp, sizeof(struct ppp_stats));
	    psp->p = state->stats;
	    iop->ioc_count = sizeof(struct ppp_stats);
	    error = 0;
	    break;

	case PPPIO_LASTMOD:
	    /* we knew this anyway */
	    error = 0;
	    break;

	default:
	    error = -1;
	    break;
	}

	if (error < 0)
	    putnext(q, mp);
	else if (error == 0) {
	    mp->b_datap->db_type = M_IOCACK;
	    qreply(q, mp);
	} else {
	    mp->b_datap->db_type = M_IOCNAK;
	    iop->ioc_count = 0;
	    iop->ioc_error = error;
	    qreply(q, mp);
	}
	break;

    case M_CTL:
	switch (*mp->b_rptr) {
	case PPPCTL_MTU:
#if defined(USE_MUTEX)
	    mutex_enter(&state->lock);
#endif /* USE_MUTEX */
	    state->mtu = ((unsigned short *)mp->b_rptr)[1];
#if defined(USE_MUTEX)
	    mutex_exit(&state->lock);
#endif /* USE_MUTEX */
	    freemsg(mp);
	    break;
	case PPPCTL_MRU:
#if defined(USE_MUTEX)
	    mutex_enter(&state->lock);
#endif /* USE_MUTEX */
	    state->mru = ((unsigned short *)mp->b_rptr)[1];
#if defined(USE_MUTEX)
	    mutex_exit(&state->lock);
#endif /* USE_MUTEX */
	    freemsg(mp);
	    break;
	case PPPCTL_UNIT:
#if defined(USE_MUTEX)
	    mutex_enter(&state->lock);
#endif /* USE_MUTEX */
	    state->unit = mp->b_rptr[1];
#if defined(USE_MUTEX)
	    mutex_exit(&state->lock);
#endif /* USE_MUTEX */
	    break;
	default:
	    putnext(q, mp);
	}
	break;

    default:
	putnext(q, mp);
    }

    return 0;
}

/*
 * Read side put routine
 */
static int
ahdlc_rput(q, mp)
    queue_t *q;
    mblk_t  *mp;
{
    ahdlc_state_t *state;

    state = (ahdlc_state_t *) q->q_ptr;
    if (state == 0) {
	DPRINT("state == 0 in ahdlc_rput\n");
	freemsg(mp);
	return 0;
    }

    switch (mp->b_datap->db_type) {
    case M_DATA:
	ahdlc_decode(q, mp);
	freemsg(mp);
	break;

    case M_HANGUP:
#if defined(USE_MUTEX)
	mutex_enter(&state->lock);
#endif /* USE_MUTEX */
	if (state->rx_buf != 0) {
	    /* XXX would like to send this up for debugging */
	    freemsg(state->rx_buf);
	    state->rx_buf = 0;
	}
	state->flags = IFLUSH;
#if defined(USE_MUTEX)
	mutex_exit(&state->lock);
#endif /* USE_MUTEX */
	putnext(q, mp);
	break;

    default:
	putnext(q, mp);
    }
    return 0;
}

/*
 * Extract bit c from map m, to determine if c needs to be escaped
 */
#define IN_TX_MAP(c, m)	((m)[(c) >> 5] & (1 << ((c) & 0x1f)))

static void
ahdlc_encode(q, mp)
    queue_t	*q;
    mblk_t	*mp;
{
    ahdlc_state_t	*state;
    u_int32_t		*xaccm, loc_xaccm[8];
    ushort_t		fcs;
    size_t		outmp_len;
    mblk_t		*outmp, *tmp;
    uchar_t		*dp, fcs_val;
    int			is_lcp, code;
#if defined(SOL2)
    clock_t		lbolt;
#endif /* SOL2 */

    if (msgdsize(mp) < 4) {
	return;
    }

    state = (ahdlc_state_t *)q->q_ptr;
#if defined(USE_MUTEX)
    mutex_enter(&state->lock);
#endif /* USE_MUTEX */

    /*
     * Allocate an output buffer large enough to handle a case where all
     * characters need to be escaped
     */
    outmp_len = (msgdsize(mp)	 << 1) +		/* input block x 2 */
		(sizeof(fcs)	 << 2) +		/* HDLC FCS x 4 */
		(sizeof(uchar_t) << 1);			/* HDLC flags x 2 */

    outmp = allocb(outmp_len, BPRI_MED);
    if (outmp == NULL) {
	state->stats.ppp_oerrors++;
#if defined(USE_MUTEX)
	mutex_exit(&state->lock);
#endif /* USE_MUTEX */
	putctl1(RD(q)->q_next, M_CTL, PPPCTL_OERROR);
	return;
    }

#if defined(SOL2)
    /*
     * Check if our last transmit happenned within flag_time, using
     * the system's LBOLT value in clock ticks
     */
    if (drv_getparm(LBOLT, &lbolt) != -1) {
	if (ABS((clock_t)lbolt - state->lbolt) > state->flag_time) {
	    *outmp->b_wptr++ = PPP_FLAG;
	} 
	state->lbolt = lbolt;
    } else {
	*outmp->b_wptr++ = PPP_FLAG;
    }
#else
    /*
     * If the driver below still has a message to process, skip the
     * HDLC flag, otherwise, put one in the beginning
     */
    if (qsize(q->q_next) == 0) {
	*outmp->b_wptr++ = PPP_FLAG;
    }
#endif

    /*
     * All control characters must be escaped for LCP packets with code
     * values between 1 (Conf-Req) and 7 (Code-Rej).
     */
    is_lcp = ((MSG_BYTE(mp, 0) == PPP_ALLSTATIONS) && 
	      (MSG_BYTE(mp, 1) == PPP_UI) && 
	      (MSG_BYTE(mp, 2) == (PPP_LCP >> 8)) &&
	      (MSG_BYTE(mp, 3) == (PPP_LCP & 0xff)) &&
	      LCP_USE_DFLT(mp));

    xaccm = state->xaccm;
    if (is_lcp) {
	bcopy((caddr_t)state->xaccm, (caddr_t)loc_xaccm, sizeof(loc_xaccm));
	loc_xaccm[0] = ~0;	/* force escape on 0x00 through 0x1f */
	xaccm = loc_xaccm;
    }

    fcs = PPP_INITFCS;		/* Initial FCS is 0xffff */

    /*
     * Process this block and the rest (if any) attached to the this one
     */
    for (tmp = mp; tmp; tmp = tmp->b_cont) {
	if (tmp->b_datap->db_type == M_DATA) {
	    for (dp = tmp->b_rptr; dp < tmp->b_wptr; dp++) {
		fcs = PPP_FCS(fcs, *dp);
		if (IN_TX_MAP(*dp, xaccm)) {
		    *outmp->b_wptr++ = PPP_ESCAPE;
		    *outmp->b_wptr++ = *dp ^ PPP_TRANS;
		} else {
		    *outmp->b_wptr++ = *dp;
		}
	    }
	} else {
	    continue;	/* skip if db_type is something other than M_DATA */
	}
    }

    /*
     * Append the HDLC FCS, making sure that escaping is done on any
     * necessary bytes
     */
    fcs_val = (fcs ^ 0xffff) & 0xff;
    if (IN_TX_MAP(fcs_val, xaccm)) {
	*outmp->b_wptr++ = PPP_ESCAPE;
	*outmp->b_wptr++ = fcs_val ^ PPP_TRANS;
    } else {
	*outmp->b_wptr++ = fcs_val;
    }

    fcs_val = ((fcs ^ 0xffff) >> 8) & 0xff;
    if (IN_TX_MAP(fcs_val, xaccm)) {
	*outmp->b_wptr++ = PPP_ESCAPE;
	*outmp->b_wptr++ = fcs_val ^ PPP_TRANS;
    } else {
	*outmp->b_wptr++ = fcs_val;
    }

    /*
     * And finally, append the HDLC flag, and send it away
     */
    *outmp->b_wptr++ = PPP_FLAG;

    state->stats.ppp_obytes += msgdsize(outmp);
    state->stats.ppp_opackets++;

#if defined(USE_MUTEX)
    mutex_exit(&state->lock);
#endif /* USE_MUTEX */

    putnext(q, outmp);
    return;
}

/*
 * Checks the 32-bit receive ACCM to see if the byte needs un-escaping
 */
#define IN_RX_MAP(c, m)	((((unsigned int) (uchar_t) (c)) < 0x20) && \
			(m) & (1 << (c)))


/*
 * Process received characters.
 */
static void
ahdlc_decode(q, mp)
    queue_t *q;
    mblk_t  *mp;
{
    ahdlc_state_t   *state;
    mblk_t	    *om;
    uchar_t	    *dp;
    ushort_t	    fcs;
#if defined(SOL2)
    mblk_t	    *zmp;
#endif /* SOL2 */

#if defined(SOL2)
    /*
     * In case the driver (or something below) doesn't send
     * data upstream in one message block, concatenate everything
     */
    if (!((mp->b_wptr - mp->b_rptr == msgdsize(mp)) && 
         ((intpointer_t)mp->b_rptr % sizeof(intpointer_t) == 0))) {

	zmp = msgpullup(mp, -1);
	freemsg(mp);
	mp = zmp;
	if (mp == 0)
	    return; 
    }
#endif /* SOL2 */

    state = (ahdlc_state_t *) q->q_ptr;

#if defined(USE_MUTEX)
    mutex_enter(&state->lock);
#endif /* USE_MUTEX */

    state->stats.ppp_ibytes += msgdsize(mp);

    for (dp = mp->b_rptr; dp < mp->b_wptr; dp++) {

	/*
	 * This should detect the lack of 8-bit communication channel
	 * which is necessary for PPP to work. In addition, it also
	 * checks on the parity.
	 */
	if (*dp & 0x80)
	    state->flags |= RCV_B7_1;
	else
	    state->flags |= RCV_B7_0;

	if (paritytab[*dp >> 5] & (1 << (*dp & 0x1f)))
	    state->flags |= RCV_ODDP;
	else
	    state->flags |= RCV_EVNP;

	/*
	 * So we have a HDLC flag ...
	 */
	if (*dp == PPP_FLAG) {

	    /*
	     * If we think that it marks the beginning of the frame,
	     * then continue to process the next octects
	     */
	    if ((state->flags & IFLUSH) ||
		(state->rx_buf == 0) ||
		(msgdsize(state->rx_buf) == 0)) {

		state->flags &= ~IFLUSH;
		continue;
	    }

	    /*
	     * We get here because the above condition isn't true,
	     * in which case the HDLC flag was there to mark the end
	     * of the frame (or so we think)
	     */
	    om = state->rx_buf;

	    if (state->infcs == PPP_GOODFCS) {
		state->stats.ppp_ipackets++;
		adjmsg(om, -PPP_FCSLEN);
		putnext(q, om);
	    } else {
		DPRINT2("ppp%d: bad fcs (len=%d)\n",
                    state->unit, msgdsize(state->rx_buf));
		freemsg(state->rx_buf);
		state->flags &= ~(IFLUSH | ESCAPED);
		state->stats.ppp_ierrors++;
		putctl1(q->q_next, M_CTL, PPPCTL_IERROR);
	    }

	    state->rx_buf = 0;
	    continue;
	}

	if (state->flags & IFLUSH) {
	    continue;
	}

	/*
	 * Allocate a receive buffer, large enough to store a frame (after
	 * un-escaping) of at least 1500 octets. If MRU is negotiated to
	 * be more than the default, then allocate that much. In addition,
	 * we add an extra 32-bytes for a fudge factor
	 */ 
	if (state->rx_buf == 0) {
	    state->rx_buf_size  = (state->mru < PPP_MRU ? PPP_MRU : state->mru);
	    state->rx_buf_size += (sizeof(u_int32_t) << 3);
	    state->rx_buf = allocb(state->rx_buf_size, BPRI_MED);

	    /*
	     * If allocation fails, try again on the next frame
	     */
	    if (state->rx_buf == 0) {
		state->flags |= IFLUSH;
		continue;
	    }
	    state->flags &= ~(IFLUSH | ESCAPED);
	    state->infcs  = PPP_INITFCS;
	}

	if (*dp == PPP_ESCAPE) {
	    state->flags |= ESCAPED;
	    continue;
	}

	/*
	 * Make sure we un-escape the necessary characters, as well as the
	 * ones in our receive async control character map
	 */
	if (state->flags & ESCAPED) {
	    *dp ^= PPP_TRANS;
	    state->flags &= ~ESCAPED;
	} else if (IN_RX_MAP(*dp, state->raccm)) 
	    continue;

	/*
	 * Unless the peer lied to us about the negotiated MRU, we should
	 * never get a frame which is too long. If it happens, toss it away
	 * and grab the next incoming one
	 */
	if (msgdsize(state->rx_buf) < state->rx_buf_size) {
	    state->infcs = PPP_FCS(state->infcs, *dp);
	    *state->rx_buf->b_wptr++ = *dp;
	} else {
	    DPRINT2("ppp%d: frame too long (%d)\n",
		state->unit, msgdsize(state->rx_buf));
	    freemsg(state->rx_buf);
	    state->rx_buf     = 0;
	    state->flags     |= IFLUSH;
	}
    }

#if defined(USE_MUTEX)
    mutex_exit(&state->lock);
#endif /* USE_MUTEX */
}

static int
msg_byte(mp, i)
    mblk_t *mp;
    unsigned int i;
{
    while (mp != 0 && i >= mp->b_wptr - mp->b_rptr)
	mp = mp->b_cont;
    if (mp == 0)
	return -1;
    return mp->b_rptr[i];
}