summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael Garcia-Suarez <rgarciasuarez@mandriva.org>2006-02-08 15:11:47 +0000
committerRafael Garcia-Suarez <rgarciasuarez@mandriva.org>2006-02-08 15:11:47 +0000
commit1015446c571e56ec6a5b0f1aae497cbcf3fe6ef9 (patch)
treeab35b78e5311c609d715f559d55bc3410d403bc3
parente5172c4bcf96785aaae10fbc69d5407599f2a718 (diff)
downloadurpmi-1015446c571e56ec6a5b0f1aae497cbcf3fe6ef9.tar
urpmi-1015446c571e56ec6a5b0f1aae497cbcf3fe6ef9.tar.gz
urpmi-1015446c571e56ec6a5b0f1aae497cbcf3fe6ef9.tar.bz2
urpmi-1015446c571e56ec6a5b0f1aae497cbcf3fe6ef9.tar.xz
urpmi-1015446c571e56ec6a5b0f1aae497cbcf3fe6ef9.zip
Get rid of message() function
-rw-r--r--urpm/args.pm2
-rw-r--r--urpm/msg.pm15
-rwxr-xr-xurpmi58
3 files changed, 35 insertions, 40 deletions
diff --git a/urpm/args.pm b/urpm/args.pm
index a9010fe9..1acf0640 100644
--- a/urpm/args.pm
+++ b/urpm/args.pm
@@ -72,7 +72,7 @@ my %options_spec = (
'no-remove|no-uninstall' => \$::no_remove,
'no-install|noinstall' => \$::no_install,
keep => sub { $urpm->{options}{keep} = 1 },
- logfile => \$::logfile,
+ 'logfile=s' => \$::logfile,
'split-level=s' => sub { $urpm->{options}{'split-level'} = $_[1] },
'split-length=s' => sub { $urpm->{options}{'split-length'} = $_[1] },
'fuzzy!' => sub { $urpm->{options}{fuzzy} = $_[1] },
diff --git a/urpm/msg.pm b/urpm/msg.pm
index 5d633ace..e46638b0 100644
--- a/urpm/msg.pm
+++ b/urpm/msg.pm
@@ -7,7 +7,7 @@ use Exporter;
(our $VERSION) = q$Id$ =~ /(\d+\.\d+)/;
our @ISA = 'Exporter';
-our @EXPORT = qw(N bug_log to_utf8 message_input message toMb from_utf8 sys_log);
+our @EXPORT = qw(N bug_log to_utf8 message_input toMb from_utf8 sys_log);
#- I18N.
use Locale::gettext;
@@ -93,20 +93,11 @@ sub message_input {
} else {
last;
}
- message(N("Sorry, bad choice, try again\n"));
+ print N("Sorry, bad choice, try again\n");
}
return $input;
}
-sub message {
- my ($msg) = @_;
- if ($urpm::args::options{bug} || !defined fileno ::SAVEOUT) {
- print STDOUT "$msg\n";
- } else {
- print ::SAVEOUT "$msg\n";
- }
-}
-
sub toMb {
my $nb = $_[0] / 1024 / 1024;
int $nb + 0.5;
@@ -130,6 +121,6 @@ urpm::msg - routines to prompt messages from the urpm* tools
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 MandrakeSoft SA
-Copyright (C) 2005 Mandriva SA
+Copyright (C) 2005, 2006 Mandriva SA
=cut
diff --git a/urpmi b/urpmi
index 4096888a..7456fec0 100755
--- a/urpmi
+++ b/urpmi
@@ -320,7 +320,7 @@ if (exists $urpm->{options}{'priority-upgrade'} && $urpm->{options}{'priority-up
}
if ($auto_update && !$bug && !$env) {
#- For translators : there are several media here
- message(N("Updating media..."));
+ print N("Updating media..."), "\n";
#- FIXME we need to configure it twice; otherwise
#- some settings are lost (like the skiplist) for
#- some reason.
@@ -401,8 +401,9 @@ sub ask_choice {
} @$choices;
if (@l > 1 && !$urpm->{options}{auto}) {
- message(N("One of the following packages is needed:"));
- my $i = 0; foreach (@l) { message(" " . ++$i . "- $_") }
+ print N("One of the following packages is needed:"), "\n";
+ my $i = 0;
+ foreach (@l) { print " " . ++$i . "- $_\n" }
$n = message_input(N("What is your choice? (1-%d) ", $i), undef, range_min => 0, range => $i);
defined($n) && $n ne "0" or exit 1; # abort.
if ($n =~ /\D/) {
@@ -436,7 +437,7 @@ if (@unselected_uninstalled) {
my $msg = N("The following packages can't be installed because they depend on packages
that are older than the installed ones:\n%s", $list);
if ($urpm->{options}{auto}) {
- message($msg);
+ print "$msg\n";
} else {
my $noexpr = N("Nn");
my $yesexpr = N("Yy");
@@ -454,7 +455,7 @@ if (@ask_unselect) {
my $list = join "\n", $urpm->translate_why_unselected($state, sort @ask_unselect);
my $msg = N("Some requested packages cannot be installed:\n%s", $list);
if ($urpm->{options}{auto}) {
- message($msg);
+ print "$msg\n";
} else {
my $noexpr = N("Nn");
my $yesexpr = N("Yy");
@@ -482,8 +483,8 @@ if (@ask_remove) {
my $list = join "\n", $urpm->translate_why_removed($state, sort @ask_remove);
if ($no_remove && !$force) {
- message(N("The installation cannot continue because the following packages
-have to be removed for others to be upgraded:\n%s\n", $list));
+ print N("The installation cannot continue because the following packages
+have to be removed for others to be upgraded:\n%s\n", $list), "\n";
exit 0;
}
@@ -492,7 +493,7 @@ have to be removed for others to be upgraded:\n%s\n", $list));
$msg = "$msg\n" . N("(test only, removal will not be actually done)");
}
if ($urpm->{options}{auto}) {
- message($msg);
+ print "$msg\n";
} else {
my $noexpr = N("Nn");
my $yesexpr = N("Yy");
@@ -593,7 +594,7 @@ foreach my $set (@{$state->{transaction} || []}) {
my (@transaction_list, %transaction_sources);
#- put a blank line to separate with previous transaction or user question.
- message("");
+ print "\n";
#- prepare transaction...
$urpm->prepare_transaction($set, $list, \%sources, \@transaction_list, \%transaction_sources);
@@ -624,7 +625,7 @@ foreach my $set (@{$state->{transaction} || []}) {
my $p = join "\n", @bad_signatures;
#- rurpmi always abort here
if ($urpm->{options}{auto} || $restricted) {
- message("$msg:\n$p\n");
+ print "$msg:\n$p\n\n";
exit 1;
} else {
my $noexpr = N("Nn");
@@ -637,8 +638,8 @@ foreach my $set (@{$state->{transaction} || []}) {
#- check for local files.
if (my @missing = grep { m|^/| && ! -e $_ } values %transaction_sources_install, values %transaction_sources) {
#- Warning : the following message is parsed in urpm::parallel_*
- message(N("Installation failed, some files are missing:\n%s\nYou may want to update your urpmi database",
- join "\n", map { s|([^:]*://[^/:\@]*:)[^/:\@]*(\@.*)|$1xxxx$2|; " $_" } @missing));
+ print N("Installation failed, some files are missing:\n%s\nYou may want to update your urpmi database",
+ join "\n", map { s|([^:]*://[^/:\@]*:)[^/:\@]*(\@.*)|$1xxxx$2|; " $_" } @missing), "\n";
++$nok;
next;
}
@@ -648,7 +649,10 @@ foreach my $set (@{$state->{transaction} || []}) {
if (my @l = grep { /\.src\.rpm$/ } values %transaction_sources_install, values %transaction_sources) {
system("rpm", "-i$rpm_opt", @l, ($root ? ("--root", $root) : @{[]}));
#- Warning : the following message is parsed in urpm::parallel_*
- $? and message(N("Installation failed")), ++$nok;
+ if ($?) {
+ print N("Installation failed"), "\n";
+ ++$nok;
+ }
}
next;
}
@@ -665,7 +669,7 @@ foreach my $set (@{$state->{transaction} || []}) {
if (keys(%transaction_sources_install) || keys(%transaction_sources)) {
if ($parallel) {
- message(N("distributing %s", join(' ', values %transaction_sources_install, values %transaction_sources)));
+ print N("distributing %s", join(' ', values %transaction_sources_install, values %transaction_sources)), "\n";
#- no remove are handle here, automatically done by each distant node.
$urpm->{log}("starting distributed install");
$urpm->parallel_install([ keys %{$state->{rejected} || {}} ], \%transaction_sources_install, \%transaction_sources,
@@ -676,12 +680,12 @@ foreach my $set (@{$state->{transaction} || []}) {
(my $common_prefix) = $packnames[0] =~ /^(.*)\//;
if (length($common_prefix) && @packnames == grep { /^\Q$common_prefix\// } @packnames) {
#- there's a common prefix, simplify message
- message(N("installing %s from %s", join(' ', map { s/.*\///; $_ } @packnames), $common_prefix));
+ print N("installing %s from %s", join(' ', map { s/.*\///; $_ } @packnames), $common_prefix), "\n";
} else {
- message(N("installing %s", join(' ', @packnames)));
+ print N("installing %s", "@packnames"), "\n";
}
my $to_remove = $urpm->{options}{'allow-force'} ? [] : ($set->{remove} || []);
- @$to_remove and message(N("removing %s", "@$to_remove"));
+ @$to_remove and print N("removing %s", "@$to_remove"), "\n";
bug_log(scalar localtime, " ", join(' ', values %transaction_sources_install, values %transaction_sources), "\n");
$urpm->{log}("starting installing packages");
my %install_options_common = (
@@ -702,7 +706,7 @@ foreach my $set (@{$state->{transaction} || []}) {
);
if (@l) {
#- Warning : the following message is parsed in urpm::parallel_*
- message(N("Installation failed") . ":\n" . join("\n", map { "\t$_" } @l));
+ print N("Installation failed") . ":\n" . join("\n", map { "\t$_" } @l), "\n";
if ($urpm->{options}{auto} || !$urpm->{options}{'allow-nodeps'} && !$urpm->{options}{'allow-force'}) {
++$nok;
++$urpm->{logger_id};
@@ -722,7 +726,7 @@ foreach my $set (@{$state->{transaction} || []}) {
);
if (@l) {
#- Warning : the following message is parsed in urpm::parallel_*
- message(N("Installation failed") . ":\n" . join("\n", map { "\t$_" } @l));
+ print N("Installation failed") . ":\n" . join("\n", map { "\t$_" } @l), "\n";
if (!$urpm->{options}{'allow-force'}) {
++$nok;
++$urpm->{logger_id};
@@ -740,7 +744,7 @@ foreach my $set (@{$state->{transaction} || []}) {
);
if (@l) {
#- Warning : the following message is parsed in urpm::parallel_*
- message(N("Installation failed") . ":\n" . join("\n", map { "\t$_" } @l));
+ print N("Installation failed") . ":\n" . join("\n", map { "\t$_" } @l), "\n";
++$nok;
++$urpm->{logger_id};
push @errors, @l;
@@ -763,12 +767,12 @@ foreach my $set (@{$state->{transaction} || []}) {
my $exit_code = 0;
if (values %error_sources) {
#- Warning : the following message is parsed in urpm::parallel_*
- message(N("Installation failed, some files are missing:\n%s\nYou may want to update your urpmi database",
- join "\n", map { s|([^:]*://[^/:\@]*:)[^/:\@]*(\@.*)|$1xxxx$2|; " $_" } values %error_sources));
+ print N("Installation failed, some files are missing:\n%s\nYou may want to update your urpmi database",
+ join "\n", map { s|([^:]*://[^/:\@]*:)[^/:\@]*(\@.*)|$1xxxx$2|; " $_" } values %error_sources), "\n";
$exit_code = 10;
}
if ($nok) {
- $nok > 1 and message(N("%d installation transactions failed", $nok) . (@errors && ":\n" . join("\n", map { "\t$_" } @errors)));
+ $nok > 1 and print N("%d installation transactions failed", $nok) . (@errors && ":\n" . join("\n", map { "\t$_" } @errors)), "\n";
if ($exit_code) {
$exit_code = $ok ? 13 : 14;
} else {
@@ -777,14 +781,14 @@ if ($nok) {
} else {
if ($test) {
#- Warning : the following message is parsed in urpm::parallel_*
- message(N("Installation is possible"));
+ print N("Installation is possible"), "\n";
} elsif (@names || @src_names || @files || @src_files || $auto_select) {
if (@{$state->{transaction} || []} == 0 && @ask_unselect == 0) {
- message(N("The package(s) are already installed")) if $verbose >= 0;
+ print N("The package(s) are already installed"), "\n" if $verbose >= 0;
if ($verbose >= 0 && !$auto_select) {
my @packages = map { $urpm->{depslist}[$_]->name } keys %requested;
my @guessed = difference2(\@packages, \(@names, @src_names));
- message(N("The following package names were assumed: %s", join ", ", @guessed)) if @guessed;
+ print N("The following package names were assumed: %s", join ", ", @guessed), "\n" if @guessed;
}
$exit_code = 15 if our $expect_install;
}
@@ -801,7 +805,7 @@ unless ($env || $nolock) {
#- restart urpmi if needed, keep command line for that.
if ($restart_itself && !$exit_code) {
- message(N("restarting urpmi"));
+ print N("restarting urpmi"), "\n";
#- it seems to work correctly with exec instead of system, provided
#- STDOUT or STDERR are not closed before (else no output at all).
#- added --no-priority-upgrade to make sure no restart will be done after this one.
id='n607' href='#n607'>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 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 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
/***********************************************************************
*
* if.c
*
* Implementation of user-space PPPoE redirector for Linux.
*
* Functions for opening a raw socket and reading/writing raw Ethernet frames.
*
* Copyright (C) 2000 by Roaring Penguin Software Inc.
*
* This program may be distributed according to the terms of the GNU
* General Public License, version 2 or (at your option) any later version.
*
***********************************************************************/

static char const RCSID[] =
"$Id$";

#include "pppoe.h"

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#ifdef HAVE_NETPACKET_PACKET_H
#include <netpacket/packet.h>
#elif defined(HAVE_LINUX_IF_PACKET_H)
#include <linux/if_packet.h>
#endif

#ifdef HAVE_NET_ETHERNET_H
#include <net/ethernet.h>
#endif

#ifdef HAVE_ASM_TYPES_H
#include <asm/types.h>
#endif

#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif

#ifdef HAVE_SYSLOG_H
#include <syslog.h>
#endif

#include <errno.h>
#include <stdlib.h>
#include <string.h>

#ifdef HAVE_NET_IF_ARP_H
#include <net/if_arp.h>
#endif

#ifdef USE_DLPI

#include <limits.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stream.h>
#include <sys/stropts.h>
#include <sys/dlpi.h>
#include <sys/bufmod.h>
#include <stdio.h>
#include <signal.h>
#include <stropts.h>

/* function declarations */

void dlpromisconreq( int fd, u_long  level);
void dlinforeq(int fd);
void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen);
void dlinfoack(int fd, char *bufp);
void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest);
void dlattachreq(int fd, u_long ppa);
void dlokack(int fd, char *bufp);
void dlbindack(int fd, char *bufp);
int strioctl(int fd, int cmd, int timout, int len, char *dp);
void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller);
void sigalrm(int sig);
void expecting(int prim, union DL_primitives *dlp);
char *dlprim(u_long prim);

/* #define DL_DEBUG */

static	int     dl_abssaplen;
static	int     dl_saplen;
static	int 	dl_addrlen;

#endif

#ifdef USE_BPF
#include <net/bpf.h>
#include <fcntl.h>

unsigned char *bpfBuffer;	/* Packet filter buffer */
int bpfLength = 0;		/* Packet filter buffer length */
int bpfSize = 0;		/* Number of unread bytes in buffer */
int bpfOffset = 0;		/* Current offset in bpfBuffer */
#endif

/* Initialize frame types to RFC 2516 values.  Some broken peers apparently
   use different frame types... sigh... */

UINT16_t Eth_PPPOE_Discovery = ETH_PPPOE_DISCOVERY;
UINT16_t Eth_PPPOE_Session   = ETH_PPPOE_SESSION;

/**********************************************************************
*%FUNCTION: etherType
*%ARGUMENTS:
* packet -- a received PPPoE packet
*%RETURNS:
* ethernet packet type (see /usr/include/net/ethertypes.h)
*%DESCRIPTION:
* Checks the ethernet packet header to determine its type.
* We should only be receveing DISCOVERY and SESSION types if the BPF
* is set up correctly.  Logs an error if an unexpected type is received.
* Note that the ethernet type names come from "pppoe.h" and the packet
* packet structure names use the LINUX dialect to maintain consistency
* with the rest of this file.  See the BSD section of "pppoe.h" for
* translations of the data structure names.
***********************************************************************/
UINT16_t
etherType(PPPoEPacket *packet)
{
    UINT16_t type = (UINT16_t) ntohs(packet->ethHdr.h_proto);
    if (type != Eth_PPPOE_Discovery && type != Eth_PPPOE_Session) {
	syslog(LOG_ERR, "Invalid ether type 0x%x", type);
    }
    return type;
}

#ifdef USE_BPF
/**********************************************************************
*%FUNCTION: getHWaddr
*%ARGUMENTS:
* ifname -- name of interface
* hwaddr -- buffer for ehthernet address
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Locates the Ethernet hardware address for an interface.
***********************************************************************/
void
getHWaddr(int sock, char const *ifname, unsigned char *hwaddr)
{
    char inbuf[8192];
    const struct sockaddr_dl *sdl;
    struct ifconf ifc;
    struct ifreq ifreq, *ifr;
    int i;
    int found = 0;

    ifc.ifc_len = sizeof(inbuf);
    ifc.ifc_buf = inbuf;
    if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
	fatalSys("SIOCGIFCONF");
    }
    ifr = ifc.ifc_req;
    ifreq.ifr_name[0] = '\0';
    for (i = 0; i < ifc.ifc_len; ) {
	ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
	i += sizeof(ifr->ifr_name) +
		    (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)
		    ? ifr->ifr_addr.sa_len
		    : sizeof(struct sockaddr));
	if (ifr->ifr_addr.sa_family == AF_LINK) {
	    sdl = (const struct sockaddr_dl *) &ifr->ifr_addr;
	    if ((sdl->sdl_type == IFT_ETHER) &&
	        (sdl->sdl_alen == ETH_ALEN) &&
		!strncmp(ifname, ifr->ifr_name, sizeof(ifr->ifr_name))) {
		if (found) {
		    char buffer[256];
		    sprintf(buffer, "interface %.16s has more than one ethernet address", ifname);
		    rp_fatal(buffer);
		} else {
		    found = 1;
	            memcpy(hwaddr, LLADDR(sdl), ETH_ALEN);
		}
	    }
	}
    }
    if (!found) {
	char buffer[256];
        sprintf(buffer, "interface %.16s has no ethernet address", ifname);
	rp_fatal(buffer);
    }
}

/**********************************************************************
*%FUNCTION: initFilter
*%ARGUMENTS:
* fd -- file descriptor of BSD device
* type -- Ethernet frame type (0 for watch mode)
* hwaddr -- buffer with ehthernet address
*%RETURNS:
* Nothing
*%DESCRIPTION:
* Initializes the packet filter rules.
***********************************************************************/
void
initFilter(int fd, UINT16_t type, unsigned char *hwaddr)
{
    /* Packet Filter Instructions:
     * Note that the ethernet type names come from "pppoe.h" and are
     * used here to maintain consistency with the rest of this file. */
    static struct bpf_insn bpfRun[] = {         /* run PPPoE */
        BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),     /* ethernet type */
        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_SESSION, 5, 0),
        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETH_PPPOE_DISCOVERY, 0, 9),
        BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0),      /* first word of dest. addr */
#define PPPOE_BCAST_CMPW 4                     /* offset of word compare */
        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 2),
        BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4),      /* next 1/2 word of dest. */
#define PPPOE_BCAST_CMPH 6                     /* offset of 1/2 word compare */
        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 4, 0),
        BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0),      /* first word of dest. addr */
#define PPPOE_FILTER_CMPW 8                     /* offset of word compare */
        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 3),
        BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4),      /* next 1/2 word of dest. */
#define PPPOE_FILTER_CMPH 10                    /* offset of 1/rd compare */
        BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 1),
        BPF_STMT(BPF_RET+BPF_K, (u_int) -1),    /* keep packet */
        BPF_STMT(BPF_RET+BPF_K, 0),             /* drop packet */
    };

    /* Fix the potentially varying parts */
    bpfRun[1].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
    bpfRun[1].jt   = 5;
    bpfRun[1].jf   = 0;
    bpfRun[1].k    = Eth_PPPOE_Session;

    bpfRun[2].code = (u_short) BPF_JMP+BPF_JEQ+BPF_K;
    bpfRun[2].jt   = 0;
    bpfRun[2].jf   = 9;
    bpfRun[2].k    = Eth_PPPOE_Discovery;

    {
      struct bpf_insn bpfInsn[sizeof(bpfRun) / sizeof(bpfRun[0])];
      struct bpf_program bpfProgram;
      memcpy(bpfInsn, bpfRun, sizeof(bpfRun));
      bpfInsn[PPPOE_BCAST_CMPW].k = ((0xff << 24) | (0xff << 16) |
                                     (0xff << 8) | 0xff);
      bpfInsn[PPPOE_BCAST_CMPH].k = ((0xff << 8) | 0xff);
      bpfInsn[PPPOE_FILTER_CMPW].k = ((hwaddr[0] << 24) | (hwaddr[1] << 16) |
				      (hwaddr[2] << 8) | hwaddr[3]);
      bpfInsn[PPPOE_FILTER_CMPH].k = ((hwaddr[4] << 8) | hwaddr[5]);
      bpfProgram.bf_len = (sizeof(bpfInsn) / sizeof(bpfInsn[0]));
      bpfProgram.bf_insns = &bpfInsn[0];
      
      /* Apply the filter */
      if (ioctl(fd, BIOCSETF, &bpfProgram) < 0) {
	fatalSys("ioctl(BIOCSETF)");
      }
    }
}

/**********************************************************************
*%FUNCTION: openInterface
*%ARGUMENTS:
* ifname -- name of interface
* type -- Ethernet frame type (0 for any frame type)
* hwaddr -- if non-NULL, set to the hardware address
*%RETURNS:
* A file descriptor for talking with the Ethernet card.  Exits on error.
* Note that the Linux version of this routine returns a socket instead.
*%DESCRIPTION:
* Opens a BPF on an interface for all PPPoE traffic (discovery and
* session).  If 'type' is 0, uses promiscuous mode to watch any PPPoE
* traffic on this network.
***********************************************************************/
int
openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
{
    static int fd = -1;
    char bpfName[32];
    u_int optval;
    struct bpf_version bpf_ver;
    struct ifreq ifr;
    int sock;
    int i;

    /* BSD only opens one socket for both Discovery and Session packets */
    if (fd >= 0) {
	return fd;
    }

    /* Find a free BPF device */
    for (i = 0; i < 256; i++) {
	sprintf(bpfName, "/dev/bpf%d", i);
	if (((fd = open(bpfName, O_RDWR, 0)) >= 0) ||
	    (errno != EBUSY)) {
	    break;
	}
    }
    if (fd < 0) {
	switch (errno) {
	case EACCES:		/* permission denied */
	    {
		char buffer[256];
		sprintf(buffer, "Cannot open %.32s -- pppoe must be run as root.", bpfName);
		rp_fatal(buffer);
	    }
	    break;
	case EBUSY:
	case ENOENT:		/* no such file */
	    if (i == 0) {
		rp_fatal("No /dev/bpf* devices (check your kernel configuration for BPF support)");
	    } else {
		rp_fatal("All /dev/bpf* devices are in use");
	    }
	    break;
	}
	fatalSys(bpfName);
    }

    if ((sock = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) {
	fatalSys("socket");
    }

    /* Check that the interface is up */
    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
	fatalSys("ioctl(SIOCGIFFLAGS)");
    }
    if ((ifr.ifr_flags & IFF_UP) == 0) {
	char buffer[256];
	sprintf(buffer, "Interface %.16s is not up\n", ifname);
	rp_fatal(buffer);
    }

    /* Fill in hardware address and initialize the packet filter rules */
    if (hwaddr == NULL) {
	rp_fatal("openInterface: no hwaddr arg.");
    }
    getHWaddr(sock, ifname, hwaddr);
    initFilter(fd, type, hwaddr);

    /* Sanity check on MTU -- apparently does not work on OpenBSD */
#if !defined(__OpenBSD__)
    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (ioctl(sock, SIOCGIFMTU, &ifr) < 0) {
	fatalSys("ioctl(SIOCGIFMTU)");
    }
    if (ifr.ifr_mtu < ETH_DATA_LEN) {
	char buffer[256];
	sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d.  You may have serious connection problems.",
		ifname, ifr.ifr_mtu, ETH_DATA_LEN);
	printErr(buffer);
    }
#endif

    /* done with the socket */
    if (close(sock) < 0) {
	fatalSys("close");
    }

    /* Check the BPF version number */
    if (ioctl(fd, BIOCVERSION, &bpf_ver) < 0) {
	fatalSys("ioctl(BIOCVERSION)");
    }
    if ((bpf_ver.bv_major != BPF_MAJOR_VERSION) ||
        (bpf_ver.bv_minor < BPF_MINOR_VERSION)) {
	char buffer[256];
	sprintf(buffer, "Unsupported BPF version: %d.%d (kernel: %d.%d)", 
			BPF_MAJOR_VERSION, BPF_MINOR_VERSION,
			bpf_ver.bv_major, bpf_ver.bv_minor);
	rp_fatal(buffer);
    }

    /* allocate a receive packet buffer */
    if (ioctl(fd, BIOCGBLEN, &bpfLength) < 0) {
	fatalSys("ioctl(BIOCGBLEN)");
    }
    if (!(bpfBuffer = (unsigned char *) malloc(bpfLength))) {
	rp_fatal("malloc");
    }

    /* reads should return as soon as there is a packet available */
    optval = 1;
    if (ioctl(fd, BIOCIMMEDIATE, &optval) < 0) {
	fatalSys("ioctl(BIOCIMMEDIATE)");
    }

    /* Bind the interface to the filter */
    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (ioctl(fd, BIOCSETIF, &ifr) < 0) {
	char buffer[256];
	sprintf(buffer, "ioctl(BIOCSETIF) can't select interface %.16s",
		ifname);
	rp_fatal(buffer);
    }

    syslog(LOG_INFO, "Interface=%.16s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%.32s Buffer size=%d",
	   ifname, 
	   hwaddr[0], hwaddr[1], hwaddr[2],
	   hwaddr[3], hwaddr[4], hwaddr[5],
	   bpfName, bpfLength);
    return fd;
}

#endif /* USE_BPF */

#ifdef USE_LINUX_PACKET
/**********************************************************************
*%FUNCTION: openInterface
*%ARGUMENTS:
* ifname -- name of interface
* type -- Ethernet frame type
* hwaddr -- if non-NULL, set to the hardware address
*%RETURNS:
* A raw socket for talking to the Ethernet card.  Exits on error.
*%DESCRIPTION:
* Opens a raw Ethernet socket
***********************************************************************/
int
openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
{
    int optval=1;
    int fd;
    struct ifreq ifr;
    int domain, stype;

#ifdef HAVE_STRUCT_SOCKADDR_LL
    struct sockaddr_ll sa;
#else
    struct sockaddr sa;
#endif

    memset(&sa, 0, sizeof(sa));

#ifdef HAVE_STRUCT_SOCKADDR_LL
    domain = PF_PACKET;
    stype = SOCK_RAW;
#else
    domain = PF_INET;
    stype = SOCK_PACKET;
#endif

    if ((fd = socket(domain, stype, htons(type))) < 0) {
	/* Give a more helpful message for the common error case */
	if (errno == EPERM) {
	    rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
	}
	fatalSys("socket");
    }

    if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
	fatalSys("setsockopt");
    }

    /* Fill in hardware address */
    if (hwaddr) {
	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
	if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
	    fatalSys("ioctl(SIOCGIFHWADDR)");
	}
	memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
#ifdef ARPHRD_ETHER
	if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
	    char buffer[256];
	    sprintf(buffer, "Interface %.16s is not Ethernet", ifname);
	    rp_fatal(buffer);
	}
#endif
	if (NOT_UNICAST(hwaddr)) {
	    char buffer[256];
	    sprintf(buffer,
		    "Interface %.16s has broadcast/multicast MAC address??",
		    ifname);
	    rp_fatal(buffer);
	}
    }

    /* Sanity check on MTU */
    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
	fatalSys("ioctl(SIOCGIFMTU)");
    }
    if (ifr.ifr_mtu < ETH_DATA_LEN) {
	char buffer[256];
	sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d.  You may have serious connection problems.",
		ifname, ifr.ifr_mtu, ETH_DATA_LEN);
	printErr(buffer);
    }

#ifdef HAVE_STRUCT_SOCKADDR_LL
    /* Get interface index */
    sa.sll_family = AF_PACKET;
    sa.sll_protocol = htons(type);

    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
    if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
	fatalSys("ioctl(SIOCFIGINDEX): Could not get interface index");
    }
    sa.sll_ifindex = ifr.ifr_ifindex;

#else
    strcpy(sa.sa_data, ifname);
#endif

    /* We're only interested in packets on specified interface */
    if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
	fatalSys("bind");
    }

    return fd;
}

#endif /* USE_LINUX */

/***********************************************************************
*%FUNCTION: sendPacket
*%ARGUMENTS:
* sock -- socket to send to
* pkt -- the packet to transmit
* size -- size of packet (in bytes)
*%RETURNS:
* 0 on success; -1 on failure
*%DESCRIPTION:
* Transmits a packet
***********************************************************************/
int
sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size)
{
#if defined(USE_BPF)
    if (write(sock, pkt, size) < 0) {
	sysErr("write (sendPacket)");
	return -1;
    }
#elif defined(HAVE_STRUCT_SOCKADDR_LL)
    if (send(sock, pkt, size, 0) < 0) {
	sysErr("send (sendPacket)");
	return -1;
    }
#else
#ifdef USE_DLPI

#define ABS(x)          ((x) < 0 ? -(x) : (x))

	u_char  addr[MAXDLADDR];
	u_char  phys[MAXDLADDR];
	u_char  sap[MAXDLADDR];
	u_char    xmitbuf[MAXDLBUF];
	int	data_size;

	short	tmp_sap;

	tmp_sap = htons(pkt->ethHdr.h_proto); 
	data_size = size - sizeof(struct ethhdr); 

	memcpy((char *)phys, (char *)pkt->ethHdr.h_dest, ETHERADDRL);
	memcpy((char *)sap,  (char *)&tmp_sap, sizeof(ushort_t));
	memcpy((char *)xmitbuf, (char *)pkt + sizeof(struct ethhdr), data_size); 

	if (dl_saplen > 0) {  /* order is sap+phys */
		(void) memcpy((char*)addr, (char*)&sap, dl_abssaplen);
		(void) memcpy((char*)addr+dl_abssaplen, (char*)phys, ETHERADDRL);
	} else {        /* order is phys+sap */
		(void) memcpy((char*)addr, (char*)phys, ETHERADDRL);
		(void) memcpy((char*)addr+ETHERADDRL, (char*)&sap, dl_abssaplen);
	}

#ifdef DL_DEBUG
	printf("%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x\n", 
		addr[0],addr[1],addr[2],addr[3],addr[4],addr[5],
		addr[6],addr[7]);
#endif

	dlunitdatareq(sock, addr, dl_addrlen, 0, 0, xmitbuf, data_size);



#else
    struct sockaddr sa;

    if (!conn) {
	rp_fatal("relay and server not supported on Linux 2.0 kernels");
    }
    strcpy(sa.sa_data, conn->ifName);
    if (sendto(sock, pkt, size, 0, &sa, sizeof(sa)) < 0) {
	sysErr("sendto (sendPacket)");
	return -1;
    }
#endif
#endif
    return 0;
}

#ifdef USE_BPF
/***********************************************************************
*%FUNCTION: clearPacketHeader
*%ARGUMENTS:
* pkt -- packet that needs its head clearing
*%RETURNS:
* nothing
*%DESCRIPTION:
* Clears a PPPoE packet header after a truncated packet has been
* received.  Insures that the packet will fail any integrity tests
* and will be discarded by upper level routines.  Also resets the
* bpfSize and bpfOffset variables to force a new read on the next
* call to receivePacket().
***********************************************************************/
void
clearPacketHeader(PPPoEPacket *pkt)
{
    bpfSize = bpfOffset = 0;
    memset(pkt, 0, HDR_SIZE);
}
#endif

/***********************************************************************
*%FUNCTION: receivePacket
*%ARGUMENTS:
* sock -- socket to read from
* pkt -- place to store the received packet
* size -- set to size of packet in bytes
*%RETURNS:
* >= 0 if all OK; < 0 if error
*%DESCRIPTION:
* Receives a packet
***********************************************************************/
int
receivePacket(int sock, PPPoEPacket *pkt, int *size)
{
#ifdef USE_BPF
    struct bpf_hdr hdr;
    int seglen, copylen;

    if (bpfSize <= 0) {
	bpfOffset = 0;
	if ((bpfSize = read(sock, bpfBuffer, bpfLength)) < 0) {
	    sysErr("read (receivePacket)");
	    return -1;
	}
    }
    if (bpfSize < sizeof(hdr)) {
	syslog(LOG_ERR, "Truncated bpf packet header: len=%d", bpfSize);
	clearPacketHeader(pkt);		/* resets bpfSize and bpfOffset */
	return 0;
    }
    memcpy(&hdr, bpfBuffer + bpfOffset, sizeof(hdr));
    if (hdr.bh_caplen != hdr.bh_datalen) {
	syslog(LOG_ERR, "Truncated bpf packet: caplen=%d, datalen=%d",
	       hdr.bh_caplen, hdr.bh_datalen);
	clearPacketHeader(pkt);		/* resets bpfSize and bpfOffset */
	return 0;
    }
    seglen = hdr.bh_hdrlen + hdr.bh_caplen;
    if (seglen > bpfSize) {
	syslog(LOG_ERR, "Truncated bpf packet: seglen=%d, bpfSize=%d",
	       seglen, bpfSize);
	clearPacketHeader(pkt);		/* resets bpfSize and bpfOffset */
	return 0;
    }
    seglen = BPF_WORDALIGN(seglen);
    *size = copylen = ((hdr.bh_caplen < sizeof(PPPoEPacket)) ?
			hdr.bh_caplen : sizeof(PPPoEPacket));
    memcpy(pkt, bpfBuffer + bpfOffset + hdr.bh_hdrlen, copylen);
    if (seglen >= bpfSize) {
	bpfSize = bpfOffset = 0;
    } else {
	bpfSize -= seglen;
	bpfOffset += seglen;
    }
#else
#ifdef USE_DLPI
	struct strbuf data; 
	int flags = 0; 	
	int retval; 

	data.buf = (char *) pkt; 
	data.maxlen = MAXDLBUF; 
	data.len = 0; 
	
	if ((retval = getmsg(sock, NULL, &data, &flags)) < 0) {
	    sysErr("read (receivePacket)");
	    return -1;
	}

	*size = data.len; 

#else
    if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) {
	sysErr("recv (receivePacket)");
	return -1;
    }
#endif
#endif
    return 0;
}

#ifdef USE_DLPI
/**********************************************************************
*%FUNCTION: openInterface
*%ARGUMENTS:
* ifname -- name of interface
* type -- Ethernet frame type
* hwaddr -- if non-NULL, set to the hardware address
*%RETURNS:
* A raw socket for talking to the Ethernet card.  Exits on error.
*%DESCRIPTION:
* Opens a raw Ethernet socket
***********************************************************************/
int
openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr)
{
    int fd;
    long buf[MAXDLBUF]; 

	union   DL_primitives   *dlp;

    char base_dev[PATH_MAX]; 
    int ppa; 

    if(strlen(ifname) > PATH_MAX) {
	rp_fatal("socket: string to long"); 
    }

    ppa = atoi(&ifname[strlen(ifname)-1]);
    strncpy(base_dev, ifname, PATH_MAX); 
    base_dev[strlen(base_dev)-1] = '\0'; 

    if (( fd = open(base_dev, O_RDWR)) < 0) {
	/* Give a more helpful message for the common error case */
	if (errno == EPERM) {
	    rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
	}
	fatalSys("socket");
    }

	dlinforeq(fd);
	dlinfoack(fd, (char *)buf);

	dlp = (union DL_primitives*) buf;

	dl_abssaplen = ABS(dlp->info_ack.dl_sap_length);
	dl_saplen = dlp->info_ack.dl_sap_length;
	if (ETHERADDRL != (dlp->info_ack.dl_addr_length - dl_abssaplen))
		fatalSys("invalid destination physical address length");
	dl_addrlen = dl_abssaplen + ETHERADDRL;

	dlattachreq(fd, ppa); 
	dlokack(fd, (char *)buf);

	dlbindreq(fd, type, 0, DL_CLDLS, 0, 0);
	dlbindack(fd, (char *)buf);

	if ( strioctl(fd, DLIOCRAW, -1, 0, NULL) < 0 ) { 
		fatalSys("DLIOCRAW"); 
	}

	if (ioctl(fd, I_FLUSH, FLUSHR) < 0) fatalSys("I_FLUSH");

    return fd;
}

/* cloned from dlcommon.c */

void dlpromisconreq(int fd, u_long level)
{
        dl_promiscon_req_t      promiscon_req;
        struct  strbuf  ctl;
        int     flags;

        promiscon_req.dl_primitive = DL_PROMISCON_REQ;
        promiscon_req.dl_level = level;

        ctl.maxlen = 0;
        ctl.len = sizeof (promiscon_req);
        ctl.buf = (char *) &promiscon_req;

        flags = 0;

        if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
                fatalSys("dlpromiscon:  putmsg");

}

void dlinforeq(int fd)
{
        dl_info_req_t   info_req;
        struct  strbuf  ctl;
        int     flags;

        info_req.dl_primitive = DL_INFO_REQ;

        ctl.maxlen = 0;
        ctl.len = sizeof (info_req);
        ctl.buf = (char *) &info_req;

        flags = RS_HIPRI;

        if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
                fatalSys("dlinforeq:  putmsg");
}

void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen)
{
        long    buf[MAXDLBUF];
        union   DL_primitives   *dlp;
        struct  strbuf  data, ctl;

        dlp = (union DL_primitives*) buf;

        dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ;
        dlp->unitdata_req.dl_dest_addr_length = addrlen;
        dlp->unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
        dlp->unitdata_req.dl_priority.dl_min = minpri;
        dlp->unitdata_req.dl_priority.dl_max = maxpri;

        (void) memcpy(OFFADDR(dlp, sizeof (dl_unitdata_req_t)), addrp, addrlen);

        ctl.maxlen = 0;
        ctl.len = sizeof (dl_unitdata_req_t) + addrlen;
        ctl.buf = (char *) buf;

        data.maxlen = 0;
        data.len = datalen;
        data.buf = (char *) datap;

        if (putmsg(fd, &ctl, &data, 0) < 0)
                fatalSys("dlunitdatareq:  putmsg");
}

void dlinfoack(int fd, char *bufp)
{
        union   DL_primitives   *dlp;
        struct  strbuf  ctl;
        int     flags;

        ctl.maxlen = MAXDLBUF;
        ctl.len = 0;
        ctl.buf = bufp;

        strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlinfoack");

        dlp = (union DL_primitives *) ctl.buf;

        expecting(DL_INFO_ACK, dlp);

        if (ctl.len < sizeof (dl_info_ack_t)) {
		char buffer[256];
		sprintf(buffer, "dlinfoack:  response ctl.len too short:  %d", ctl.len); 
                rp_fatal(buffer); 
	}

        if (flags != RS_HIPRI)
                rp_fatal("dlinfoack:  DL_INFO_ACK was not M_PCPROTO");

        if (ctl.len < sizeof (dl_info_ack_t)) {
		char buffer[256];
		sprintf(buffer, "dlinfoack:  short response ctl.len:  %d", ctl.len); 
		rp_fatal(buffer); 
	}
}

void dlbindreq(int fd, u_long sap, u_long max_conind, u_long service_mode, u_long conn_mgmt, u_long xidtest)
{
        dl_bind_req_t   bind_req;
        struct  strbuf  ctl;
        int     flags;

        bind_req.dl_primitive = DL_BIND_REQ;
        bind_req.dl_sap = sap;
        bind_req.dl_max_conind = max_conind;
        bind_req.dl_service_mode = service_mode;
        bind_req.dl_conn_mgmt = conn_mgmt;
        bind_req.dl_xidtest_flg = xidtest;

        ctl.maxlen = 0;
        ctl.len = sizeof (bind_req);
        ctl.buf = (char *) &bind_req;

        flags = 0;

        if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
                fatalSys("dlbindreq:  putmsg");
}

void dlattachreq(int fd, u_long ppa)
{
        dl_attach_req_t attach_req;
        struct  strbuf  ctl;
        int     flags;

        attach_req.dl_primitive = DL_ATTACH_REQ;
        attach_req.dl_ppa = ppa;

        ctl.maxlen = 0;
        ctl.len = sizeof (attach_req);
        ctl.buf = (char *) &attach_req;

        flags = 0;

        if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
                fatalSys("dlattachreq:  putmsg");
}

void dlokack(int fd, char *bufp)
{
        union   DL_primitives   *dlp;
        struct  strbuf  ctl;
        int     flags;

        ctl.maxlen = MAXDLBUF;
        ctl.len = 0;
        ctl.buf = bufp;

        strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlokack");

        dlp = (union DL_primitives *) ctl.buf;

        expecting(DL_OK_ACK, dlp);

        if (ctl.len < sizeof (dl_ok_ack_t)) { 
		char buffer[256];
		sprintf(buffer, "dlokack:  response ctl.len too short:  %d", ctl.len);
		rp_fatal(buffer); 
	}

        if (flags != RS_HIPRI)
                rp_fatal("dlokack:  DL_OK_ACK was not M_PCPROTO");

        if (ctl.len < sizeof (dl_ok_ack_t)) {
		char buffer[256]; 
		sprintf(buffer, "dlokack:  short response ctl.len:  %d", ctl.len);
		rp_fatal(buffer); 
	}
}

void dlbindack(int fd, char *bufp)
{
        union   DL_primitives   *dlp;
        struct  strbuf  ctl;
        int     flags;

        ctl.maxlen = MAXDLBUF;
        ctl.len = 0;
        ctl.buf = bufp;

        strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlbindack");

        dlp = (union DL_primitives *) ctl.buf;

        expecting(DL_BIND_ACK, dlp);

        if (flags != RS_HIPRI)
                rp_fatal("dlbindack:  DL_OK_ACK was not M_PCPROTO");

        if (ctl.len < sizeof (dl_bind_ack_t)) {
		char buffer[256];
		sprintf(buffer, "dlbindack:  short response ctl.len:  %d", ctl.len);
		rp_fatal(buffer); 
	}
}

int strioctl(int fd, int cmd, int timout, int len, char *dp)
{
        struct  strioctl        sioc;
        int     rc;

        sioc.ic_cmd = cmd;
        sioc.ic_timout = timout;
        sioc.ic_len = len;
        sioc.ic_dp = dp;
        rc = ioctl(fd, I_STR, &sioc);

        if (rc < 0)
                return (rc);
        else
                return (sioc.ic_len);
}

void strgetmsg(int fd, struct strbuf *ctlp, struct strbuf *datap, int *flagsp, char *caller)
{
        int     rc;
        static  char    errmsg[80];

        /*
         * Start timer.
         */
        (void) signal(SIGALRM, sigalrm);
        if (alarm(MAXWAIT) < 0) {
                (void) sprintf(errmsg, "%s:  alarm", caller);
                fatalSys(errmsg);
        }

        /*
         * Set flags argument and issue getmsg().
         */
        *flagsp = 0;
        if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) {
                (void) sprintf(errmsg, "%s:  getmsg", caller);
                fatalSys(errmsg);
        }

        /*
         * Stop timer.
         */
        if (alarm(0) < 0) {
                (void) sprintf(errmsg, "%s:  alarm", caller);
                fatalSys(errmsg);
        }

        /*
         * Check for MOREDATA and/or MORECTL.
         */
        if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA)) {
		char buffer[256]; 
		sprintf(buffer, "%s:  MORECTL|MOREDATA", caller);
		rp_fatal(buffer);
	}
                
        if (rc & MORECTL) {
		char buffer[256];
		sprintf(buffer, "%s:  MORECTL", caller);
		rp_fatal(buffer); 
	}
        
        if (rc & MOREDATA) {
		char buffer[256]; 
		sprintf(buffer, "%s:  MOREDATA", caller);
		rp_fatal(buffer);
	}

        /*
         * Check for at least sizeof (long) control data portion.
         */
        if (ctlp->len < sizeof (long)) {
		char buffer[256]; 
		sprintf(buffer, "getmsg:  control portion length < sizeof (long):  %d", ctlp->len);
		rp_fatal(buffer); 
	}
}

void sigalrm(int sig)
{
        (void) rp_fatal("sigalrm:  TIMEOUT");
}

void expecting(int prim, union DL_primitives *dlp)
{
        if (dlp->dl_primitive != (u_long)prim) {
		char buffer[256]; 
		sprintf(buffer, "expected %s got %s", dlprim(prim), dlprim(dlp->dl_primitive));
		rp_fatal(buffer); 
		exit(1); 
	}
}

char *dlprim(u_long prim)
{
        static  char    primbuf[80];

        switch ((int)prim) {
                CASERET(DL_INFO_REQ);
                CASERET(DL_INFO_ACK);
                CASERET(DL_ATTACH_REQ);
                CASERET(DL_DETACH_REQ);
                CASERET(DL_BIND_REQ);
                CASERET(DL_BIND_ACK);
                CASERET(DL_UNBIND_REQ);
                CASERET(DL_OK_ACK);
                CASERET(DL_ERROR_ACK);
                CASERET(DL_SUBS_BIND_REQ);
                CASERET(DL_SUBS_BIND_ACK);
                CASERET(DL_UNITDATA_REQ);
                CASERET(DL_UNITDATA_IND);
                CASERET(DL_UDERROR_IND);
                CASERET(DL_UDQOS_REQ);
                CASERET(DL_CONNECT_REQ);
                CASERET(DL_CONNECT_IND);
                CASERET(DL_CONNECT_RES);
                CASERET(DL_CONNECT_CON);
                CASERET(DL_TOKEN_REQ);
                CASERET(DL_TOKEN_ACK);
                CASERET(DL_DISCONNECT_REQ);
                CASERET(DL_DISCONNECT_IND);
                CASERET(DL_RESET_REQ);
                CASERET(DL_RESET_IND);
                CASERET(DL_RESET_RES);
                CASERET(DL_RESET_CON);
                default:
                        (void) sprintf(primbuf, "unknown primitive 0x%lx", prim);
                        return (primbuf);
        }
}

#endif /* USE_DLPI */