--- /dev/null
+diff -r -N -u -b -B ppp-2.4.1.orig/configure ppp-2.4.1.pppoe2/configure
+--- ppp-2.4.1.orig/configure Mon Apr 24 03:41:40 2000
++++ ppp-2.4.1.pppoe2/configure Fri Mar 30 16:37:20 2001
+@@ -131,7 +131,7 @@
+ makext=$orig_makext
+ fi
+ fi
+- for dir in pppd pppstats chat pppdump; do
++ for dir in pppd pppstats chat pppdump pppd/plugins pppd/plugins/pppoe; do
+ rm -f $dir/Makefile
+ if [ -f $dir/Makefile.$makext ]; then
+ ln -s Makefile.$makext $dir/Makefile
+diff -r -N -u -b -B ppp-2.4.1.orig/linux/Makefile.top ppp-2.4.1.pppoe2/linux/Makefile.top
+--- ppp-2.4.1.orig/linux/Makefile.top Mon Apr 17 06:39:26 2000
++++ ppp-2.4.1.pppoe2/linux/Makefile.top Fri Mar 30 18:43:51 2001
+@@ -10,6 +10,7 @@
+
+ all:
+ cd chat; $(MAKE) $(MFLAGS) all
++ cd pppd/plugins; $(MAKE) $(MFLAGS) all
+ cd pppd; $(MAKE) $(MFLAGS) all
+ cd pppstats; $(MAKE) $(MFLAGS) all
+ cd pppdump; $(MAKE) $(MFLAGS) all
+@@ -18,6 +19,7 @@
+
+ install-progs:
+ cd chat; $(MAKE) BINDIR=$(BINDIR) MANDIR=$(MANDIR) $(MFLAGS) install
++ cd pppd/plugins; $(MAKE) BINDIR=$(BINDIR) MANDIR=$(MANDIR) $(MFLAGS) install
+ cd pppd; $(MAKE) BINDIR=$(BINDIR) MANDIR=$(MANDIR) $(MFLAGS) install
+ cd pppstats; $(MAKE) BINDIR=$(BINDIR) MANDIR=$(MANDIR) $(MFLAGS) install
+ cd pppdump; $(MAKE) BINDIR=$(BINDIR) MANDIR=$(MANDIR) $(MFLAGS) install
+@@ -44,6 +46,7 @@
+ rm -f `find . -name 'core' -print`
+ rm -f `find . -name '*~' -print`
+ cd chat; $(MAKE) clean
++ cd pppd/plugins; $(MAKE) clean
+ cd pppd; $(MAKE) clean
+ cd pppstats; $(MAKE) clean
+ cd pppdump; $(MAKE) clean
+diff -r -N -u -b -B ppp-2.4.1.orig/pppd/options.c ppp-2.4.1.pppoe2/pppd/options.c
+--- ppp-2.4.1.orig/pppd/options.c Tue Mar 13 00:56:19 2001
++++ ppp-2.4.1.pppoe2/pppd/options.c Fri Mar 30 19:33:55 2001
+@@ -789,6 +789,23 @@
+ }
+
+ /*
++ * remove_option - permanently remove an option from consideration...
++ * for use by modules to remove choices which no longer make sense.
++ * returns true if found an option
++ */
++int
++remove_option(name)
++ char *name;
++{
++ option_t *o;
++ o = find_option(name);
++ if (o == NULL)
++ return 0;
++ o->name = "";
++ return 1;
++}
++
++/*
+ * check_options - check that options are valid and consistent.
+ */
+ void
+diff -r -N -u -b -B ppp-2.4.1.orig/pppd/plugins/Makefile.linux ppp-2.4.1.pppoe2/pppd/plugins/Makefile.linux
+--- ppp-2.4.1.orig/pppd/plugins/Makefile.linux Tue Mar 6 23:21:18 2001
++++ ppp-2.4.1.pppoe2/pppd/plugins/Makefile.linux Sun May 27 08:08:58 2001
+@@ -3,7 +3,10 @@
+ LDFLAGS = -shared
+ INSTALL = install
+
+-all: minconn.so passprompt.so
++all: minconn.so passprompt.so pppoe/pppoe.so
++
++pppoe/pppoe.so:
++ $(MAKE) -C pppoe $(MFLAGS) pppoe.so
+
+ minconn.so: minconn.c
+ $(CC) -o $@ $(LDFLAGS) $(CFLAGS) minconn.c
+@@ -13,7 +16,10 @@
+
+ LIBDIR = /usr/lib/pppd
+
+-install: minconn.so passprompt.so
++install: minconn.so passprompt.so pppoe/pppoe.so
+ version=`awk -F '"' '/VERSION/ { print $$2; }' ../patchlevel.h`; \
+ $(INSTALL) -d $(LIBDIR)/$$version; \
+ $(INSTALL) $? $(LIBDIR)/$$version
+\ No newline at end of file
++
++clean:
++ rm -rf *.o *.so
+\ No newline at end of file
+diff -r -N -u -b -B ppp-2.4.1.orig/pppd/plugins/pppoe/Makefile.linux ppp-2.4.1.pppoe2/pppd/plugins/pppoe/Makefile.linux
+--- ppp-2.4.1.orig/pppd/plugins/pppoe/Makefile.linux Wed Dec 31 19:00:00 1969
++++ ppp-2.4.1.pppoe2/pppd/plugins/pppoe/Makefile.linux Sun May 27 08:08:40 2001
+@@ -0,0 +1,43 @@
++CC = gcc
++CFLAGS = -g -I.. -I../.. -I../../../include -D_linux_=1 -fPIC
++LDFLAGS = -shared
++
++all: pppoe.so pppoed
++
++
++PLUGINDIR = $(LIBDIR)/plugins
++PLUGINSRCS= pppoe.c libpppoe.c utils.c pppoehash.c pppoe_client.c \
++ pppoe_relay.c pppoe_server.c pppd_utils.c
++#
++# include dependancies if present and backup if as a header file
++ifeq (.depend,$(wildcard .depend))
++include .depend
++endif
++
++
++
++pppoefwd: pppoefwd.o libpppoe.a
++ $(CC) -o $@ $^
++
++pppoed: pppoed.o pppd_utils.o libpppoe.a
++ $(CC) -o $@ $^
++
++libpppoe.a: pppoehash.o pppoe_client.o pppoe_relay.o pppoe_server.o \
++ utils.o libpppoe.o
++ ar -rc $@ $^
++
++pppoe.so: pppoe.o libpppoe.a
++ $(CC) -o $@ $(LDFLAGS) $^
++
++%.so: %.c
++ $(CC) -o $@ $(LDFLAGS) $(CFLAGS) $^
++
++clean:
++ rm -f *.o *.so *.a pppoefwd pppoed
++
++
++$(PLUGINDIR):
++ $(INSTALL) -d -m 755 $@
++
++depend:
++ $(CPP) -M $(CFLAGS) $(PLUGINSRCS) >.depend
+diff -r -N -u -b -B ppp-2.4.1.orig/pppd/plugins/pppoe/libpppoe.c ppp-2.4.1.pppoe2/pppd/plugins/pppoe/libpppoe.c
+--- ppp-2.4.1.orig/pppd/plugins/pppoe/libpppoe.c Wed Dec 31 19:00:00 1969
++++ ppp-2.4.1.pppoe2/pppd/plugins/pppoe/libpppoe.c Fri Mar 30 07:40:42 2001
+@@ -0,0 +1,631 @@
++/* PPPoE support library "libpppoe"
++ *
++ * Copyright 2000 Michal Ostrowski <mostrows@styx.uwaterloo.ca>,
++ * Jamal Hadi Salim <hadi@cyberus.ca>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#include "pppoe.h"
++
++int disc_sock=-1;
++
++int verify_packet( struct session *ses, struct pppoe_packet *p);
++
++#define TAG_DATA(type,tag_ptr) ((type *) ((struct pppoe_tag*)tag_ptr)->tag_data)
++
++
++/***************************************************************************
++ *
++ * Return the location where the next tag can be pu
++ *
++ **************************************************************************/
++static struct pppoe_tag *next_tag(struct pppoe_hdr *ph)
++{
++ return (struct pppoe_tag *)
++ (((char *) &ph->tag) + ntohs(ph->length));
++}
++
++/**************************************************************************
++ *
++ * Update header to reflect the addition of a new tag
++ *
++ **************************************************************************/
++static void add_tag(struct pppoe_hdr *ph, struct pppoe_tag *pt)
++{
++ int len = (ntohs(ph->length) +
++ ntohs(pt->tag_len) +
++ sizeof(struct pppoe_tag));
++
++ if (pt != next_tag(ph))
++ printf("PPPoE add_tag caller is buggy\n");
++
++ ph->length = htons(len);
++}
++
++/*************************************************************************
++ *
++ * Look for a tag of a specific type
++ *
++ ************************************************************************/
++struct pppoe_tag *get_tag(struct pppoe_hdr *ph, u_int16_t idx)
++{
++ char *end = (char *) next_tag(ph);
++ char *ptn = NULL;
++ struct pppoe_tag *pt = &ph->tag[0];
++
++ /*
++ * Keep processing tags while a tag header will still fit.
++ *
++ * This check will ensure that the entire tag header pointed
++ * to by pt will fit inside the message, and thus it will be
++ * valid to check the tag_type and tag_len fields.
++ */
++ while ((char *)(pt + 1) <= end) {
++ /*
++ * If the tag data would go past the end of the packet, abort.
++ */
++ ptn = (((char *) (pt + 1)) + ntohs(pt->tag_len));
++ if (ptn > end)
++ return NULL;
++
++ if (pt->tag_type == idx)
++ return pt;
++
++ pt = (struct pppoe_tag *) ptn;
++ }
++
++ return NULL;
++}
++
++/* We want to use tag names to reference into arrays containing the tag data.
++ This takes an RFC 2516 tag identifier and maps it into a local one.
++ The reverse mapping is accomplished via the tag_map array */
++#define UNMAP_TAG(x) case PTT_##x : return TAG_##x
++static inline int tag_index(int tag){
++ switch(tag){
++ UNMAP_TAG(SRV_NAME);
++ UNMAP_TAG(AC_NAME);
++ UNMAP_TAG(HOST_UNIQ);
++ UNMAP_TAG(AC_COOKIE);
++ UNMAP_TAG(VENDOR);
++ UNMAP_TAG(RELAY_SID);
++ UNMAP_TAG(SRV_ERR);
++ UNMAP_TAG(SYS_ERR);
++ UNMAP_TAG(GEN_ERR);
++ UNMAP_TAG(EOL);
++ };
++ return -1;
++}
++
++/*************************************************************************
++ *
++ * Makes a copy of a tag into a PPPoE packe
++ *
++ ************************************************************************/
++void copy_tag(struct pppoe_packet *dest, struct pppoe_tag *pt)
++{
++ struct pppoe_tag *end_tag = get_tag(dest->hdr, PTT_EOL);
++ int tagid;
++ int tag_len;
++ if( !pt ) {
++ return;
++ }
++ tagid = tag_index(pt->tag_type);
++
++ tag_len = sizeof(struct pppoe_tag) + ntohs(pt->tag_len);
++
++ if( end_tag ){
++ memcpy(((char*)end_tag)+tag_len ,
++ end_tag, sizeof(struct pppoe_tag));
++
++ dest->tags[tagid]=end_tag;
++ dest->tags[TAG_EOL] = (struct pppoe_tag*)((char*)dest->tags[TAG_EOL] + tag_len);
++ memcpy(end_tag, pt, tag_len);
++ dest->hdr->length = htons(ntohs(dest->hdr->length) + tag_len);
++
++ }else{
++ memcpy(next_tag(dest->hdr),pt, tag_len);
++ dest->tags[tagid]=next_tag(dest->hdr);
++ add_tag(dest->hdr,next_tag(dest->hdr));
++ }
++
++
++}
++
++
++/*************************************************************************
++ *
++ * Put tags from a packet into a nice array
++ *
++ ************************************************************************/
++static void extract_tags(struct pppoe_hdr *ph, struct pppoe_tag** buf){
++ int i=0;
++ for(;i<MAX_TAGS;++i){
++ buf[i] = get_tag(ph,tag_map[i]);
++ }
++}
++
++
++/*************************************************************************
++ *
++ * Verify that a packet has a tag containint a specific value
++ *
++ ************************************************************************/
++static int verify_tag(struct session* ses,
++ struct pppoe_packet* p,
++ unsigned short id,
++ char* data,
++ int data_len)
++{
++ int len;
++ struct pppoe_tag *pt = p->tags[id];
++
++ if( !pt ){
++ poe_info(ses,"Missing tag %d. Expected %s\n",
++ id,data);
++ return 0;
++ }
++ len = ntohs(pt->tag_len);
++ if(len != data_len){
++ poe_info(ses,"Length mismatch on tag %d: expect: %d got: %d\n",
++ id, data_len, len);
++ return 0;
++ }
++
++ if( 0!=memcmp(pt->tag_data,data,data_len)){
++ poe_info(ses,"Tag data mismatch on tag %d: expect: %s vs %s\n",
++ id, data,pt->tag_data);
++ return 0;
++ }
++ return 1;
++}
++
++
++/*************************************************************************
++ *
++ * Verify the existence of an ethernet device.
++ * Construct an AF_PACKET address struct to match.
++ *
++ ************************************************************************/
++int get_sockaddr_ll(const char *devnam,struct sockaddr_ll* sll){
++ struct ifreq ifr;
++ int retval;
++
++ if(disc_sock<0){
++
++ disc_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
++ if( disc_sock < 0 ){
++ return -1;
++ }
++ }
++
++ strncpy(ifr.ifr_name, devnam, sizeof(ifr.ifr_name));
++
++ retval = ioctl( disc_sock , SIOCGIFINDEX, &ifr);
++
++ if( retval < 0 ){
++// error("Bad device name: %s (%m)",devnam);
++ return 0;
++ }
++
++ if(sll) sll->sll_ifindex = ifr.ifr_ifindex;
++
++ retval = ioctl (disc_sock, SIOCGIFHWADDR, &ifr);
++ if( retval < 0 ){
++// error("Bad device name: %s (%m)",devnam);
++ return 0;
++ }
++
++ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
++ error("Interface %s is not Ethernet!", devnam);
++ return 0;
++ }
++ if(sll){
++ sll->sll_family = AF_PACKET;
++ sll->sll_protocol= ntohs(ETH_P_PPP_DISC);
++ sll->sll_hatype = ARPHRD_ETHER;
++ sll->sll_pkttype = PACKET_BROADCAST;
++ sll->sll_hatype = ETH_ALEN;
++ memcpy( sll->sll_addr , ifr.ifr_hwaddr.sa_data, ETH_ALEN);
++ }
++ return 1;
++}
++
++
++
++
++/*************************************************************************
++ *
++ * Construct and send a discovery message.
++ *
++ ************************************************************************/
++int send_disc(struct session *ses, struct pppoe_packet *p)
++{
++ char buf[MAX_PAYLOAD + sizeof(struct pppoe_hdr)];
++ int data_len = sizeof(struct pppoe_hdr);
++
++ struct pppoe_hdr *ph = NULL;
++ struct pppoe_tag *tag = NULL;
++ int i, error = 0;
++ int got_host_uniq = 0;
++ int got_srv_name = 0;
++ int got_ac_name = 0;
++
++ for (i = 0; i < MAX_TAGS; i++) {
++ if (!p->tags[i])
++ continue;
++
++ got_host_uniq |= (p->tags[i]->tag_type == PTT_HOST_UNIQ);
++
++ /* Relay identifiers qualify as HOST_UNIQ's:
++ we need HOST_UNIQ to uniquely identify the packet,
++ PTT_RELAY_SID is sufficient for us for outgoing packets */
++ got_host_uniq |= (p->tags[i]->tag_type == PTT_RELAY_SID);
++
++ got_srv_name |= (p->tags[i]->tag_type == PTT_SRV_NAME);
++ got_ac_name |= (p->tags[i]->tag_type == PTT_AC_NAME);
++
++ data_len += (ntohs(p->tags[i]->tag_len) +
++ sizeof(struct pppoe_tag));
++ }
++
++ ph = (struct pppoe_hdr *) buf;
++
++
++ memcpy(ph, p->hdr, sizeof(struct pppoe_hdr));
++ ph->length = __constant_htons(0);
++
++ /* if no HOST_UNIQ tags --- add one with process id */
++ if (!got_host_uniq){
++ data_len += (sizeof(struct pppoe_tag) +
++ sizeof(struct session *));
++ tag = next_tag(ph);
++ tag->tag_type = PTT_HOST_UNIQ;
++ tag->tag_len = htons(sizeof(struct session *));
++ memcpy(tag->tag_data,
++ &ses,
++ sizeof(struct session *));
++
++ add_tag(ph, tag);
++ }
++
++ if( !got_srv_name ){
++ data_len += sizeof(struct pppoe_tag);
++ tag = next_tag(ph);
++ tag->tag_type = PTT_SRV_NAME;
++ tag->tag_len = 0;
++ add_tag(ph, tag);
++ }
++
++ if(!got_ac_name && ph->code==PADO_CODE){
++ data_len += sizeof(struct pppoe_tag);
++ tag = next_tag(ph);
++ tag->tag_type = PTT_AC_NAME;
++ tag->tag_len = 0;
++ add_tag(ph, tag);
++ }
++
++ for (i = 0; i < MAX_TAGS; i++) {
++ if (!p->tags[i])
++ continue;
++
++ tag = next_tag(ph);
++ memcpy(tag, p->tags[i],
++ sizeof(struct pppoe_tag) + ntohs(p->tags[i]->tag_len));
++
++ add_tag(ph, tag);
++ }
++
++ /* Now fixup the packet struct to make sure all of its pointers
++ are self-contained */
++ memcpy( p->hdr , ph, data_len );
++ extract_tags( p->hdr, p->tags);
++
++ error = sendto(disc_sock, buf, data_len, 0,
++ (struct sockaddr*) &p->addr,
++ sizeof(struct sockaddr_ll));
++
++ if(error < 0)
++ poe_error(ses,"sendto returned: %m\n");
++
++ return error;
++}
++
++/*************************************************************************
++ *
++ * Verify that a packet is legal
++ *
++ *************************************************************************/
++int verify_packet( struct session *ses, struct pppoe_packet *p){
++ struct session * hu_val;
++
++ /* This code here should do all of the error checking and
++ validation on the incoming packet */
++
++
++ /* If we receive any error tags, abort */
++#define CHECK_TAG(name, val) \
++ if((NULL==p->tags[name])== val){ \
++ poe_error(ses,"Tag error: " #name ); \
++ return -1; \
++ }
++
++
++
++ CHECK_TAG(TAG_SRV_ERR,0);
++ CHECK_TAG(TAG_SYS_ERR,0);
++ CHECK_TAG(TAG_GEN_ERR,0);
++
++ /* A HOST_UNIQ must be present */
++ CHECK_TAG(TAG_HOST_UNIQ,1);
++
++ hu_val = *TAG_DATA(struct session* ,p->tags[TAG_HOST_UNIQ]);
++
++ if( hu_val != ses ){
++ poe_info(ses,"HOST_UNIQ mismatch: %08x %i\n",(int)hu_val,getpid());
++ return -1;
++ }
++
++ if(ses->filt->htag &&
++ !verify_tag(ses,p,TAG_HOST_UNIQ,ses->filt->htag->tag_data,(int)ntohs(ses->filt->htag->tag_len)))
++ return -1;
++ else
++ poe_info(ses,"HOST_UNIQ successful match\n");
++
++
++ if(ses->filt->ntag &&
++ !verify_tag(ses,p,TAG_AC_NAME,ses->filt->ntag->tag_data,(int)ntohs(ses->filt->ntag->tag_len))){
++ poe_info(ses,"AC_NAME failure");
++ return -1;
++ }
++
++ if(ses->filt->stag &&
++ !verify_tag(ses,p,TAG_SRV_NAME,ses->filt->stag->tag_data,(int)ntohs(ses->filt->stag->tag_len))){
++ poe_info(ses,"SRV_NAME failure");
++ return -1;
++ }
++
++}
++
++
++/*************************************************************************
++ *
++ * Receive and verify an incoming packet.
++ *
++ *************************************************************************/
++static int recv_disc( struct session *ses,
++ struct pppoe_packet *p){
++ int error = 0;
++ unsigned int from_len = sizeof(struct sockaddr_ll);
++ struct session* hu_val;
++ struct pppoe_tag *pt;
++
++ p->hdr = (struct pppoe_hdr*)p->buf;
++
++ error = recvfrom( disc_sock, p->buf, 1500, 0,
++ (struct sockaddr*)&p->addr, &from_len);
++
++ if(error < 0) return error;
++
++ extract_tags(p->hdr,p->tags);
++
++ return 1;
++}
++
++
++/*************************************************************************
++ *
++ * Send a PADT
++ *
++ *************************************************************************/
++int session_disconnect(struct session *ses){
++ struct pppoe_packet padt;
++
++ memset(&padt,0,sizeof(struct pppoe_packet));
++ memcpy(&padt.addr, &ses->remote, sizeof(struct sockaddr_ll));
++
++ padt.hdr = (struct pppoe_hdr*) ses->curr_pkt.buf;
++ padt.hdr->ver = 1;
++ padt.hdr->type = 1;
++ padt.hdr->code = PADT_CODE;
++ padt.hdr->sid = ses->sp.sa_addr.pppoe.sid;
++
++ send_disc(ses,&padt);
++ ses->sp.sa_addr.pppoe.sid = 0 ;
++ ses->state = PADO_CODE;
++ return 0;
++
++}
++
++
++/*************************************************************************
++ *
++ * Make a connection -- behaviour depends on callbacks specified in "ses"
++ *
++ *************************************************************************/
++int session_connect(struct session *ses)
++{
++
++ int pkt_size=0;
++ int ret_pkt_size=0;
++ struct pppoe_tag *tags = NULL;
++ struct pppoe_packet *p_out=NULL;
++ struct pppoe_packet rcv_packet;
++ int ret;
++
++
++ if(ses->init_disc){
++ ret = (*ses->init_disc)(ses, NULL, &p_out);
++ if( ret != 0 ) return ret;
++ }
++
++ /* main discovery loop */
++
++
++ while(ses->retransmits < ses->retries || ses->retries==-1 ){
++
++ fd_set in;
++ struct timeval tv;
++ FD_ZERO(&in);
++
++ FD_SET(disc_sock,&in);
++
++ if(ses->retransmits>=0){
++ ++ses->retransmits;
++ tv.tv_sec = 1 << ses->retransmits;
++ tv.tv_usec = 0;
++ ret = select(disc_sock+1, &in, NULL, NULL, &tv);
++ }else{
++ ret = select(disc_sock+1, &in, NULL, NULL, NULL);
++ }
++
++ if( ret == 0 ){
++ if( DEB_DISC ){
++ poe_dbglog(ses, "Re-sending ...");
++ }
++
++ if( ses->timeout ){
++ ret = (*ses->timeout)(ses, NULL, &p_out);
++ if( ret != 0 )
++ return ret;
++
++ }else if(p_out){
++ send_disc(ses,p_out);
++ }
++ continue;
++ }
++
++
++ ret = recv_disc(ses, &rcv_packet);
++
++ /* Should differentiate between system errors and
++ bad packets and the like... */
++ if( ret < 0 && errno != EINTR){
++
++ return -1;
++ }
++
++
++
++
++ switch (rcv_packet.hdr->code) {
++
++ case PADI_CODE:
++ {
++ if(ses->rcv_padi){
++ ret = (*ses->rcv_padi)(ses,&rcv_packet,&p_out);
++
++ if( ret != 0){
++ return ret;
++ }
++ }
++ break;
++ }
++
++ case PADO_CODE: /* wait for PADO */
++ {
++ if(ses->rcv_pado){
++ ret = (*ses->rcv_pado)(ses,&rcv_packet,&p_out);
++
++ if( ret != 0){
++ return ret;
++ }
++ }
++ break;
++ }
++
++ case PADR_CODE:
++ {
++ if(ses->rcv_padr){
++ ret = (*ses->rcv_padr)(ses,&rcv_packet,&p_out);
++
++ if( ret != 0){
++ return ret;
++ }
++ }
++ break;
++ }
++
++ case PADS_CODE:
++ {
++ if(ses->rcv_pads){
++ ret = (*ses->rcv_pads)(ses,&rcv_packet,&p_out);
++
++ if( ret != 0){
++ return ret;
++ }
++ }
++ break;
++ }
++
++ case PADT_CODE:
++ {
++ if( rcv_packet.hdr->sid != ses->sp.sa_addr.pppoe.sid ){
++ --ses->retransmits;
++ continue;
++ }
++ if(ses->rcv_padt){
++ ret = (*ses->rcv_padt)(ses,&rcv_packet,&p_out);
++
++ if( ret != 0){
++ return ret;
++ }
++ }else{
++ poe_error (ses,"connection terminated");
++ return (-1);
++ }
++ break;
++ }
++ default:
++ poe_error(ses,"invalid packet %P",&rcv_packet);
++ return (-1);
++ }
++ }
++ return (0);
++}
++
++
++/*************************************************************************
++ *
++ * Register an ethernet address as a client of relaying services.
++ *
++ *************************************************************************/
++int add_client(char *addr)
++{
++ struct pppoe_con* pc = (struct pppoe_con*)malloc(sizeof(struct pppoe_con));
++ int ret;
++ if(!pc)
++ return -ENOMEM;
++
++ memset(pc, 0 , sizeof(struct pppoe_con));
++
++ memcpy(pc->client,addr, ETH_ALEN);
++ memcpy(pc->key, addr, ETH_ALEN);
++
++ pc->key_len = ETH_ALEN;
++
++ if( (ret=store_con(pc)) < 0 ){
++ free(pc);
++ }
++ return ret;
++
++}
++
++struct pppoe_tag *make_filter_tag(short type, short length, char* data){
++ struct pppoe_tag *pt =
++ (struct pppoe_tag* )malloc( sizeof(struct pppoe_tag) + length );
++
++ if(pt == NULL) return NULL;
++
++ pt->tag_len=htons(length);
++ pt->tag_type=type;
++
++ if(length>0 && data){
++ memcpy( pt+1, data, length);
++ }
++ return pt;
++}
+diff -r -N -u -b -B ppp-2.4.1.orig/pppd/plugins/pppoe/pppd_utils.c ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppd_utils.c
+--- ppp-2.4.1.orig/pppd/plugins/pppoe/pppd_utils.c Wed Dec 31 19:00:00 1969
++++ ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppd_utils.c Sun Aug 6 11:39:28 2000
+@@ -0,0 +1,162 @@
++/* PPPoE support library "libpppoe"
++ *
++ * Copyright 2000 Michal Ostrowski <mostrows@styx.uwaterloo.ca>,
++ * Jamal Hadi Salim <hadi@cyberus.ca>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++#include "pppoe.h"
++
++/*
++ *
++ */
++int build_ppp_opts(char *args[],struct session *ses)
++{
++ char buf[256];
++ int retval=0,i=0;
++
++ memset(buf,0,256);
++
++/* pppds path */
++ if ( NULL != ses->filt->pppd){
++ args[0]=(char *)malloc(strlen(ses->filt->pppd));
++ strcpy (args[0],ses->filt->pppd);
++ } else {
++ args[0]=(char *)malloc(strlen(_PATH_PPPD));
++ strcpy (args[0],_PATH_PPPD);
++ }
++
++/* long device name */
++ snprintf(buf, 256,"%02x:%02x:%02x:%02x:%02x:%02x/%04x/%s",
++ ses->remote.sll_addr[0],
++ ses->remote.sll_addr[1],
++ ses->remote.sll_addr[2],
++ ses->remote.sll_addr[3],
++ ses->remote.sll_addr[4],
++ ses->remote.sll_addr[5],
++ ses->sp.sa_addr.pppoe.sid,
++ ses->name);
++ args[1]=(char *)malloc(strlen(buf));
++ strcpy(args[1],buf);
++
++ i=2;
++
++/* override options file */
++ if (NULL != ses->filt->fname ) {
++
++ if (!ses->filt->peermode) {
++ args[i]=(char *)malloc(strlen("file"));
++ strcpy (args[i],"file");
++ i++;
++ args[i]=(char *)malloc(strlen(ses->filt->fname)+1);
++ strcpy (args[i],ses->filt->fname);
++ i++;
++ } else{ /* peermode */
++ args[i]=(char *)malloc(strlen("call"));
++ strcpy (args[i],"call");
++ i++;
++ args[i]=(char *)malloc(strlen(ses->filt->fname)+1);
++ strcpy (args[i],ses->filt->fname);
++ i++;
++ }
++ }
++
++/* user requested for a specific name */
++ if (NULL != ses->filt->ntag) {
++ if ( NULL != ses->filt->ntag->tag_data) {
++ args[i]=(char *)malloc(strlen("pppoe_ac_name"));
++ strcpy(args[i],"pppoe_ac_name");
++ i++;
++ args[i]=(char *)malloc(ntohs(ses->filt->ntag->tag_len));
++ strcpy(args[i],ses->filt->ntag->tag_data);
++ i++;
++ }
++ }
++/* user requested for a specific service name */
++ if (NULL != ses->filt->stag) {
++ if ( NULL != ses->filt->stag->tag_data) {
++ args[i]=(char *)malloc(strlen("pppoe_srv_name"));
++ strcpy(args[i],"pppoe_srv_name");
++ i++;
++ args[i]=(char *)malloc(ntohs(ses->filt->stag->tag_len));
++ strcpy(args[i],ses->filt->stag->tag_data);
++ i++;
++ }
++ }
++
++/*
++ */
++ if (ses->opt_daemonize) {
++ args[i]=(char *)malloc(strlen("nodetach"));
++ strcpy(args[i],"nodetach");
++ i++;
++ }
++
++ args[i]=NULL;
++ {
++ int j;
++ poe_info(ses,"calling pppd with %d args\n",i);
++ j=i;
++ for (i=0; i<j,NULL !=args[i]; i++) {
++ poe_info(ses," <%d: %s > \n",i,args[i]);
++ }
++ }
++ return retval;
++}
++
++
++/*
++ *
++ */
++int ppp_connect (struct session *ses)
++{
++ int ret,pid;
++ char *args[32];
++
++
++ poe_info(ses,"calling ses_connect\n");
++ do{
++ ret = session_connect(ses);
++ }while(ret == 0);
++
++ if (ret > 0 )
++ if (ses->np == 1 && ret == 1)
++ return ses->np; /* -G */
++ if (ses->np == 2)
++ return ses->np; /* -H */
++
++ if( ret <= 0){
++ return ret;
++ }
++
++ poe_info(ses,"DONE calling ses_connect np is %d \n",ses->np);
++
++
++ pid = fork ();
++ if (pid < 0) {
++ poe_error (ses,"unable to fork() for pppd: %m");
++ poe_die (-1);
++ }
++
++
++ if(!pid) {
++ poe_info(ses,"calling build_ppp_opts\n");
++ if (0> build_ppp_opts(args,ses)) {
++ poe_error(ses,"ppp_connect: failed to build ppp_opts\n");
++ return -1;
++ }
++ execvp(args[0],args);
++ poe_info (ses," child got killed");
++ } else if( ses->type == SESSION_CLIENT) {
++ if (!ses->opt_daemonize)
++ return 1;
++ pause();
++ poe_info (ses," OK we got killed");
++ return -1;
++ }
++ return 1;
++}
++
+diff -r -N -u -b -B ppp-2.4.1.orig/pppd/plugins/pppoe/pppoe.c ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppoe.c
+--- ppp-2.4.1.orig/pppd/plugins/pppoe/pppoe.c Wed Dec 31 19:00:00 1969
++++ ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppoe.c Sat May 26 23:35:01 2001
+@@ -0,0 +1,385 @@
++/* pppoe.c - pppd plugin to implement PPPoE protocol.
++ *
++ * Copyright 2000 Michal Ostrowski <mostrows@styx.uwaterloo.ca>,
++ * Jamal Hadi Salim <hadi@cyberus.ca>
++ * Borrows heavily from the PPPoATM plugin by Mitchell Blank Jr.,
++ * which is based in part on work from Jens Axboe and Paul Mackerras.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#include <string.h>
++#include <sys/ioctl.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <unistd.h>
++#include <errno.h>
++#include <sys/stat.h>
++#include "pppoe.h"
++#if _linux_
++extern int new_style_driver; /* From sys-linux.c */
++#include <linux/ppp_defs.h>
++#include <linux/if_pppox.h>
++#include <linux/if_ppp.h>
++#else
++#error this module meant for use with linux only at this time
++#endif
++
++
++#include "pppd.h"
++#include "fsm.h"
++#include "lcp.h"
++#include "ipcp.h"
++#include "ccp.h"
++#include "pathnames.h"
++
++const char pppd_version[] = VERSION;
++
++#define _PATH_ETHOPT _ROOT_PATH "/etc/ppp/options."
++
++#define PPPOE_MTU 1492
++extern int kill_link;
++static char *bad_options[] = {
++ "noaccomp",
++ "-ac",
++ "default-asyncmap",
++ "-am",
++ "asyncmap",
++ "-as",
++ "escape",
++ "multilink",
++ "receive-all",
++ "crtscts",
++ "-crtscts",
++ "nocrtscts",
++ "cdtrcts",
++ "nocdtrcts",
++ "xonxoff",
++ "modem",
++ "local",
++ "sync",
++ "deflate",
++ "nodeflate",
++ "vj",
++ "novj",
++ "nobsdcomp",
++ "bsdcomp",
++ "-bsdcomp",
++ NULL
++};
++
++bool pppoe_server=0;
++char *pppoe_srv_name=NULL;
++char *pppoe_ac_name=NULL;
++char *hostuniq = NULL;
++int retries = 0;
++
++int setdevname_pppoe(const char *cp);
++
++static option_t pppoe_options[] = {
++ { "device name", o_wild, (void *) &setdevname_pppoe,
++ "Serial port device name",
++ OPT_DEVNAM | OPT_PRIVFIX | OPT_NOARG | OPT_A2STRVAL | OPT_STATIC,
++ devnam},
++ { "pppoe_srv_name", o_string, &pppoe_srv_name,
++ "PPPoE service name"},
++ { "pppoe_ac_name", o_string, &pppoe_ac_name,
++ "PPPoE access concentrator name"},
++ { "pppoe_hostuniq", o_string, &hostuniq,
++ "PPPoE client uniq hostid "},
++ { "pppoe_retransmit", o_int, &retries,
++ "PPPoE client number of retransmit tries"},
++ { "pppoe_server", o_bool, &pppoe_server,
++ "PPPoE listen for incoming requests",1},
++ { NULL }
++};
++
++
++
++struct session *ses = NULL;
++static int connect_pppoe_ses(void)
++{
++ int i,err=-1;
++ if( pppoe_server == 1 ){
++ srv_init_ses(ses,devnam);
++ }else{
++ client_init_ses(ses,devnam);
++ }
++#if 0
++ ses->np=1; /* jamal debug the discovery portion */
++#endif
++ strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
++
++ err= session_connect ( ses );
++
++ if(err < 0){
++ poe_fatal(ses,"Failed to negotiate PPPoE connection: %d %m",errno,errno);
++ }
++
++
++ poe_info(ses,"Connecting PPPoE socket: %E %04x %s %p",
++ ses->sp.sa_addr.pppoe.remote,
++ ses->sp.sa_addr.pppoe.sid,
++ ses->sp.sa_addr.pppoe.dev,ses);
++
++ err = connect(ses->fd, (struct sockaddr*)&ses->sp,
++ sizeof(struct sockaddr_pppox));
++
++
++ if( err < 0 ){
++ poe_fatal(ses,"Failed to connect PPPoE socket: %d %m",errno,errno);
++ return err;
++ }
++#if 0
++ if (ses->np)
++ fatal("discovery complete\n");
++#endif
++ /* Once the logging is fixed, print a message here indicating
++ connection parameters */
++
++ return ses->fd;
++}
++
++static void disconnect_pppoe_ses(void)
++{
++ int ret;
++ warn("Doing disconnect");
++ session_disconnect(ses);
++ ses->sp.sa_addr.pppoe.sid = 0;
++ ret = connect(ses->fd, (struct sockaddr*)&ses->sp,
++ sizeof(struct sockaddr_pppox));
++
++}
++
++
++static int setspeed_pppoe(const char *cp)
++{
++ return 0;
++}
++
++static void init_device_pppoe(void)
++{
++ struct filter *filt;
++ unsigned int size=0;
++ ses=(void *)malloc(sizeof(struct session));
++ if(!ses){
++ fatal("No memory for new PPPoE session");
++ }
++ memset(ses,0,sizeof(struct session));
++
++ if ((ses->filt=malloc(sizeof(struct filter))) == NULL) {
++ poe_error (ses,"failed to malloc for Filter ");
++ poe_die (-1);
++ }
++
++ filt=ses->filt; /* makes the code more readable */
++ memset(filt,0,sizeof(struct filter));
++
++ if (pppoe_ac_name !=NULL) {
++ if (strlen (pppoe_ac_name) > 255) {
++ poe_error (ses," AC name too long (maximum allowed 256 chars)");
++ poe_die(-1);
++ }
++ ses->filt->ntag = make_filter_tag(PTT_AC_NAME,
++ strlen(pppoe_ac_name),
++ pppoe_ac_name);
++
++ if ( ses->filt->ntag== NULL) {
++ poe_error (ses,"failed to malloc for AC name");
++ poe_die(-1);
++ }
++
++ }
++
++
++ if (pppoe_srv_name !=NULL) {
++ if (strlen (pppoe_srv_name) > 255) {
++ poe_error (ses," Service name too long
++ (maximum allowed 256 chars)");
++ poe_die(-1);
++ }
++ ses->filt->stag = make_filter_tag(PTT_SRV_NAME,
++ strlen(pppoe_srv_name),
++ pppoe_srv_name);
++ if ( ses->filt->stag == NULL) {
++ poe_error (ses,"failed to malloc for service name");
++ poe_die(-1);
++ }
++ }
++
++ if (hostuniq) {
++ ses->filt->htag = make_filter_tag(PTT_HOST_UNIQ,
++ strlen(hostuniq),
++ hostuniq);
++ if ( ses->filt->htag == NULL) {
++ poe_error (ses,"failed to malloc for Uniq Host Id ");
++ poe_die(-1);
++ }
++ }
++
++ if (retries) {
++ ses->retries=retries;
++ }
++
++ memcpy( ses->name, devnam, IFNAMSIZ);
++ ses->opt_debug=1;
++}
++
++static void pppoe_extra_options()
++{
++ int ret;
++ char buf[256];
++ snprintf(buf, 256, _PATH_ETHOPT "%s",devnam);
++ if(!options_from_file(buf, 0, 0, 1))
++ exit(EXIT_OPTION_ERROR);
++
++}
++
++
++
++static void send_config_pppoe(int mtu,
++ u_int32_t asyncmap,
++ int pcomp,
++ int accomp)
++{
++ int sock;
++ struct ifreq ifr;
++
++ if (mtu > PPPOE_MTU)
++ warn("Couldn't increase MTU to %d", mtu);
++ sock = socket(AF_INET, SOCK_DGRAM, 0);
++ if (sock < 0)
++ fatal("Couldn't create IP socket: %m");
++ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
++ ifr.ifr_mtu = mtu;
++ if (ioctl(sock, SIOCSIFMTU, (caddr_t) &ifr) < 0)
++ fatal("ioctl(SIOCSIFMTU): %m");
++ (void) close (sock);
++}
++
++
++static void recv_config_pppoe(int mru,
++ u_int32_t asyncmap,
++ int pcomp,
++ int accomp)
++{
++ if (mru > PPPOE_MTU)
++ error("Couldn't increase MRU to %d", mru);
++}
++
++static void set_xaccm_pppoe(int unit, ext_accm accm)
++{
++ /* NOTHING */
++}
++
++
++
++struct channel pppoe_channel;
++/* Check is cp is a valid ethernet device
++ * return either 1 if "cp" is a reasonable thing to name a device
++ * or die.
++ * Note that we don't actually open the device at this point
++ * We do need to fill in:
++ * devnam: a string representation of the device
++ */
++
++int (*old_setdevname_hook)(const char* cp) = NULL;
++int setdevname_pppoe(const char *cp)
++{
++ int ret;
++ char dev[IFNAMSIZ+1];
++ int addr[ETH_ALEN];
++ int sid;
++
++ char **a;
++ ret =sscanf(cp, FMTSTRING(IFNAMSIZ),addr, addr+1, addr+2,
++ addr+3, addr+4, addr+5,&sid,dev);
++ if( ret != 8 ){
++
++ ret = get_sockaddr_ll(cp,NULL);
++ if (ret < 0)
++ fatal("PPPoE: Cannot create PF_PACKET socket for PPPoE discovery\n");
++ if (ret == 1)
++ strncpy(devnam, cp, sizeof(devnam));
++ }else{
++ /* long form parsed */
++ ret = get_sockaddr_ll(dev,NULL);
++ if (ret < 0)
++ fatal("PPPoE: Cannot create PF_PACKET socket for PPPoE discovery\n");
++
++ strncpy(devnam, cp, sizeof(devnam));
++ ret = 1;
++ }
++
++
++ if( ret == 1 && the_channel != &pppoe_channel ){
++
++ the_channel = &pppoe_channel;
++
++ {
++ char **a;
++ for (a = bad_options; *a != NULL; a++)
++ remove_option(*a);
++ }
++ modem = 0;
++
++ lcp_allowoptions[0].neg_accompression = 0;
++ lcp_wantoptions[0].neg_accompression = 0;
++
++ lcp_allowoptions[0].neg_asyncmap = 0;
++ lcp_wantoptions[0].neg_asyncmap = 0;
++
++ lcp_allowoptions[0].neg_pcompression = 0;
++ lcp_wantoptions[0].neg_pcompression = 0;
++
++ ccp_allowoptions[0].deflate = 0 ;
++ ccp_wantoptions[0].deflate = 0 ;
++
++ ipcp_allowoptions[0].neg_vj=0;
++ ipcp_wantoptions[0].neg_vj=0;
++
++ ccp_allowoptions[0].bsd_compress = 0;
++ ccp_wantoptions[0].bsd_compress = 0;
++
++ init_device_pppoe();
++ }
++ return ret;
++}
++
++
++
++void plugin_init(void)
++{
++/*
++ fatal("PPPoE plugin loading...");
++*/
++
++#if _linux_
++ if (!ppp_available() && !new_style_driver)
++ fatal("Kernel doesn't support ppp_generic needed for PPPoE");
++#else
++ fatal("No PPPoE support on this OS");
++#endif
++ add_options(pppoe_options);
++
++
++ info("PPPoE Plugin Initialized");
++}
++
++struct channel pppoe_channel = {
++ options: pppoe_options,
++ process_extra_options: &pppoe_extra_options,
++ check_options: NULL,
++ connect: &connect_pppoe_ses,
++ disconnect: &disconnect_pppoe_ses,
++ establish_ppp: &generic_establish_ppp,
++ disestablish_ppp: &generic_disestablish_ppp,
++ send_config: &send_config_pppoe,
++ recv_config: &recv_config_pppoe,
++ close: NULL,
++ cleanup: NULL
++};
++
+diff -r -N -u -b -B ppp-2.4.1.orig/pppd/plugins/pppoe/pppoe.h ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppoe.h
+--- ppp-2.4.1.orig/pppd/plugins/pppoe/pppoe.h Wed Dec 31 19:00:00 1969
++++ ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppoe.h Sat Mar 31 19:20:14 2001
+@@ -0,0 +1,273 @@
++/* PPPoE support library "libpppoe"
++ *
++ * Copyright 2000 Michal Ostrowski <mostrows@styx.uwaterloo.ca>,
++ * Jamal Hadi Salim <hadi@cyberus.ca>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#ifndef PPPOE_H
++#define PPPOE_H 1
++#include <stdio.h> /* stdio */
++#include <stdlib.h> /* strtoul(), realloc() */
++#include <unistd.h> /* STDIN_FILENO,exec */
++#include <string.h> /* memcpy() */
++#include <errno.h> /* errno */
++#include <signal.h>
++#include <getopt.h>
++#include <stdarg.h>
++#include <syslog.h>
++#include <paths.h>
++
++#include <sys/types.h> /* socket types */
++#include <asm/types.h>
++#include <sys/time.h>
++#include <sys/wait.h>
++#include <sys/fcntl.h>
++#include <sys/ioctl.h> /* ioctl() */
++#include <sys/select.h>
++#include <sys/socket.h> /* socket() */
++#include <net/if.h> /* ifreq struct */
++#include <net/if_arp.h>
++#include <netinet/in.h>
++
++#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
++#include <netpacket/packet.h>
++//#include <net/ethernet.h>
++#else
++#include <asm/types.h>
++#include <linux/if_packet.h>
++#include <linux/if_ether.h>
++#endif
++
++
++#include <asm/byteorder.h>
++
++/*
++ jamal: we really have to change this
++ to make it compatible to the 2.2 and
++ 2.3 kernel
++*/
++
++#include <linux/if_pppox.h>
++
++
++#define CONNECTED 1
++#define DISCONNECTED 0
++
++#ifndef _PATH_PPPD
++#define _PATH_PPPD "/usr/sbin/pppd"
++#endif
++
++#ifndef LOG_PPPOE
++#define LOG_PPPOE LOG_DAEMON
++#endif
++
++
++#define VERSION_MAJOR 0
++#define VERSION_MINOR 4
++#define VERSION_DATE 991120
++
++/* Bigger than the biggest ethernet packet we'll ever see, in bytes */
++#define MAX_PACKET 2000
++
++/* references: RFC 2516 */
++/* ETHER_TYPE fields for PPPoE */
++
++#define ETH_P_PPPOE_DISC 0x8863 /* discovery stage */
++#define ETH_P_PPPOE_SESS 0x8864
++
++/* ethernet broadcast address */
++#define MAC_BCAST_ADDR "\xff\xff\xff\xff\xff\xff"
++
++/* Format for parsing long device-name */
++#define _STR(x) #x
++#define FMTSTRING(size) "%x:%x:%x:%x:%x:%x/%x/%" _STR(size) "s"
++
++/* maximum payload length */
++#define MAX_PAYLOAD 1484
++
++
++
++/* PPPoE tag types */
++#define MAX_TAGS 11
++
++
++/* PPPoE packet; includes Ethernet headers and such */
++struct pppoe_packet{
++ struct sockaddr_ll addr;
++ struct pppoe_tag *tags[MAX_TAGS];
++ struct pppoe_hdr *hdr;
++ char buf[MAX_PAYLOAD]; /* buffer in which tags are held */
++};
++/* Defines meaning of each "tags" element */
++
++#define TAG_SRV_NAME 0
++#define TAG_AC_NAME 1
++#define TAG_HOST_UNIQ 2
++#define TAG_AC_COOKIE 3
++#define TAG_VENDOR 4
++#define TAG_RELAY_SID 5
++#define TAG_SRV_ERR 6
++#define TAG_SYS_ERR 7
++#define TAG_GEN_ERR 8
++#define TAG_EOL 9
++
++static int tag_map[] = { PTT_SRV_NAME,
++ PTT_AC_NAME,
++ PTT_HOST_UNIQ,
++ PTT_AC_COOKIE,
++ PTT_VENDOR,
++ PTT_RELAY_SID,
++ PTT_SRV_ERR,
++ PTT_SYS_ERR,
++ PTT_GEN_ERR,
++ PTT_EOL
++};
++
++
++/* Debug flags */
++int DEB_DISC,DEB_DISC2;
++/*
++ #define DEB_DISC (opt_debug & 0x0002)
++ #define DEB_DISC2 (opt_debug & 0x0004)
++*/
++#define MAX_FNAME 256
++
++
++struct session;
++
++/* return <0 --> fatal error; abor
++ return =0 --> ok, proceed
++ return >0 --> ok, qui
++*/
++typedef int (*packet_cb_t)(struct session* ses,
++ struct pppoe_packet *p_in,
++ struct pppoe_packet **p_out);
++
++/* various override filter tags */
++struct filter {
++ struct pppoe_tag *stag; /* service name tag override */
++ struct pppoe_tag *ntag; /*AC name override */
++ struct pppoe_tag *htag; /* hostuniq override */
++ int num_restart;
++ int peermode;
++ char *fname;
++ char *pppd;
++} __attribute__ ((packed));
++
++
++struct pppoe_tag *make_filter_tag(short type, short length, char* data);
++
++/* Session type definitions */
++#define SESSION_CLIENT 0
++#define SESSION_SERVER 1
++#define SESSION_RELAY 2
++
++struct session {
++
++ /* Administrative */
++ int type;
++ int opt_debug;
++ int detached;
++ int np;
++ int log_to_fd;
++ int ifindex; /* index of device */
++ char name[IFNAMSIZ]; /*dev name */
++ struct pppoe_packet curr_pkt;
++
++ packet_cb_t init_disc;
++ packet_cb_t rcv_pado;
++ packet_cb_t rcv_padi;
++ packet_cb_t rcv_pads;
++ packet_cb_t rcv_padr;
++ packet_cb_t rcv_padt;
++ packet_cb_t timeout;
++
++
++ /* Generic */
++ struct filter *filt;
++ struct sockaddr_ll local;
++ struct sockaddr_ll remote;
++ struct sockaddr_pppox sp;
++ int fd; /* fd of PPPoE socket */
++
++
++ /* For client */
++ int retransmits; /* Number of retransmission performed
++ if < 0 , retransmissions disabled */
++ int retries;
++ int state;
++ int opt_daemonize;
++
++ /* For server */
++ int fork;
++
++ /* For forwarding */
++ int fwd_sock;
++ char fwd_name[IFNAMSIZ]; /* Name of device to forward to */
++} __attribute__ ((packed));
++
++/*
++ retransmit retries for the PADR and PADI packets
++ during discovery
++*/
++int PADR_ret;
++int PADI_ret;
++
++int log_to_fd;
++int ctrl_fd;
++int opt_debug;
++int opt_daemonize;
++
++
++/* Structure for keeping track of connection relays */
++struct pppoe_con{
++ struct pppoe_con *next;
++ int id;
++ int connected;
++ int cl_sock;
++ int sv_sock;
++ int ref_count;
++ char client[ETH_ALEN];
++ char server[ETH_ALEN];
++ char key_len;
++ char key[32];
++};
++
++/* Functions exported from utils.c. */
++
++/* Functions exported from pppoehash.c */
++struct pppoe_con *get_con(int len, char *key);
++int store_con(struct pppoe_con *pc);
++struct pppoe_con *delete_con(unsigned long len, char *key);
++
++/* exported by lib.c */
++
++extern int init_lib();
++
++extern int get_sockaddr_ll(const char *devnam,struct sockaddr_ll* sll);
++
++extern int client_init_ses (struct session *ses, char* devnam);
++extern int relay_init_ses(struct session *ses, char* from, char* to);
++extern int srv_init_ses(struct session *ses, char* from);
++extern int session_connect(struct session *ses);
++extern int session_disconnect(struct session*ses);
++
++extern int verify_packet( struct session *ses, struct pppoe_packet *p);
++
++extern void copy_tag(struct pppoe_packet *dest, struct pppoe_tag *pt);
++extern struct pppoe_tag *get_tag(struct pppoe_hdr *ph, u_int16_t idx);
++extern int send_disc(struct session *ses, struct pppoe_packet *p);
++
++
++extern int add_client(char *addr);
++
++/* Make connections (including spawning pppd) as server/client */
++extern ppp_connect(struct session *ses);
++
++
++#endif
+Binary files ppp-2.4.1.orig/pppd/plugins/pppoe/pppoe.so and ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppoe.so differ
+diff -r -N -u -b -B ppp-2.4.1.orig/pppd/plugins/pppoe/pppoe_client.c ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppoe_client.c
+--- ppp-2.4.1.orig/pppd/plugins/pppoe/pppoe_client.c Wed Dec 31 19:00:00 1969
++++ ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppoe_client.c Sun Aug 6 11:39:28 2000
+@@ -0,0 +1,232 @@
++/* PPPoE support library "libpppoe"
++ *
++ * Copyright 2000 Michal Ostrowski <mostrows@styx.uwaterloo.ca>,
++ * Jamal Hadi Salim <hadi@cyberus.ca>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#include "pppoe.h"
++
++
++
++static int std_rcv_pado(struct session* ses,
++ struct pppoe_packet *p_in,
++ struct pppoe_packet **p_out){
++
++ if( verify_packet(ses, p_in) < 0)
++ return -1;
++
++ if(ses->state != PADO_CODE ){
++ poe_error(ses,"Unexpected packet: %P",p_in);
++ return 0;
++ }
++
++
++ if (DEB_DISC2) {
++ poe_dbglog (ses,"PADO received: %P", p_in);
++ }
++
++ memcpy(&ses->remote, &p_in->addr, sizeof(struct sockaddr_ll));
++ memcpy( &ses->curr_pkt.addr, &ses->remote , sizeof(struct sockaddr_ll));
++
++ ses->curr_pkt.hdr->code = PADR_CODE;
++
++ /* The HOST_UNIQ has been verified already... there's no "if" about this */
++ /* if(ses->filt->htag) */
++ copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_HOST_UNIQ));
++
++ if (ses->filt->ntag) {
++ ses->curr_pkt.tags[TAG_AC_NAME]=NULL;
++ }
++// copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_AC_NAME));
++
++ if(ses->filt->stag) {
++ ses->curr_pkt.tags[TAG_SRV_NAME]=NULL;
++ }
++ copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_SRV_NAME));
++
++ copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_AC_COOKIE));
++ copy_tag(&ses->curr_pkt,get_tag(p_in->hdr,PTT_RELAY_SID));
++
++ ses->state = PADS_CODE;
++
++ ses->retransmits = 0;
++
++ send_disc(ses, &ses->curr_pkt);
++ (*p_out) = &ses->curr_pkt;
++
++ if (ses->np)
++ return 1;
++
++ return 0;
++}
++
++static int std_init_disc(struct session* ses,
++ struct pppoe_packet *p_in,
++ struct pppoe_packet **p_out){
++
++ memset(&ses->curr_pkt,0, sizeof(struct pppoe_packet));
++
++
++ /* Check if already connected */
++ if( ses->state != PADO_CODE ){
++ return 1;
++ }
++
++ ses->curr_pkt.hdr = (struct pppoe_hdr*) ses->curr_pkt.buf;
++ ses->curr_pkt.hdr->ver = 1;
++ ses->curr_pkt.hdr->type = 1;
++ ses->curr_pkt.hdr->code = PADI_CODE;
++
++
++ memcpy( &ses->curr_pkt.addr, &ses->remote , sizeof(struct sockaddr_ll));
++
++ poe_info (ses,"Sending PADI");
++ if (DEB_DISC)
++ poe_dbglog (ses,"Sending PADI");
++
++ ses->retransmits = 0 ;
++
++ if(ses->filt->ntag) {
++ ses->curr_pkt.tags[TAG_AC_NAME]=ses->filt->ntag;
++ poe_info(ses,"overriding AC name\n");
++ }
++
++ if(ses->filt->stag)
++ ses->curr_pkt.tags[TAG_SRV_NAME]=ses->filt->stag;
++
++ if(ses->filt->htag)
++ ses->curr_pkt.tags[TAG_HOST_UNIQ]=ses->filt->htag;
++
++ send_disc(ses, &ses->curr_pkt);
++ (*p_out)= &ses->curr_pkt;
++ return 0;
++}
++
++
++static int std_rcv_pads(struct session* ses,
++ struct pppoe_packet *p_in,
++ struct pppoe_packet **p_out){
++ if( verify_packet(ses, p_in) < 0)
++ return -1;
++
++ if (DEB_DISC)
++ poe_dbglog (ses,"Got connection: %x",
++ ntohs(p_in->hdr->sid));
++ poe_info (ses,"Got connection: %x", ntohs(p_in->hdr->sid));
++
++ ses->sp.sa_family = AF_PPPOX;
++ ses->sp.sa_protocol = PX_PROTO_OE;
++ ses->sp.sa_addr.pppoe.sid = p_in->hdr->sid;
++ memcpy(ses->sp.sa_addr.pppoe.dev,ses->name, IFNAMSIZ);
++ memcpy(ses->sp.sa_addr.pppoe.remote, p_in->addr.sll_addr, ETH_ALEN);
++
++
++ return 1;
++}
++
++static int std_rcv_padt(struct session* ses,
++ struct pppoe_packet *p_in,
++ struct pppoe_packet **p_out){
++ ses->state = PADO_CODE;
++ return 0;
++}
++
++
++extern int disc_sock;
++int client_init_ses (struct session *ses, char* devnam)
++{
++ int i=0;
++ int retval;
++ char dev[IFNAMSIZ+1];
++ int addr[ETH_ALEN];
++ int sid;
++
++ /* do error checks here; session name etc are valid */
++// poe_info (ses,"init_ses: creating socket");
++
++ /* Make socket if necessary */
++ if( disc_sock < 0 ){
++
++ disc_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
++ if( disc_sock < 0 ){
++ poe_fatal(ses,
++ "Cannot create PF_PACKET socket for PPPoE discovery\n");
++ }
++
++ }
++
++ /* Check for long format */
++ retval =sscanf(devnam, FMTSTRING(IFNAMSIZ),addr, addr+1, addr+2,
++ addr+3, addr+4, addr+5,&sid,dev);
++ if( retval != 8 ){
++ /* Verify the device name , construct ses->local */
++ retval = get_sockaddr_ll(devnam,&ses->local);
++ if (retval < 0)
++ poe_fatal(ses, "client_init_ses: "
++ "Cannot create PF_PACKET socket for PPPoE discovery\n");
++
++
++ ses->state = PADO_CODE;
++ memcpy(&ses->remote, &ses->local, sizeof(struct sockaddr_ll) );
++
++ memset( ses->remote.sll_addr, 0xff, ETH_ALEN);
++ }else{
++ /* long form parsed */
++
++ /* Verify the device name , construct ses->local */
++ retval = get_sockaddr_ll(dev,&ses->local);
++ if (retval < 0)
++ poe_fatal(ses,"client_init_ses(2): "
++ "Cannot create PF_PACKET socket for PPPoE discovery\n");
++ ses->state = PADS_CODE;
++ ses->sp.sa_family = AF_PPPOX;
++ ses->sp.sa_protocol = PX_PROTO_OE;
++ ses->sp.sa_addr.pppoe.sid = sid;
++
++ memcpy(&ses->remote, &ses->local, sizeof(struct sockaddr_ll) );
++
++ for(; i < ETH_ALEN ; ++i ){
++ ses->sp.sa_addr.pppoe.remote[i] = addr[i];
++ ses->remote.sll_addr[i]=addr[i];
++ }
++ memcpy(ses->sp.sa_addr.pppoe.dev, dev, IFNAMSIZ);
++
++
++
++ }
++ if( retval < 0 )
++ error("bad device name: %s",devnam);
++
++
++ retval = bind( disc_sock ,
++ (struct sockaddr*)&ses->local,
++ sizeof(struct sockaddr_ll));
++
++
++ if( retval < 0 ){
++ error("bind to PF_PACKET socket failed: %m");
++ }
++
++ ses->fd = socket(AF_PPPOX,SOCK_STREAM,PX_PROTO_OE);
++ if(ses->fd < 0)
++ {
++ poe_fatal(ses,"Failed to create PPPoE socket: %m");
++ }
++
++
++ ses->init_disc = std_init_disc;
++ ses->rcv_pado = std_rcv_pado;
++ ses->rcv_pads = std_rcv_pads;
++ ses->rcv_padt = std_rcv_padt;
++
++ /* this should be filter overridable */
++ ses->retries = 10;
++
++ return ses->fd;
++}
++
+diff -r -N -u -b -B ppp-2.4.1.orig/pppd/plugins/pppoe/pppoe_relay.c ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppoe_relay.c
+--- ppp-2.4.1.orig/pppd/plugins/pppoe/pppoe_relay.c Wed Dec 31 19:00:00 1969
++++ ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppoe_relay.c Sun Aug 6 11:39:28 2000
+@@ -0,0 +1,260 @@
++/* PPPoE support library "libpppoe"
++ *
++ * Copyright 2000 Michal Ostrowski <mostrows@styx.uwaterloo.ca>,
++ * Jamal Hadi Salim <hadi@cyberus.ca>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#include "pppoe.h"
++
++static int relay_init_disc(struct session* ses,
++ struct pppoe_packet *p_in,
++ struct pppoe_packet **p_out){
++
++ ses->state = 0;
++ ses->retransmits = -1 ;
++ ses->retries = -1;
++
++ (*p_out) = NULL;
++ return 0;
++}
++
++static int pcid=0;
++static int relay_rcv_padi(struct session* ses,
++ struct pppoe_packet *p_in,
++ struct pppoe_packet **p_out){
++ char tag_buf[32];
++ struct pppoe_con *newpc = NULL;
++ struct pppoe_tag *tag = (struct pppoe_tag *) tag_buf;
++
++
++ tag->tag_type = PTT_RELAY_SID;
++ tag->tag_len = htons(ETH_ALEN + sizeof(struct session *));
++
++ memcpy(tag->tag_data, p_in->addr.sll_addr, ETH_ALEN);
++ memcpy(tag->tag_data + ETH_ALEN, &ses, sizeof(struct session *));
++
++ if(! p_in->tags[TAG_RELAY_SID] ){
++ copy_tag(p_in, tag);
++ }
++
++
++ poe_dbglog(ses, "Recv'd PADI: %P",p_in);
++ poe_dbglog(ses, "Recv'd packet: %P",p_in);
++ newpc = get_con( ntohs(tag->tag_len), tag->tag_data );
++ if(!newpc){
++
++ newpc = (struct pppoe_con *) malloc(sizeof(struct pppoe_con));
++ memset(newpc , 0, sizeof(struct pppoe_con));
++
++ newpc->id = pcid++;
++
++ newpc->key_len = ntohs(p_in->tags[TAG_RELAY_SID]->tag_len);
++ memcpy(newpc->key, p_in->tags[TAG_RELAY_SID]->tag_data, newpc->key_len);
++ memcpy(newpc->client, p_in->addr.sll_addr, ETH_ALEN);
++
++ memcpy(newpc->server, MAC_BCAST_ADDR, ETH_ALEN);
++
++ store_con(newpc);
++
++ }
++
++ ++newpc->ref_count;
++
++ memset(p_in->addr.sll_addr, 0xff, ETH_ALEN);
++
++ p_in->addr.sll_ifindex = ses->remote.sll_ifindex;
++
++ send_disc(ses, p_in);
++ return 0;
++}
++
++static int relay_rcv_pkt(struct session* ses,
++ struct pppoe_packet *p_in,
++ struct pppoe_packet **p_out){
++ struct pppoe_con *pc;
++ char tag_buf[32];
++ struct pppoe_tag *tag = p_in->tags[TAG_RELAY_SID];
++
++ if( !tag ) return 0;
++
++ pc = get_con(ntohs(tag->tag_len),tag->tag_data);
++
++ if( !pc ) return 0;
++
++ poe_dbglog(ses, "Recv'd packet: %P",p_in);
++
++ if( memcmp(pc->client , p_in->addr.sll_addr , ETH_ALEN ) == 0 ){
++
++ memcpy(p_in->addr.sll_addr, pc->server, ETH_ALEN);
++ p_in->addr.sll_ifindex = ses->remote.sll_ifindex;
++
++ }else{
++ if( memcmp(pc->server, MAC_BCAST_ADDR, ETH_ALEN) == 0 ){
++ memcpy(pc->server, p_in->addr.sll_addr, ETH_ALEN);
++
++ }else if( memcmp(pc->server, p_in->addr.sll_addr, ETH_ALEN) !=0){
++ return 0;
++ }
++
++ memcpy(p_in->addr.sll_addr, pc->client, ETH_ALEN);
++ p_in->addr.sll_ifindex = ses->local.sll_ifindex;
++
++
++ }
++
++
++ send_disc(ses, p_in);
++ return 0;
++}
++
++static int relay_rcv_pads(struct session* ses,
++ struct pppoe_packet *p_in,
++ struct pppoe_packet **p_out){
++
++ struct pppoe_con *pc;
++ char tag_buf[32];
++ struct pppoe_tag *tag = p_in->tags[TAG_RELAY_SID];
++ struct sockaddr_pppox sp_cl= { AF_PPPOX, PX_PROTO_OE,
++ { p_in->hdr->sid, {0,},{0,}}};
++
++ struct sockaddr_pppox sp_sv= { AF_PPPOX, PX_PROTO_OE,
++ { p_in->hdr->sid, {0,},{0,}}};
++
++ int ret;
++
++
++ if( !tag ) return 0;
++
++ pc = get_con(ntohs(tag->tag_len),tag->tag_data);
++
++ if( !pc ) return 0;
++
++
++ if(!pc->connected){
++
++ pc->sv_sock = socket( AF_PPPOX, SOCK_DGRAM, PX_PROTO_OE);
++ if( pc->sv_sock < 0){
++ poe_fatal(ses,"Cannot open PPPoE socket: %i",errno);
++ }
++
++ pc->cl_sock = socket( AF_PPPOX, SOCK_DGRAM, PX_PROTO_OE);
++ if( pc->cl_sock < 0){
++ poe_fatal(ses,"Cannot open PPPoE socket: %i",errno);
++ }
++
++ memcpy( sp_sv.sa_addr.pppoe.dev, ses->fwd_name, IFNAMSIZ);
++ memcpy( sp_sv.sa_addr.pppoe.remote, pc->server, ETH_ALEN);
++
++ ret = connect( pc->sv_sock,
++ (struct sockaddr*)&sp_sv,
++ sizeof(struct sockaddr_pppox));
++ if( ret < 0){
++ poe_fatal(ses,"Cannot connect PPPoE socket: %i",errno);
++ }
++
++ memcpy( sp_cl.sa_addr.pppoe.dev, ses->name, IFNAMSIZ);
++ memcpy( sp_cl.sa_addr.pppoe.remote, pc->client, ETH_ALEN);
++
++ ret = connect( pc->cl_sock,
++ (struct sockaddr*)&sp_cl,
++ sizeof(struct sockaddr_pppox));
++ if( ret < 0){
++ poe_fatal(ses,"Cannot connect PPPoE socket: %i",errno);
++ }
++
++
++ ret = ioctl( pc->sv_sock, PPPOEIOCSFWD, &sp_cl);
++ if( ret < 0){
++ poe_fatal(ses,"Cannot set forwarding on PPPoE socket: %i",errno);
++ }
++
++ ret = ioctl( pc->cl_sock, PPPOEIOCSFWD, &sp_sv);
++ if( ret < 0){
++ poe_fatal(ses,"Cannot set forwarding on PPPoE socket: %i",errno);
++ }
++
++ pc->connected = 1;
++ }
++
++ poe_info(ses,"PPPoE relay for %E established to %E (sid=%04x)\n",
++ pc->client,pc->server, p_in->hdr->sid);
++
++ return relay_rcv_pkt(ses,p_in,p_out);
++}
++
++
++static int relay_rcv_padt(struct session* ses,
++ struct pppoe_packet *p_in,
++ struct pppoe_packet **p_out){
++
++ int ret;
++ struct pppoe_con *pc;
++ char tag_buf[32];
++ struct pppoe_tag *tag = p_in->tags[TAG_RELAY_SID];
++
++ if( !tag ) return 0;
++
++ pc = get_con(ntohs(tag->tag_len),tag->tag_data);
++
++ if( !pc ) return 0;
++
++ ret = relay_rcv_pkt(ses,p_in,p_out);
++
++
++ if(pc->cl_sock>0){
++ close(pc->cl_sock);
++ }
++
++ if(pc->sv_sock>0){
++ close(pc->sv_sock);
++ }
++
++ --pc->ref_count;
++ if( pc->ref_count == 0 ){
++ delete_con(pc->key_len, pc->key);
++
++ free(pc);
++ }
++}
++
++
++int relay_init_ses(struct session *ses, char* from, char* to)
++{
++ int retval = client_init_ses(ses, from);
++
++ if(retval<0) return retval;
++
++ ses->fwd_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
++ if( ses->fwd_sock < 0 ) {
++ poe_fatal(ses,"Cannot create PF_PACKET socket for PPPoE forwarding\n");
++ }
++
++ /* Verify the device name , construct ses->local */
++ retval = get_sockaddr_ll(to, &ses->remote);
++ if (retval < 0)
++ poe_fatal(ses,"relay_init_ses:get_sockaddr_ll failed %m");
++
++ retval = bind( ses->fwd_sock ,
++ (struct sockaddr*)&ses->remote,
++ sizeof(struct sockaddr_ll));
++
++ if( retval < 0 ){
++ poe_fatal(ses,"bind to PF_PACKET socket failed: %m");
++ }
++
++ memcpy(ses->fwd_name, to, IFNAMSIZ);
++ memcpy(ses->name, from, IFNAMSIZ);
++
++
++ ses->init_disc = relay_init_disc;
++ ses->rcv_padi = relay_rcv_padi;
++ ses->rcv_pado = relay_rcv_pkt;
++ ses->rcv_padr = relay_rcv_pkt;
++ ses->rcv_pads = relay_rcv_pads;
++ ses->rcv_padt = relay_rcv_padt;
++}
+diff -r -N -u -b -B ppp-2.4.1.orig/pppd/plugins/pppoe/pppoe_server.c ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppoe_server.c
+--- ppp-2.4.1.orig/pppd/plugins/pppoe/pppoe_server.c Wed Dec 31 19:00:00 1969
++++ ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppoe_server.c Sun Aug 6 11:39:28 2000
+@@ -0,0 +1,143 @@
++/* PPPoE support library "libpppoe"
++ *
++ * Copyright 2000 Michal Ostrowski <mostrows@styx.uwaterloo.ca>,
++ * Jamal Hadi Salim <hadi@cyberus.ca>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++#include "pppoe.h"
++#include <unistd.h>
++
++static unsigned int pcid=1111;
++static int srv_rcv_padi(struct session* ses,
++ struct pppoe_packet *p_in,
++ struct pppoe_packet **p_out){
++ struct pppoe_con *newpc = NULL;
++ struct pppoe_tag *tag;
++
++ poe_dbglog(ses,"Srv Recv'd packet: %P\n",p_in);
++
++
++ ses->curr_pkt.hdr = (struct pppoe_hdr*) ses->curr_pkt.buf;
++ ses->curr_pkt.hdr->ver = 1;
++ ses->curr_pkt.hdr->type = 1;
++
++ tag = get_tag(p_in->hdr,PTT_SRV_NAME);
++
++ if(!tag )
++ return 0;
++
++ if( ntohs(tag->tag_len)==0 ){
++ ses->curr_pkt.tags[TAG_SRV_NAME] = ses->filt->stag ;
++ }else if( tag->tag_len != ses->filt->stag->tag_len
++ || !memcmp( tag+1, ses->filt->stag, ntohs(tag->tag_len)) ){
++ return 0;
++ }else{
++ ses->curr_pkt.tags[TAG_SRV_NAME] = tag;
++ }
++
++ ses->curr_pkt.tags[ TAG_AC_NAME] = ses->filt->ntag ;
++ ses->curr_pkt.tags[ TAG_HOST_UNIQ ] = get_tag(p_in->hdr,PTT_HOST_UNIQ);
++
++ memcpy(&ses->remote, &p_in->addr, sizeof(struct sockaddr_ll));
++ memcpy( &ses->curr_pkt.addr, &ses->remote , sizeof(struct sockaddr_ll));
++
++ ses->curr_pkt.hdr->code = PADO_CODE;
++
++
++ ses->curr_pkt.tags[ TAG_RELAY_SID ] = get_tag(p_in->hdr,PTT_RELAY_SID);
++
++ send_disc(ses, &ses->curr_pkt);
++ poe_dbglog(ses,"Srv Sent packet: %P\n",&ses->curr_pkt);
++
++ return 0;
++}
++
++
++static int srv_rcv_padr(struct session* ses,
++ struct pppoe_packet *p_in,
++ struct pppoe_packet **p_out){
++ struct pppoe_tag *tag;
++
++ poe_dbglog(ses,"Recv'd packet: %P\n",p_in);
++
++
++
++ /* Run checks to ensure this packets asks for
++ what we're willing to offer */
++
++ tag = get_tag(p_in->hdr,PTT_SRV_NAME);
++
++ if(!tag || tag->tag_len == 0 ){
++ p_in->tags[TAG_SRV_NAME] = ses->filt->stag;
++
++ }else if( tag->tag_len != ses->filt->stag->tag_len
++ || !memcmp(tag + 1 , ses->filt->stag, ntohs(tag->tag_len)) ){
++ return 0;
++ }else{
++ p_in->tags[TAG_SRV_NAME] = tag;
++ }
++
++ tag = get_tag(p_in->hdr,PTT_AC_NAME);
++ if( !tag || tag->tag_len==0 ){
++ p_in->tags[TAG_AC_NAME] = ses->filt->ntag;
++ }else if( tag->tag_len != ses->filt->ntag->tag_len
++ || !memcmp(tag + 1, ses->filt->ntag, ntohs(tag->tag_len)) ){
++ return 0;
++ }else{
++ p_in->tags[TAG_AC_NAME] = tag;
++ }
++
++
++
++
++ pcid = ++pcid & 0x0000ffff ;
++ if(pcid == 0 ){
++ pcid = 1111;
++ }
++
++ p_in->hdr->sid = ntohs(pcid);
++
++ p_in->hdr->code = PADS_CODE;
++ send_disc(ses, p_in);
++
++ poe_dbglog(ses,"Sent packet: %P\n",p_in);
++
++ ses->sp.sa_family = AF_PPPOX;
++ ses->sp.sa_protocol=PX_PROTO_OE;
++ ses->sp.sa_addr.pppoe.sid = p_in->hdr->sid;
++ memcpy(ses->sp.sa_addr.pppoe.dev, ses->name, IFNAMSIZ);
++ memcpy(ses->sp.sa_addr.pppoe.remote, p_in->addr.sll_addr, ETH_ALEN);
++ memcpy(&ses->remote, &p_in->addr, sizeof(struct sockaddr_ll));
++ return 1;
++}
++
++static int srv_rcv_padt(struct session* ses,
++ struct pppoe_packet *p_in,
++ struct pppoe_packet **p_out){
++ return 0;
++}
++
++
++
++int srv_init_ses(struct session *ses, char* from)
++{
++ int retval;
++ retval = client_init_ses(ses, from);
++ ses->init_disc = NULL;
++ ses->rcv_pado = NULL;
++ ses->rcv_pads = NULL;
++ ses->rcv_padi = srv_rcv_padi;
++ ses->rcv_padr = srv_rcv_padr;
++ ses->rcv_padt = srv_rcv_padt;
++
++ /* retries forever */
++ ses->retries = -1;
++
++ return retval;
++}
++
++
+Binary files ppp-2.4.1.orig/pppd/plugins/pppoe/pppoed and ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppoed differ
+diff -r -N -u -b -B ppp-2.4.1.orig/pppd/plugins/pppoe/pppoed.c ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppoed.c
+--- ppp-2.4.1.orig/pppd/plugins/pppoe/pppoed.c Wed Dec 31 19:00:00 1969
++++ ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppoed.c Sun Aug 6 11:39:28 2000
+@@ -0,0 +1,283 @@
++/* PPPoE support library "libpppoe"
++ *
++ * Copyright 2000 Jamal Hadi Salim <hadi@cyberus.ca>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#include "pppoe.h"
++
++int detached=1;
++void
++sigproc (int src)
++{
++ int i;
++ fprintf (stderr,"Received signal %d", src);
++}
++
++void
++sigchild (int src)
++{
++ pid_t pid;
++ int status;
++ int i;
++ pid = waitpid (-1, &status, WNOHANG);
++
++ if (!detached)
++ fprintf (stderr,"Child received signal %d PID %d, status %d", src, pid, status);
++ if (pid < 1) {
++ return;
++ }
++}
++
++void
++print_help ()
++{
++
++ fprintf (stdout,"\npppoe version %d.%d build %d", VERSION_MAJOR, VERSION_MINOR,
++ VERSION_DATE);
++ fprintf (stdout,"\nrecognized options are:");
++ fprintf (stdout,"\n -I <interface> : overrides the default interface of eth0");
++ fprintf (stdout,"\n -S : starts pppoed in server mode");
++ fprintf (stdout,"\n -R <num_retries>: forces pppoed to be restarted num_retries");
++ fprintf (stdout,"\n should the other end be detected to be dead.");
++ fprintf (stdout,"\n Needs lcp_echo. Read the INSTALL file instructions");
++ fprintf (stdout,"\n -F <filename> : specifies additional ppp options file");
++ fprintf (stdout,"\n -C <filename> : ppp options file in /etc/ppp/peers/");
++ fprintf (stdout,"\n -d <level> : sets debug level");
++ fprintf (stdout,"\n -D : prevents pppoed from detaching itself and running in the background");
++ fprintf (stdout,"\n -P <path to pppd> : selects a different pppd. Defaults to " _PATH_PPPD);
++ fprintf (stdout,"\n -A <AC name> to select a specific AC by name");
++ fprintf (stdout,"\n -E <AC service name> to select a specific AC service by name");
++ fprintf (stdout,"\n -G Do service discovery only");
++ fprintf (stdout,"\n -H Do service discovery and connection (no pppd)\n");
++}
++
++
++int
++get_args (int argc, char **argv,struct session *sess)
++{
++ struct filter *filt;
++ struct host_tag *tg;
++ int opt;
++
++
++ sess->opt_debug = 0;
++ DEB_DISC=0;
++ DEB_DISC2=0;
++ sess->log_to_fd = 1;
++ sess->np = 0;
++ sess->opt_daemonize = 0;
++
++ sess->log_to_fd = fileno (stdout);
++
++/* defaults to eth0 */
++ strcpy (sess->name, "eth0");
++
++
++ if ((sess->filt=malloc(sizeof(struct filter))) == NULL) {
++ poe_error (sess,"failed to malloc for Filter ");
++ poe_die (-1);
++ }
++
++ filt=sess->filt; /* makes the code more readable */
++ memset(filt,0,sizeof(struct filter));
++
++ filt->num_restart=1;
++
++/* set default filters; move this to routine */
++ /* parse options */
++
++ while ((opt = getopt (argc, argv, "A:C:E:d:DR:I:F:L:V:P:SN:GH")) != -1)
++
++ switch (opt) {
++ case 'R': /* sets number of retries */
++ filt->num_restart = strtol (optarg, (char **) NULL, 10);
++ filt->num_restart += 1;
++ break;
++ case 'I': /* sets interface */
++ if (strlen (optarg) >= IFNAMSIZ) {
++ poe_error (sess,"interface name cannot exceed %d characters", IFNAMSIZ - 1);
++ return (-1);
++ }
++ strncpy (sess->name, optarg, strlen(optarg)+1);
++ break;
++ case 'C': /* name of the file in /etc/ppp/peers */
++ if (NULL != filt->fname) {
++ poe_error (sess,"-F can not be used with -C");
++ return (-1);
++ }
++ if (strlen(optarg) > MAX_FNAME) {
++ poe_error (sess,"file name cannot exceed %d characters", MAX_FNAME - 1);
++ return (-1);
++ }
++ filt->fname=malloc(strlen(optarg));
++ strncpy (filt->fname, optarg, strlen(optarg));
++ filt->peermode=1;
++ break;
++ case 'F': /* sets the options file */
++ if (NULL != filt->fname) {
++ poe_error (sess,"-F can not be used with -C");
++ return (-1);
++ }
++
++ if (strlen(optarg) > MAX_FNAME) {
++ poe_error (sess,"file name cannot exceed %d characters", MAX_FNAME - 1);
++ return (-1);
++ }
++ filt->fname=malloc(strlen(optarg)+1);
++ strncpy (filt->fname, optarg, strlen(optarg)+1);
++
++ poe_info (sess,"selected %s as filename\n",filt->fname);
++ break;
++ case 'D': /* don't daemonize */
++ sess->opt_daemonize = 1;
++ detached=0;
++ break;
++ case 'd': /* debug level */
++ sess->opt_debug = strtol (optarg, (char **) NULL, 10);
++ if (sess->opt_debug & 0x0002)
++ DEB_DISC=1;
++ if (sess->opt_debug & 0x0004)
++ DEB_DISC2=1;
++ break;
++ case 'P': /* sets the pppd binary */
++ if (strlen(optarg) > MAX_FNAME) {
++ poe_error (sess,"pppd binary cant exceed %d characters", MAX_FNAME - 1);
++ return (-1);
++ }
++ filt->pppd=malloc(strlen(optarg));
++ strncpy (filt->pppd, optarg, strlen(optarg));
++ break;
++ case 'H':
++ sess->np = 2;
++ break;
++ case 'G':
++ sess->np = 1;
++ break;
++ case 'V': /* version */
++ fprintf (stdout,"pppoe version %d.%d build %d", VERSION_MAJOR,
++ VERSION_MINOR, VERSION_DATE);
++ return (0);
++ case 'S': /* server mode */
++ sess->type = SESSION_SERVER;
++ break;
++ case 'A': /* AC override */
++ poe_info (sess,"AC name override to %s", optarg);
++ if (strlen (optarg) > 255) {
++ poe_error (sess," AC name too long
++ (maximum allowed 256 chars)");
++ poe_die(-1);
++ }
++ if ((sess->filt->ntag= malloc (sizeof (struct pppoe_tag) +
++ strlen (optarg)))== NULL) {
++ poe_error (sess,"failed to malloc for AC name");
++ poe_die(-1);
++ }
++ sess->filt->ntag->tag_len=htons(strlen(optarg));
++ sess->filt->ntag->tag_type=PTT_AC_NAME;
++ poe_error (sess," pppoe_ac_name: AC name Override %p\n",
++ sess->filt->ntag);
++ strcpy(sess->filt->ntag->tag_data,optarg);
++ break;
++ case 'E': /* AC service name override */
++ poe_info (sess,"AC service name override to %s", optarg);
++ if (strlen (optarg) > 255) {
++ poe_error (sess," Service name too long
++ (maximum allowed 256 chars)");
++ poe_die(-1);
++ }
++
++ if ((filt->stag = malloc (strlen (optarg) + sizeof (struct pppoe_tag))) == NULL) {
++ poe_error (sess,"failed to malloc for service name: %m");
++ return (-1);
++ }
++
++ filt->stag->tag_len = htons (strlen (optarg));
++ filt->stag->tag_type = PTT_SRV_NAME;
++ strcpy ((char *) (filt->stag->tag_data), optarg);
++ break;
++ default:
++ poe_error (sess,"Unknown option '%c'", optopt);
++ print_help ();
++ return (-1);
++ }
++
++
++ return (1);
++
++}
++
++
++int main(int argc, char** argv){
++ int ret;
++ struct filter *filt;
++ struct session *ses = (struct session *)malloc(sizeof(struct session));
++ char buf[256];
++ ses=(void *)malloc(sizeof(struct session));
++
++ if(!ses){
++ return -1;
++ }
++ memset(ses,0,sizeof(struct session));
++
++
++
++ openlog ("pppoed", LOG_PID | LOG_NDELAY, LOG_PPPOE);
++ setlogmask (LOG_UPTO (ses->opt_debug ? LOG_DEBUG : LOG_INFO));
++
++
++ if ((get_args (argc,(char **) argv,ses)) <1)
++ poe_die(-1);
++
++ filt=ses->filt; /* makes the code more readable */
++
++ if (!ses->np) {
++ poe_create_pidfile (ses);
++// signal (SIGINT, &sigproc);
++// signal (SIGTERM, &sigproc);
++ signal (SIGCHLD, &sigchild);
++ }
++
++ if(ses->type == SESSION_CLIENT){
++
++ poe_info(ses,"calling client_init_ses\n");
++ ret = client_init_ses(ses,ses->name);
++
++ if( ret < 0 ){
++ return -1;
++ }
++
++ while (ses->filt->num_restart > 0)
++ {
++ poe_info(ses,"Restart number %d ",ses->filt->num_restart);
++ ppp_connect (ses);
++ ses->filt->num_restart--;
++ }
++
++ }else if( ses->type == SESSION_SERVER ){
++
++ poe_info(ses,"calling srv_init_ses\n");
++ ret = srv_init_ses(ses,ses->name);
++
++ if( ret < 0 ){
++ return -1;
++ }
++
++ ret = 1;
++ while(ret>=0)
++ ret = ppp_connect(ses);
++
++ }
++
++
++
++
++ poe_info(ses,"ppp_connect came back! %d",ret);
++
++ exit(0);
++
++}
+diff -r -N -u -b -B ppp-2.4.1.orig/pppd/plugins/pppoe/pppoefwd.c ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppoefwd.c
+--- ppp-2.4.1.orig/pppd/plugins/pppoe/pppoefwd.c Wed Dec 31 19:00:00 1969
++++ ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppoefwd.c Sun Aug 6 11:39:28 2000
+@@ -0,0 +1,61 @@
++#include "pppoe.h"
++
++void fatal (char *fmt, ...)
++{
++ va_list pvar;
++
++#if defined(__STDC__)
++ va_start(pvar, fmt);
++#else
++ char *fmt;
++ va_start(pvar);
++ fmt = va_arg(pvar, char *);
++#endif
++
++ vprintf( fmt, pvar);
++ va_end(pvar);
++
++ exit(1); /* as promised */
++}
++
++void info (char *fmt, ...)
++{
++ va_list pvar;
++
++#if defined(__STDC__)
++ va_start(pvar, fmt);
++#else
++ char *fmt;
++ va_start(pvar);
++ fmt = va_arg(pvar, char *);
++#endif
++
++ vprintf( fmt, pvar);
++ va_end(pvar);
++
++}
++
++
++int main(int argc, char** argv){
++ int ret;
++ struct session *ses = (struct session *)malloc(sizeof(struct session));
++
++ if(!ses) return -1;
++
++ ret = relay_init_ses(ses,argv[1],argv[2]);
++
++ if( ret < 0 ){
++ return -1;
++ }
++
++ ses->log_to_fd = 1;
++ ses->opt_debug=1;
++ while(1)
++ ret = session_connect(ses);
++
++
++
++ return ret;
++
++
++}
+diff -r -N -u -b -B ppp-2.4.1.orig/pppd/plugins/pppoe/pppoehash.c ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppoehash.c
+--- ppp-2.4.1.orig/pppd/plugins/pppoe/pppoehash.c Wed Dec 31 19:00:00 1969
++++ ppp-2.4.1.pppoe2/pppd/plugins/pppoe/pppoehash.c Sun Aug 6 11:39:28 2000
+@@ -0,0 +1,91 @@
++/* PPPoE support library "libpppoe"
++ *
++ * Copyright 2000 Michal Ostrowski <mostrows@styx.uwaterloo.ca>,
++ * Jamal Hadi Salim <hadi@cyberus.ca>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++#include "pppoe.h"
++
++
++#define PPPOE_HASH_SIZE 16
++
++
++static inline int keycmp(char *a, char *b, int x, int y){
++ return x==y && !memcmp(a,b,x);
++}
++
++static int hash_con(int key_len, char* key)
++{
++ int i = 0;
++ char hash[sizeof(int)]={0,};
++
++ for (i = 0; i < key_len ; ++i)
++ hash[i% sizeof(int)] = hash[i%sizeof(int)] ^ key[i];
++
++ i = (*((int*)hash)) ;
++ i &= PPPOE_HASH_SIZE - 1;
++
++ return i;
++}
++
++static struct pppoe_con *con_ht[PPPOE_HASH_SIZE] = { 0, };
++
++struct pppoe_con *get_con(int len, char *key)
++{
++ int hash = hash_con(len, key);
++ struct pppoe_con *ret;
++
++ ret = con_ht[hash];
++
++ while (ret && !keycmp(ret->key,key, ret->key_len, len))
++ ret = ret->next;
++
++ return ret;
++}
++
++int store_con(struct pppoe_con *pc)
++{
++ int hash = hash_con(pc->key_len, pc->key);
++ struct pppoe_con *ret;
++
++ ret = con_ht[hash];
++ while (ret) {
++ if (!keycmp(ret->key, pc->key, ret->key_len, pc->key_len))
++ return -EALREADY;
++
++ ret = ret->next;
++ }
++
++ if (!ret) {
++ pc->next = con_ht[hash];
++ con_ht[hash] = pc;
++ }
++
++ return 0;
++}
++
++struct pppoe_con *delete_con(unsigned long len, char *key)
++{
++ int hash = hash_con(len, key);
++ struct pppoe_con *ret, **src;
++
++ ret = con_ht[hash];
++ src = &con_ht[hash];
++
++ while (ret) {
++ if (keycmp(ret->key,key, ret->key_len, len)) {
++ *src = ret->next;
++ break;
++ }
++
++ src = &ret->next;
++ ret = ret->next;
++ }
++
++ return ret;
++}
++
+diff -r -N -u -b -B ppp-2.4.1.orig/pppd/plugins/pppoe/utils.c ppp-2.4.1.pppoe2/pppd/plugins/pppoe/utils.c
+--- ppp-2.4.1.orig/pppd/plugins/pppoe/utils.c Wed Dec 31 19:00:00 1969
++++ ppp-2.4.1.pppoe2/pppd/plugins/pppoe/utils.c Sun Aug 6 11:39:28 2000
+@@ -0,0 +1,667 @@
++
++/*
++ * utils.c - various utility functions used in pppoed.
++ *
++ * mostly stolen from ppp-2.3.10 by Marc Boucher <marc@mbsi.ca>
++ *
++ * Feb 18/2000 Made fully re-entrant (JHS)
++ *
++ * Copyright (c) 1999 The Australian National University.
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms are permitted
++ * provided that the above copyright poe_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 the Australian National 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.
++ */
++
++#include <stdio.h> /* stdio */
++#include <stdlib.h> /* strtoul(), realloc() */
++#include <string.h> /* memcpy() */
++#include <unistd.h> /* STDIN_FILENO,exec */
++#include <errno.h> /* errno */
++
++#include <sys/time.h>
++
++#include <net/ethernet.h>
++#include <netinet/in.h>
++
++#include <stdarg.h>
++#include <ctype.h>
++#include <syslog.h>
++#include <limits.h>
++#include <paths.h>
++
++#include "pppoe.h"
++
++static char pidfilename[PATH_MAX]; /* name of pid file */
++
++/*
++static int detached = 0;
++ log_to_fd = -1;
++ */
++
++static void vslp_printer (void *, char *,...);
++static void format_packet (struct pppoe_packet *, int, void (*)(void *, char *,...), void *);
++static void format_tag (struct pppoe_tag *, void (*)(void *, char *,...), void *);
++struct buffer_poe_info {
++ char *ptr;
++ int len;
++};
++
++void poe_die (int status);
++
++
++/*
++ * vpoe_slprintf - like vsprintf, except we
++ * also specify the length of the output buffer, and we handle
++ * %r (recursive format), %m (poe_error message), %v (visible string),
++ * %q (quoted string), %t (current time) and %E (Ether address) formats.
++ * Doesn't do floating-point formats.
++ * Returns the number of chars put into buf.
++ */
++#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0)
++
++int
++vpoe_slprintf (char *buf, int buflen, char *fmt, va_list args)
++{
++ int c, i, n;
++ int width, prec, fillch;
++ int base, len, neg, quoted;
++ unsigned long val = 0;
++ char *str, *f, *buf0;
++ unsigned char *p;
++ char num[32];
++ time_t t;
++ static char hexchars[] = "0123456789abcdef";
++ struct buffer_poe_info bufpoe_info;
++
++ buf0 = buf;
++ --buflen;
++ while (buflen > 0) {
++ for (f = fmt; *f != '%' && *f != 0; ++f);
++ if (f > fmt) {
++ len = f - fmt;
++ if (len > buflen)
++ len = buflen;
++ memcpy (buf, fmt, len);
++ buf += len;
++ buflen -= len;
++ fmt = f;
++ }
++ if (*fmt == 0)
++ break;
++ c = *++fmt;
++ width = 0;
++ prec = -1;
++ fillch = ' ';
++ if (c == '0') {
++ fillch = '0';
++ c = *++fmt;
++ }
++ if (c == '*') {
++ width = va_arg (args, int);
++ c = *++fmt;
++ }
++ else {
++ while (isdigit (c)) {
++ width = width * 10 + c - '0';
++ c = *++fmt;
++ }
++ }
++ if (c == '.') {
++ c = *++fmt;
++ if (c == '*') {
++ prec = va_arg (args, int);
++ c = *++fmt;
++ }
++ else {
++ prec = 0;
++ while (isdigit (c)) {
++ prec = prec * 10 + c - '0';
++ c = *++fmt;
++ }
++ }
++ }
++ str = 0;
++ base = 0;
++ neg = 0;
++ ++fmt;
++ switch (c) {
++ case 'd':
++ i = va_arg (args, int);
++ if (i < 0) {
++ neg = 1;
++ val = -i;
++ }
++ else
++ val = i;
++ base = 10;
++ break;
++ case 'o':
++ val = va_arg (args, unsigned int);
++ base = 8;
++ break;
++ case 'x':
++ case 'X':
++ val = va_arg (args, unsigned int);
++ base = 16;
++ break;
++ case 'p':
++ val = (unsigned long) va_arg (args, void *);
++ base = 16;
++ neg = 2;
++ break;
++ case 's':
++ str = va_arg (args, char *);
++ break;
++ case 'c':
++ num[0] = va_arg (args, int);
++ num[1] = 0;
++ str = num;
++ break;
++ case 'm':
++ str = strerror (errno);
++ break;
++ case 'E':
++ p = va_arg (args, unsigned char *);
++ for (n = ETH_ALEN; n > 0; --n) {
++ c = *p++;
++ OUTCHAR (hexchars[(c >> 4) & 0xf]);
++ OUTCHAR (hexchars[c & 0xf]);
++ if (n > 1)
++ OUTCHAR (':');
++ }
++ continue;
++ case 'r':
++ f = va_arg (args, char *);
++#ifndef __powerpc__
++ n = vpoe_slprintf (buf, buflen + 1, f, va_arg (args, va_list));
++#else
++ /* On the powerpc, a va_list is an array of 1 structure */
++ n = vpoe_slprintf (buf, buflen + 1, f, va_arg (args, void *));
++#endif
++ buf += n;
++ buflen -= n;
++ continue;
++ case 't':
++ time (&t);
++ str = ctime (&t);
++ str += 4; /* chop off the day name */
++ str[15] = 0; /* chop off year and newline */
++ break;
++ case 'v': /* "visible" string */
++ case 'q': /* quoted string */
++ quoted = c == 'q';
++ p = va_arg (args, unsigned char *);
++ if (fillch == '0' && prec >= 0) {
++ n = prec;
++ }
++ else {
++ n = strlen ((char *) p);
++ if (prec >= 0 && n > prec)
++ n = prec;
++ }
++ while (n > 0 && buflen > 0) {
++ c = *p++;
++ --n;
++ if (!quoted && c >= 0x80) {
++ OUTCHAR ('M');
++ OUTCHAR ('-');
++ c -= 0x80;
++ }
++ if (quoted && (c == '"' || c == '\\'))
++ OUTCHAR ('\\');
++ if (c < 0x20 || (0x7f <= c && c < 0xa0)) {
++ if (quoted) {
++ OUTCHAR ('\\');
++ switch (c) {
++ case '\t':
++ OUTCHAR ('t');
++ break;
++ case '\n':
++ OUTCHAR ('n');
++ break;
++ case '\b':
++ OUTCHAR ('b');
++ break;
++ case '\f':
++ OUTCHAR ('f');
++ break;
++ default:
++ OUTCHAR ('x');
++ OUTCHAR (hexchars[c >> 4]);
++ OUTCHAR (hexchars[c & 0xf]);
++ }
++ }
++ else {
++ if (c == '\t')
++ OUTCHAR (c);
++ else {
++ OUTCHAR ('^');
++ OUTCHAR (c ^ 0x40);
++ }
++ }
++ }
++ else
++ OUTCHAR (c);
++ }
++ continue;
++ case 'P': /* print PPPoE packet */
++ bufpoe_info.ptr = buf;
++ bufpoe_info.len = buflen + 1;
++ p = va_arg (args, unsigned char *);
++ n = va_arg (args, int);
++ format_packet ((struct pppoe_packet *) p, n, vslp_printer, &bufpoe_info);
++ buf = bufpoe_info.ptr;
++ buflen = bufpoe_info.len - 1;
++ continue;
++ case 'T': /* print PPPoE tag */
++ bufpoe_info.ptr = buf;
++ bufpoe_info.len = buflen + 1;
++ p = va_arg (args, unsigned char *);
++ format_tag ((struct pppoe_tag *) p, vslp_printer, &bufpoe_info);
++ buf = bufpoe_info.ptr;
++ buflen = bufpoe_info.len - 1;
++ continue;
++ case 'B':
++ p = va_arg (args, unsigned char *);
++ for (n = prec; n > 0; --n) {
++ c = *p++;
++ if (fillch == ' ')
++ OUTCHAR (' ');
++ OUTCHAR (hexchars[(c >> 4) & 0xf]);
++ OUTCHAR (hexchars[c & 0xf]);
++ }
++ continue;
++ default:
++ *buf++ = '%';
++ if (c != '%')
++ --fmt; /* so %z outputs %z etc. */
++ --buflen;
++ continue;
++ }
++ if (base != 0) {
++ str = num + sizeof (num);
++ *--str = 0;
++ while (str > num + neg) {
++ *--str = hexchars[val % base];
++ val = val / base;
++ if (--prec <= 0 && val == 0)
++ break;
++ }
++ switch (neg) {
++ case 1:
++ *--str = '-';
++ break;
++ case 2:
++ *--str = 'x';
++ *--str = '0';
++ break;
++ }
++ len = num + sizeof (num) - 1 - str;
++ }
++ else {
++ len = strlen (str);
++ if (prec >= 0 && len > prec)
++ len = prec;
++ }
++ if (width > 0) {
++ if (width > buflen)
++ width = buflen;
++ if ((n = width - len) > 0) {
++ buflen -= n;
++ for (; n > 0; --n)
++ *buf++ = fillch;
++ }
++ }
++ if (len > buflen)
++ len = buflen;
++ memcpy (buf, str, len);
++ buf += len;
++ buflen -= len;
++ }
++ *buf = 0;
++ return buf - buf0;
++}
++
++/*
++ * vslp_printer - used in processing a %P format
++ */
++static void
++vslp_printer (void *arg, char *fmt,...)
++{
++ int n;
++ va_list pvar;
++ struct buffer_poe_info *bi;
++
++ va_start (pvar, fmt);
++
++ bi = (struct buffer_poe_info *) arg;
++ n = vpoe_slprintf (bi->ptr, bi->len, fmt, pvar);
++ va_end (pvar);
++
++ bi->ptr += n;
++ bi->len -= n;
++}
++
++/*
++ * format_packet - make a readable representation of a packet,
++ * calling `printer(arg, format, ...)' to output it.
++ */
++static void
++format_packet (struct pppoe_packet *p,
++ int len,
++ void (*printer) (void *, char *,...),
++ void *arg)
++{
++ struct pppoe_tag *t;
++
++ printer (arg, "Ether addr: %E\n", p->addr.sll_addr);
++
++ switch ((unsigned) ntohs (p->addr.sll_protocol)) {
++ case ETH_P_PPPOE_DISC:
++ printer (arg, " (PPPOE Discovery)\n");
++ break;
++ case ETH_P_PPPOE_SESS:
++ printer (arg, " (PPPOE Session)\n");
++ break;
++ }
++
++ printer (arg, " PPPoE hdr: ver=0x%01x type=0x%01x code=0x%02x "
++ "sid=0x%04x length=0x%04x ", (unsigned) p->hdr->ver,
++ (unsigned) p->hdr->type, (unsigned) p->hdr->code, (unsigned) p->hdr->sid,
++ (unsigned) ntohs (p->hdr->length));
++
++ switch (p->hdr->code) {
++ case PADI_CODE:
++ printer (arg, "(PADI)\n");
++ break;
++ case PADO_CODE:
++ printer (arg, "(PADO)\n");
++ break;
++ case PADR_CODE:
++ printer (arg, "(PADR)\n");
++ break;
++ case PADS_CODE:
++ printer (arg, "(PADS)\n");
++ break;
++ case PADT_CODE:
++ printer (arg, "(PADT)\n");
++ break;
++ default:
++ printer (arg, "(Unknown)\n");
++ }
++
++#if 0
++ if (ntohs (p->addr.sll_protocol) != ETH_P_PPPOE_DISC) {
++ len = ntohs (p->length);
++
++ if (len > 64)
++ printer (arg, " %.64B ...", (p + 1));
++ else
++ printer (arg, " %.*B", len, p + 1);
++
++ return;
++ }
++#endif
++
++ for(t = (struct pppoe_tag *) (&p->hdr->tag);
++ (t < (struct pppoe_tag *) ((char *) (&p->hdr->tag) + ntohs (p->hdr->length))) &&
++ ntohs (t->tag_type) != PTT_EOL;
++ t = (struct pppoe_tag *) ((char *) (t + 1) + ntohs (t->tag_len))) {
++ format_tag (t, printer, arg);
++ }
++}
++
++/*
++ * format_tag - make a readable representation of a tag,
++ * calling `printer(arg, format, ...)' to output it.
++ */
++static void
++format_tag (struct pppoe_tag *t,
++ void (*printer) (void *, char *,...),
++ void *arg)
++{
++ printer (arg, " PPPoE tag: type=%04x length=%04x ",
++ ntohs (t->tag_type), ntohs (t->tag_len));
++ switch ( t->tag_type ) {
++ case PTT_EOL:
++ printer (arg, "(End of list)");
++ break;
++ case PTT_SRV_NAME:
++ printer (arg, "(Service name)");
++ break;
++ case PTT_AC_NAME:
++ printer (arg, "(AC Name)");
++ break;
++ case PTT_HOST_UNIQ:
++ printer (arg, "(Host Uniq)");
++ break;
++ case PTT_AC_COOKIE:
++ printer (arg, "(AC Cookie)");
++ break;
++ case PTT_VENDOR:
++ printer (arg, "(Vendor Specific)");
++ break;
++ case PTT_RELAY_SID:
++ printer (arg, "(Relay Session ID)");
++ break;
++ case PTT_SRV_ERR:
++ printer (arg, "(Service Name Error)");
++ break;
++ case PTT_SYS_ERR:
++ printer (arg, "(AC System Error)");
++ break;
++ case PTT_GEN_ERR:
++ printer (arg, "(Generic Error)");
++ break;
++ default:
++ printer (arg, "(Unknown)");
++ }
++ if (ntohs (t->tag_len) > 0)
++ switch ( t->tag_type ) {
++ case PTT_SRV_NAME:
++ case PTT_AC_NAME:
++ case PTT_SRV_ERR:
++ case PTT_SYS_ERR:
++ case PTT_GEN_ERR: /* ascii data */
++ {
++ char *buf;
++ buf = malloc (ntohs (t->tag_len) + 1);
++ memset (buf, 0, ntohs (t->tag_len) + 1);
++ strncpy (buf, (char *) (t + 1), ntohs (t->tag_len));
++// buf[ntohs (t->tag_len)] = '\0';
++ printer (arg, " data (UTF-8): %s", buf);
++ free (buf);
++ break;
++ }
++
++ case PTT_HOST_UNIQ:
++ case PTT_AC_COOKIE:
++ case PTT_RELAY_SID:
++ printer (arg, " data (bin): %.*B", ntohs (t->tag_len), (char *) (t + 1));
++ break;
++
++ default:
++ printer (arg, " unrecognized data");
++ }
++}
++
++/*
++ * poe_logit - does the hard work for poe_fatal et al.
++ */
++static void
++poe_logit (struct session *ses,int level, char *fmt, va_list args)
++{
++ int n;
++ char buf[256];
++
++ n = vpoe_slprintf (buf, sizeof (buf), fmt, args);
++ syslog (level, "%s", buf);
++ if (log_to_fd >= 0 && (level != LOG_DEBUG || ses->opt_debug)) {
++ if (buf[n - 1] != '\n')
++ buf[n++] = '\n';
++ if (write (log_to_fd, buf, n) != n)
++ log_to_fd = -1;
++ }
++}
++
++/*
++ * poe_fatal - log an poe_error message and poe_die horribly.
++ */
++void
++poe_fatal (struct session *ses, char *fmt,...)
++{
++ va_list pvar;
++
++ va_start (pvar, fmt);
++
++ poe_logit (ses,LOG_ERR, fmt, pvar);
++ va_end (pvar);
++
++ poe_die(1); /* as promised */
++}
++
++/*
++ * poe_error - log an poe_error message.
++ */
++void
++poe_error (struct session *ses,char *fmt,...)
++{
++ va_list pvar;
++
++ va_start (pvar, fmt);
++
++ poe_logit (ses,LOG_ERR, fmt, pvar);
++ va_end (pvar);
++}
++
++/*
++ * poe_warn - log a poe_warning message.
++ */
++void
++poe_warn (struct session *ses,char *fmt,...)
++{
++ va_list pvar;
++
++ va_start (pvar, fmt);
++
++ poe_logit (ses,LOG_WARNING, fmt, pvar);
++ va_end (pvar);
++}
++
++#if 0
++/*
++ * poe_notice - log a poe_notice-level message.
++ */
++void
++poe_notice (int log_to_fd ,char *fmt,...)
++{
++ va_list pvar;
++
++ va_start (pvar, fmt);
++
++ poe_logit (log_to_fd,LOG_NOTICE, fmt, pvar);
++ va_end (pvar);
++}
++
++#endif
++/*
++ * poe_info - log an poe_informational message.
++ */
++void
++poe_info (struct session *ses,char *fmt,...)
++{
++ va_list pvar;
++
++ va_start (pvar, fmt);
++
++ poe_logit (ses,LOG_INFO, fmt, pvar);
++ va_end (pvar);
++}
++
++/*
++ * poe_dbglog - log a debug message.
++ */
++void
++poe_dbglog (struct session *ses ,char *fmt,...)
++{
++ va_list pvar;
++
++ va_start (pvar, fmt);
++
++ poe_logit (ses,LOG_DEBUG, fmt, pvar);
++ va_end (pvar);
++}
++
++/*
++ * Create a file containing our process ID.
++ */
++void
++poe_create_pidfile (struct session *ses)
++{
++ FILE *pidfile;
++
++ sprintf (pidfilename, "%s%s.pid", _PATH_VARRUN, "pppoed");
++ if ((pidfile = fopen (pidfilename, "w")) != NULL) {
++ fprintf (pidfile, "%d\n", getpid ());
++ (void) fclose (pidfile);
++ }
++ else {
++ poe_error (ses,"Failed to create pid file %s: %m", pidfilename);
++ pidfilename[0] = 0;
++ }
++}
++
++/*
++ * detach - detach us from the controlling terminal.
++ */
++void
++poe_detach (struct session *ses)
++{
++ if (ses->detached)
++ return;
++
++ if ((daemon (0, 0)) < 0) {
++ poe_error (ses,"Couldn't detach (daemon failed: %m)");
++#if 0
++ poe_die (1); /* or just return? */
++#endif
++ }
++ ses->detached = 1;
++ ses->log_to_fd = -1;
++ /* update pid files if they have been written already */
++ if (pidfilename[0])
++ poe_create_pidfile (ses);
++}
++
++/*
++ * cleanup - restore anything which needs to be restored before we exit
++ */
++/* ARGSUSED */
++static void
++cleanup ()
++{
++ if (pidfilename[0] != 0 && unlink (pidfilename) < 0 && errno != ENOENT)
++ syslog (LOG_INFO,"unable to delete pid file ");
++ pidfilename[0] = 0;
++}
++
++/*
++ * poe_die - clean up state and exit with the specified status.
++ */
++void
++poe_die (int status)
++{
++ cleanup ();
++ syslog (LOG_INFO, "Exit.");
++ exit (status);
++}
+diff -r -N -u -b -B ppp-2.4.1.orig/pppd/pppd.h ppp-2.4.1.pppoe2/pppd/pppd.h
+--- ppp-2.4.1.orig/pppd/pppd.h Tue Mar 13 00:54:37 2001
++++ ppp-2.4.1.pppoe2/pppd/pppd.h Sun Apr 1 15:06:17 2001
+@@ -496,6 +496,8 @@
+ int open_ppp_loopback __P((void)); /* Open loopback for demand-dialling */
+ int tty_establish_ppp __P((int)); /* Turn serial port into a ppp interface */
+ void tty_disestablish_ppp __P((int)); /* Restore port to normal operation */
++void generic_disestablish_ppp __P((int dev_fd)); /* Restore device setting */
++int generic_establish_ppp __P((int dev_fd)); /* Make a ppp interface */
+ void make_new_bundle __P((int, int, int, int)); /* Create new bundle */
+ int bundle_attach __P((int)); /* Attach link to existing bundle */
+ void cfg_bundle __P((int, int, int, int)); /* Configure existing bundle */
+@@ -587,6 +589,7 @@
+ /* Simplified number_option for decimal ints */
+ void add_options __P((option_t *)); /* Add extra options */
+ void check_options __P((void)); /* check values after all options parsed */
++int remove_option __P((char *)); /* Disable the specified option */
+ int override_value __P((const char *, int, const char *));
+ /* override value if permitted by priority */
+ void print_options __P((void (*) __P((void *, char *, ...)), void *));
+diff -r -N -u -b -B ppp-2.4.1.orig/pppd/sys-linux.c ppp-2.4.1.pppoe2/pppd/sys-linux.c
+--- ppp-2.4.1.orig/pppd/sys-linux.c Tue Mar 13 00:54:41 2001
++++ ppp-2.4.1.pppoe2/pppd/sys-linux.c Sun Apr 1 15:44:53 2001
+@@ -141,7 +141,7 @@
+ static int restore_term = 0; /* 1 => we've munged the terminal */
+ static struct termios inittermios; /* Initial TTY termios */
+
+-static int new_style_driver = 0;
++int new_style_driver = 0;
+
+ static char loop_name[20];
+ static unsigned char inbuf[512]; /* buffer for chars read from loopback */
+@@ -352,23 +352,14 @@
+ return (1);
+ }
+
++
+ /********************************************************************
+ *
+- * tty_establish_ppp - Turn the serial port into a ppp interface.
++ * generic_establish_ppp - Turn the fd into a ppp interface.
+ */
+-
+-int tty_establish_ppp (int tty_fd)
++int generic_establish_ppp (int fd)
+ {
+ int x;
+- int fd = -1;
+-
+-/*
+- * Ensure that the tty device is in exclusive mode.
+- */
+- if (ioctl(tty_fd, TIOCEXCL, 0) < 0) {
+- if ( ! ok_error ( errno ))
+- warn("Couldn't make tty exclusive: %m");
+- }
+ /*
+ * Demand mode - prime the old ppp device to relinquish the unit.
+ */
+@@ -377,26 +368,13 @@
+ error("ioctl(transfer ppp unit): %m");
+ return -1;
+ }
+-/*
+- * Set the current tty to the PPP discpline
+- */
+
+-#ifndef N_SYNC_PPP
+-#define N_SYNC_PPP 14
+-#endif
+- ppp_disc = (new_style_driver && sync_serial)? N_SYNC_PPP: N_PPP;
+- if (ioctl(tty_fd, TIOCSETD, &ppp_disc) < 0) {
+- if ( ! ok_error (errno) ) {
+- error("Couldn't set tty to PPP discipline: %m");
+- return -1;
+- }
+- }
+
+ if (new_style_driver) {
+ /* Open another instance of /dev/ppp and connect the channel to it */
+ int flags;
+
+- if (ioctl(tty_fd, PPPIOCGCHAN, &chindex) == -1) {
++ if (ioctl(fd, PPPIOCGCHAN, &chindex) == -1) {
+ error("Couldn't get channel number: %m");
+ goto err;
+ }
+@@ -440,8 +419,8 @@
+ /*
+ * Old-style driver: find out which interface we were given.
+ */
+- set_ppp_fd (tty_fd);
+- if (ioctl(tty_fd, PPPIOCGUNIT, &x) < 0) {
++ set_ppp_fd (fd);
++ if (ioctl(fd, PPPIOCGUNIT, &x) < 0) {
+ if (ok_error (errno))
+ goto err;
+ fatal("ioctl(PPPIOCGUNIT): %m(%d)", errno);
+@@ -454,9 +433,9 @@
+ /*
+ * Fetch the initial file flags and reset blocking mode on the file.
+ */
+- initfdflags = fcntl(tty_fd, F_GETFL);
++ initfdflags = fcntl(fd, F_GETFL);
+ if (initfdflags == -1 ||
+- fcntl(tty_fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
++ fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
+ if ( ! ok_error (errno))
+ warn("Couldn't set device to non-blocking mode: %m");
+ }
+@@ -470,13 +450,6 @@
+ if (!looped)
+ set_kdebugflag (kdebugflag);
+
+-#define SC_RCVB (SC_RCV_B7_0 | SC_RCV_B7_1 | SC_RCV_EVNP | SC_RCV_ODDP)
+-#define SC_LOGB (SC_DEBUG | SC_LOG_INPKT | SC_LOG_OUTPKT | SC_LOG_RAWIN \
+- | SC_LOG_FLUSH)
+-
+- set_flags(ppp_fd, ((get_flags(ppp_fd) & ~(SC_RCVB | SC_LOGB))
+- | ((kdebugflag * SC_DEBUG) & SC_LOGB)));
+-
+ SYSDEBUG ((LOG_NOTICE, "Using version %d.%d.%d of PPP driver",
+ driver_version, driver_modification, driver_patch));
+
+@@ -485,22 +458,86 @@
+ err_close:
+ close(fd);
+ err:
+- if (ioctl(tty_fd, TIOCSETD, &tty_disc) < 0 && !ok_error(errno))
++ if (ioctl(fd, TIOCSETD, &tty_disc) < 0 && !ok_error(errno))
+ warn("Couldn't reset tty to normal line discipline: %m");
+ return -1;
+ }
+
+ /********************************************************************
+ *
+- * tty_disestablish_ppp - Restore the serial port to normal operation,
+- * and reconnect the ppp unit to the loopback if in demand mode.
++ * tty_establish_ppp - Turn the serial port into a ppp interface.
++ */
++
++int tty_establish_ppp (int tty_fd)
++{
++ int ret_fd;
++/*
++ * Ensure that the tty device is in exclusive mode.
++ */
++ if (ioctl(tty_fd, TIOCEXCL, 0) < 0) {
++ if ( ! ok_error ( errno ))
++ warn("Couldn't make tty exclusive: %m");
++ }
++/*
++ * Set the current tty to the PPP discpline
++ */
++
++#ifndef N_SYNC_PPP
++#define N_SYNC_PPP 14
++#endif
++ ppp_disc = (new_style_driver && sync_serial)? N_SYNC_PPP: N_PPP;
++ if (ioctl(tty_fd, TIOCSETD, &ppp_disc) < 0) {
++ if ( ! ok_error (errno) ) {
++ error("Couldn't set tty to PPP discipline: %m");
++ return -1;
++ }
++ }
++
++ ret_fd = generic_establish_ppp(tty_fd);
++#define SC_RCVB (SC_RCV_B7_0 | SC_RCV_B7_1 | SC_RCV_EVNP | SC_RCV_ODDP)
++#define SC_LOGB (SC_DEBUG | SC_LOG_INPKT | SC_LOG_OUTPKT | SC_LOG_RAWIN \
++ | SC_LOG_FLUSH)
++
++ set_flags(ppp_fd, ((get_flags(ppp_fd) & ~(SC_RCVB | SC_LOGB))
++ | ((kdebugflag * SC_DEBUG) & SC_LOGB)));
++
++ return ret_fd;
++}
++
++/********************************************************************
++ *
++ * generic_disestablish_ppp - Restore device components to normal
++ * operation, and reconnect the ppp unit to the loopback if in demand
++ * mode. This shouldn't call die() because it's called from die().
++*/
++void generic_disestablish_ppp(int dev_fd){
++ /* Restore loop if needed */
++ if(demand)
++ restore_loop();
++
++ /* Finally detach the device */
++ initfdflags = -1;
++
++ if (new_style_driver) {
++ close(ppp_fd);
++ ppp_fd = -1;
++ if (!looped && ifunit >= 0 && ioctl(ppp_dev_fd, PPPIOCDETACH) < 0)
++ error("Couldn't release PPP unit: %m");
++ if (!multilink)
++ remove_fd(ppp_dev_fd);
++ }
++}
++
++/********************************************************************
++ *
++ * tty_disestablish_ppp - Restore the serial port to normal operation.
+ * This shouldn't call die() because it's called from die().
+ */
+
+ void tty_disestablish_ppp(int tty_fd)
+ {
+- if (demand)
+- restore_loop();
++ generic_disestablish_ppp(tty_fd);
++
+ if (!hungup) {
+ /*
+ * Flush the tty output buffer so that the TIOCSETD doesn't hang.
+@@ -526,16 +563,6 @@
+ warn("Couldn't restore device fd flags: %m");
+ }
+ }
+- initfdflags = -1;
+-
+- if (new_style_driver) {
+- close(ppp_fd);
+- ppp_fd = -1;
+- if (!looped && ifunit >= 0 && ioctl(ppp_dev_fd, PPPIOCDETACH) < 0)
+- error("Couldn't release PPP unit: %m");
+- if (!multilink)
+- remove_fd(ppp_dev_fd);
+- }
+ }
+
+ /*
+@@ -2567,7 +2594,7 @@
+ * Just to be sure, set the real serial port to the normal discipline.
+ */
+
+-static void
++void
+ restore_loop(void)
+ {
+ looped = 1;
+diff -r -N -u -b -B ppp-2.4.1.orig/sunos4/Makefile ppp-2.4.1.pppoe2/sunos4/Makefile
+--- ppp-2.4.1.orig/sunos4/Makefile Tue Mar 24 22:09:35 1998
++++ ppp-2.4.1.pppoe2/sunos4/Makefile Wed Dec 31 19:00:00 1969
+@@ -1,57 +0,0 @@
+-#
+-# Makefile for STREAMS modules for SunOS 4.
+-#
+-# $Id$
+-#
+-
+-include Makedefs
+-
+-LD = /usr/bin/ld # make sure we don't get gnu ld
+-
+-# Defining __$(ARCH)__ is for gcc's broken version of sun/vddrv.h.
+-ARCH = `/bin/arch -k`
+-DEFINES= -DKERNEL -D_KERNEL -DSUNOS4 -D$(ARCH) -D__$(ARCH)__ \
+- -DDEBUG -DNO_DLPI -DSNIT_SUPPORT
+-CFLAGS= $(DEFINES) -I../include $(COPTS)
+-
+-MODULES= ppp_mod.o ppp_ahdl_mod.o ppp_comp_mod.o if_ppp_mod.o
+-
+-all: $(MODULES)
+-
+-ppp_mod.o: ppp.o ppp_vdcmd.o
+- $(LD) -r -o ppp_mod.o ppp.o ppp_vdcmd.o
+-
+-ppp_ahdl_mod.o: ppp_ahdlc.o ppp_ahdlc_vdcmd.o
+- $(LD) -r -o ppp_ahdl_mod.o ppp_ahdlc.o ppp_ahdlc_vdcmd.o
+-
+-COMP_OBJS = ppp_comp.o bsd-comp.o deflate.o zlib.o vjcompress.o \
+- ppp_comp_vdcmd.o
+-ppp_comp_mod.o: $(COMP_OBJS)
+- $(LD) -r -o $@ $(COMP_OBJS)
+-
+-if_ppp.o: ../modules/if_ppp.c
+- $(CC) $(CFLAGS) -c $?
+-bsd-comp.o: ../modules/bsd-comp.c
+- $(CC) $(CFLAGS) -c $?
+-deflate.o: ../modules/deflate.c
+- $(CC) $(CFLAGS) -c $?
+-ppp.o: ../modules/ppp.c
+- $(CC) $(CFLAGS) -c $?
+-ppp_ahdlc.o: ../modules/ppp_ahdlc.c
+- $(CC) $(CFLAGS) -c $?
+-ppp_comp.o: ../modules/ppp_comp.c
+- $(CC) $(CFLAGS) -c $?
+-vjcompress.o: ../modules/vjcompress.c
+- $(CC) $(CFLAGS) -c $?
+-zlib.o: ../common/zlib.c
+- $(CC) $(CFLAGS) -c $?
+-
+-if_ppp_mod.o: if_ppp.o if_ppp_vdcmd.o
+- $(LD) -r -o if_ppp_mod.o if_ppp.o if_ppp_vdcmd.o
+-
+-install: all
+- $(INSTALL) $(MODULES) $(BINDIR)
+- ./ppp.INSTALL
+-
+-clean:
+- rm -f ppp ppp_comp ppp_ahdl *.o *~ core