/* * bacp.cc - Self explanitory * Copyright (C) 1997-2000 SpellCaster Telecommunications Inc. * $Id: bacp.cc,v 1.2 2004/04/07 15:15:51 bcrl Exp $ * Released under the GNU Public License. See LICENSE file for details. */ #include "debug.h" #include "bacp.h" #include "iface.h" static unsigned char fatalCodes[] = { CONFREQ, CONFACK, CONFNAK, CONFREJ, TERMREQ, TERMACK, CODEREJ }; CBacpProtocol::CBacpProtocol() { DebugEnter("CBacpProtocol::CBacpProtocol()"); m_parent->m_lcfg.loc_fpeer = jiffies; m_parent->m_lcfg.rem_fpeer = 0; DebugExit(); } CBacpProtocol::~CBacpProtocol() { DebugEnter("CBacpProtocol::~CBacpProtocol()"); DebugExit(); } void CBacpProtocol::Input(CPppPacket *pkt) { u8 code = pkt->Pull8(); u8 ident = pkt->Pull8(); u16 len = pkt->Pull16(); DebugEnter("CBacpProtocol::Input()"); switch(code) { case CONFREQ: Log(LF_DEBUG|LF_PROTO, "Bacp CONFREQ"); m_lastRcvdIdent = ident; RcvConfReq(pkt); break; case CONFACK: Log(LF_DEBUG|LF_PROTO, "Bacp CONFACK"); if(ident != m_lastSentIdent) { // Drop Packet Log(LF_DEBUG|LF_PROTO, "BACP ConfAck, Bad Ident...dropping"); DebugVoidReturn; } RcvConfAck(pkt); break; case CONFNAK: Log(LF_DEBUG|LF_PROTO, "Bacp CONFNAK"); if(ident != m_lastSentIdent) { // Drop Packet Log(LF_INFO|LF_PROTO, "BACP ConfNak, Bad Ident...dropping"); DebugVoidReturn; } RcvConfNak(pkt); break; case CONFREJ: Log(LF_DEBUG|LF_PROTO, "Bacp CONFREJ"); if(ident != m_lastSentIdent) { // Drop Packet Log(LF_DEBUG|LF_PROTO, "BACP ConfRej, Bad Ident...dropping"); DebugVoidReturn; } RcvConfRej(pkt); break; case TERMREQ: Log(LF_DEBUG|LF_PROTO, "Bacp TERMREQ"); m_lastRcvdIdent = ident; RcvTermReq(); break; case TERMACK: Log(LF_DEBUG|LF_PROTO, "Bacp TERMACK"); if(ident != m_lastSentIdent) { // Drop Packet Log(LF_DEBUG|LF_INFO, "BACP TermAck, Bad Ident...dropping"); DebugVoidReturn; } RcvTermAck(); break; case CODEREJ: Log(LF_DEBUG|LF_PROTO, "Bacp CODEREJ"); RcvCodeReject(pkt); break; default: Log(LF_DEBUG|LF_PROTO, "Bacp Unknown"); SndCodeReject(pkt); RcvUnknownCode(); break; } DebugVoidReturn; } void CBacpProtocol::RcvConfReq(CPppPacket *pkt) { OptionSet_t ack_opts; u32 fpeer; // Peer FP magic-number u8 rdata[254]; DebugEnter("CBacpProtocol::RcvConfReq()"); Log(LF_DEBUG|LF_PROTO, "BACP Rcvd ConfReq -->"); OptionSet_t &will = m_parent->links->ifOptions; ack_opts.Set(m_parent->m_lcfg); // Create response packets CPppPacket ackPkt, nakPkt, rejPkt; ackPkt.Reserve(PPP_HEADER_LENGTH + BACP_HEADER_LENGTH); nakPkt.Reserve(PPP_HEADER_LENGTH + BACP_HEADER_LENGTH); rejPkt.Reserve(PPP_HEADER_LENGTH + BACP_HEADER_LENGTH); while(pkt->GetLength()) { u8 type = pkt->Pull8(); u8 len = pkt->Pull8(); switch(type) { case BACP_OPT_FPEER: if(len != BACP_OPT_FPEER_LEN) { // Wrong size, reject option Log(LF_DEBUG|LF_PROTO, "Wrong size - rejecting"); pkt->Pull(rdata, len - 2); rejPkt.Put8(type); rejPkt.Put8(len); rejPkt.Put(rdata, len - 2); Log(LF_DEBUG|LF_PROTO, "BACP ConfReq: [FPEER], Invalid size (%d)", len); } else { fpeer = pkt->Pull32(); if(fpeer == 0) { nakPkt.Put8(type); nakPkt.Put8(len); nakPkt.Put32(fpeer); } else if(fpeer == will.loc_fpeer) { nakPkt.Put8(type); nakPkt.Put8(len); nakPkt.Put32(fpeer); } else { // Ack ackPkt.Put8(type); ackPkt.Put8(len); ackPkt.Put32(fpeer); ack_opts.rem_fpeer = fpeer; } } break; default: Log(LF_DEBUG|LF_PROTO, "Unknown BACP option"); // Reject this unknown option rejPkt.Put8(type); rejPkt.Put8(len); pkt->Pull(rdata, len -2); rejPkt.Put(rdata, len - 2); break; } } // If we are rejecting, send it if(rejPkt.GetLength()) { rejPkt.Push16(rejPkt.GetLength() + BACP_HEADER_LENGTH); rejPkt.Push8(m_lastRcvdIdent); rejPkt.Push8(CONFREJ); rejPkt.Push16(PPP_PROTO_BACP); m_parent->Output(&rejPkt); RcvBadConfReq(); DebugVoidReturn; } // If we are naking, send it if(nakPkt.GetLength()) { nakPkt.Push16(nakPkt.GetLength() + BACP_HEADER_LENGTH); nakPkt.Push8(m_lastRcvdIdent); nakPkt.Push8(CONFNAK); nakPkt.Push16(PPP_PROTO_BACP); m_parent->Output(&nakPkt); RcvBadConfReq(); DebugVoidReturn; } m_parent->m_lcfg.Set(ack_opts); ackPkt.Push16(ackPkt.GetLength() + BACP_HEADER_LENGTH); ackPkt.Push8(m_lastRcvdIdent); ackPkt.Push8(CONFACK); ackPkt.Push16(PPP_PROTO_BACP); m_parent->Output(&ackPkt); RcvGoodConfReq(); DebugVoidReturn; } void CBacpProtocol::RcvConfNak(CPppPacket *packet) { DebugEnter("CBacpProtocol::RcvConfNak()"); Log(LF_INFO|LF_PROTO, "BACP Rcvd ConfNak -->"); while(packet->GetLength()) { u8 type = packet->Pull8(); u8 len = packet->Pull8(); u8 rdata[254]; switch(type) { case BACP_OPT_FPEER: // // Generate a new number // m_parent->m_lcfg.loc_fpeer = jiffies; packet->Pull32(); } } CFsmProtocol::RcvConfNak(); DebugVoidReturn; } void CBacpProtocol::RcvConfRej(CPppPacket *packet) { DebugEnter("CBacpProtocol::RcvConfRej()"); // Same state transition so use Nak CFsmProtocol::RcvConfNak(); DebugVoidReturn; } void CBacpProtocol::RcvConfAck(CPppPacket *packet) { DebugEnter("CBacpProtocol::RcvConfAck()"); CFsmProtocol::RcvConfAck(); DebugVoidReturn; } void CBacpProtocol::SndTermReq() { CPppPacket reqPkt; DebugEnter("CBacpProtocol::SndTermReq()"); reqPkt.Reserve(PPP_HEADER_LENGTH + BACP_HEADER_LENGTH); reqPkt.Push16(4); reqPkt.Push8(m_lastSentIdent++); reqPkt.Push8(TERMREQ); reqPkt.Push16(PPP_PROTO_BACP); m_parent->Output(&reqPkt); DebugVoidReturn; } void CBacpProtocol::SndTermAck() { CPppPacket ackPkt; DebugEnter("CBacpProtocol::SndTermAck()"); ackPkt.Reserve(PPP_HEADER_LENGTH + BACP_HEADER_LENGTH); ackPkt.Push16(4); ackPkt.Push8(m_lastRcvdIdent); ackPkt.Push8(TERMACK); ackPkt.Push16(PPP_PROTO_BACP); m_parent->Output(&ackPkt); DebugVoidReturn; } void CBacpProtocol::SndConfReq() { CPppPacket c; DebugEnter("CBacpProtocol::SndConfReq()"); OptionSet_t &want = m_parent->m_lcfg; c.Reserve(PPP_HEADER_LENGTH + BACP_HEADER_LENGTH); c.Put8(BACP_OPT_FPEER); c.Put8(BACP_OPT_FPEER_LEN); c.Put32(want.loc_fpeer); c.Push16(c.GetLength() + BACP_HEADER_LENGTH); c.Push8(++m_lastSentIdent); c.Push8(CONFREQ); c.Push16(PPP_PROTO_BACP); m_parent->Output(&c); DebugVoidReturn; } void CBacpProtocol::SndCodeReject(CPppPacket *packet) { CPppPacket cr; DebugEnter("CBacpProtocol::SndCodeReject()"); cr.Reserve(PPP_HEADER_LENGTH + BACP_HEADER_LENGTH); // Truncate the packet if necessary if(packet->GetLength() + BACP_HEADER_LENGTH > 1500) { packet->Chop(packet->GetLength() + BACP_HEADER_LENGTH - 1500); } cr.Put(packet); cr.Push16(packet->GetLength() + BACP_HEADER_LENGTH + PPP_HEADER_LENGTH); cr.Push8(m_lastRcvdIdent); cr.Push8(CODEREJ); cr.Push16(PPP_PROTO_BACP); m_parent->Output(&cr); DebugVoidReturn; } void CBacpProtocol::RcvCodeReject(CPppPacket *pkt) { int i; u8 code = *((u8 *)pkt); DebugEnter("CBacpProtocol::RcvCodeReject()"); // Determine if the code is fatal or not while(fatalCodes[i] != '\0') { if(fatalCodes[i] == code) { // Fatal, close the link RcvFatalReject(); } i++; } // The rejected code is not fatal, reconfigure to stop // sending the code CFsmProtocol::RcvCodeReject(); DebugVoidReturn; } void CBacpProtocol::ThisLayerUp() { DebugEnter("CBacpProtocol::ThisLayerUp()"); m_parent->m_bapProto.Up(); DebugVoidReturn; } void CBacpProtocol::ThisLayerDown() { DebugEnter("CBacpProtocol::ThisLayerDown()"); m_parent->m_bapProto.Down(); DebugVoidReturn; }