use crate::bmp::bmputl::*;
use crate::message::notification::BgpNotificationMessage;
use crate::message::open::BgpOpenMessage;
use crate::message::*;
use crate::util::*;
use crate::{BgpError, BgpMessage, BgpSessionParams};
use std::convert::TryInto;
#[derive(Debug, Clone)]
pub struct BmpMessagePeerUp {
pub peer: BmpMessagePeerHeader,
pub localaddress: std::net::IpAddr,
pub localport: u16,
pub remoteport: u16,
pub msg1: BgpOpenMessage,
pub msg2: BgpOpenMessage,
}
#[derive(Debug)]
pub enum BmpMessagePeerDownReason {
AdministrativelyClosed(BgpNotificationMessage), LocalSystemState(u16), RemoteNotification(BgpNotificationMessage), Remote, BmpDisabled, }
#[derive(Debug)]
pub struct BmpMessagePeerDown {
pub peer: BmpMessagePeerHeader,
pub reason: BmpMessagePeerDownReason,
}
impl BmpMessagePeerUp {
pub fn decode_from(buf: &[u8]) -> Result<(BmpMessagePeerUp, usize), BgpError> {
if buf.len() < 62 {
return Err(BgpError::InsufficientBufferSize(file!(), line!()));
}
let pm = BmpMessagePeerHeader::decode_from(buf)?;
let mut ret = BmpMessagePeerUp {
peer: pm.0,
localaddress: decode_bmp_addr_from(&buf[pm.1..])?,
localport: getn_u16(&buf[pm.1 + 16..]),
remoteport: getn_u16(&buf[pm.1 + 18..]),
msg1: BgpOpenMessage::new(),
msg2: BgpOpenMessage::new(),
};
let sesspars = BgpSessionParams::from(&ret.peer);
let mut pos: usize = pm.1 + 20;
let msgt = sesspars.decode_message_head(&buf[pos..])?;
pos += 19;
if msgt.0 != BgpMessageType::Open {
return Err(BgpError::static_str("Invalid BGP message type #1"));
}
ret.msg1.decode_from(&sesspars, &buf[pos..pos + msgt.1])?;
pos += msgt.1;
let msgt = sesspars.decode_message_head(&buf[pos..])?;
pos += 19;
if msgt.0 != BgpMessageType::Open {
return Err(BgpError::static_str("Invalid BGP message type #2"));
}
ret.msg2.decode_from(&sesspars, &buf[pos..pos + msgt.1])?;
pos += msgt.1;
Ok((ret, pos))
}
pub fn encode_to(&self, buf: &mut [u8]) -> Result<usize, BgpError> {
if buf.len() < 62 {
return Err(BgpError::InsufficientBufferSize(file!(), line!()));
}
let mut curpos: usize = 0;
curpos += self.peer.encode_to(buf)?;
encode_bmp_addr_to(&self.localaddress, &mut buf[curpos..])?;
curpos += 16;
setn_u16(self.localport, &mut buf[curpos..]);
curpos += 2;
setn_u16(self.remoteport, &mut buf[curpos..]);
curpos += 2;
let sesspars: &BgpSessionParams = &(&self.peer).into();
let messagelen = self.msg1.encode_to(sesspars, &mut buf[curpos + 19..])?;
let blen =
sesspars.prepare_message_buf(&mut buf[curpos..], BgpMessageType::Open, messagelen)?;
curpos += blen;
let messagelen = self.msg2.encode_to(sesspars, &mut buf[curpos + 19..])?;
let blen =
sesspars.prepare_message_buf(&mut buf[curpos..], BgpMessageType::Open, messagelen)?;
curpos += blen;
Ok(curpos)
}
}
impl BmpMessagePeerDown {
pub fn decode_from(buf: &[u8]) -> Result<(BmpMessagePeerDown, usize), BgpError> {
if buf.len() < 43 {
return Err(BgpError::InsufficientBufferSize(file!(), line!()));
}
let pm = BmpMessagePeerHeader::decode_from(buf)?;
let mut pos = pm.1;
let reason_code = buf[pos];
pos += 1;
let reason = match reason_code {
1 => {
let sesspars = BgpSessionParams::from(&pm.0);
let msgt = sesspars.decode_message_head(&buf[pos..])?;
pos += 19;
if msgt.0 != BgpMessageType::Notification {
return Err(BgpError::static_str("Invalid BGP message type"));
}
let mut msg = BgpNotificationMessage::new();
msg.decode_from(&sesspars, &buf[pos..pos + msgt.1])?;
pos += msgt.1;
BmpMessagePeerDownReason::AdministrativelyClosed(msg)
}
2 => {
if buf.len() - pos < 2 {
return Err(BgpError::InsufficientBufferSize(file!(), line!()));
}
let state = u16::from_be_bytes((&buf[pos..pos + 2]).try_into().unwrap());
pos += 2;
BmpMessagePeerDownReason::LocalSystemState(state)
}
3 => {
let sesspars = BgpSessionParams::from(&pm.0);
let msgt = sesspars.decode_message_head(&buf[pos..])?;
pos += 19;
if msgt.0 != BgpMessageType::Notification {
return Err(BgpError::static_str("Invalid BGP message type"));
}
let mut msg = BgpNotificationMessage::new();
msg.decode_from(&sesspars, &buf[pos..pos + msgt.1])?;
pos += msgt.1;
BmpMessagePeerDownReason::RemoteNotification(msg)
}
4 => BmpMessagePeerDownReason::Remote,
5 => BmpMessagePeerDownReason::BmpDisabled,
_ => return Err(BgpError::static_str("Unknown BMP Peer Down Reason Type")),
};
Ok((BmpMessagePeerDown { peer: pm.0, reason }, pos))
}
pub fn encode_to(&self, buf: &mut [u8]) -> Result<usize, BgpError> {
if buf.len() < 43 {
return Err(BgpError::InsufficientBufferSize(file!(), line!()));
}
let mut curpos: usize = 0;
curpos += self.peer.encode_to(buf)?;
match &self.reason {
BmpMessagePeerDownReason::AdministrativelyClosed(msg) => {
buf[curpos] = 1;
curpos += 1;
if buf.len() - curpos < 19 {
return Err(BgpError::InsufficientBufferSize(file!(), line!()));
}
let sesspars: &BgpSessionParams = &(&self.peer).into();
let messagelen = msg.encode_to(sesspars, &mut buf[curpos + 19..])?;
let blen = sesspars.prepare_message_buf(
&mut buf[curpos..],
BgpMessageType::Notification,
messagelen,
)?;
curpos += blen;
}
BmpMessagePeerDownReason::LocalSystemState(state) => {
buf[curpos] = 2;
curpos += 1;
if buf.len() - curpos < 2 {
return Err(BgpError::InsufficientBufferSize(file!(), line!()));
}
setn_u16(*state, &mut buf[curpos..]);
curpos += 2;
}
BmpMessagePeerDownReason::RemoteNotification(msg) => {
buf[curpos] = 3;
curpos += 1;
if buf.len() - curpos < 19 {
return Err(BgpError::InsufficientBufferSize(file!(), line!()));
}
let sesspars: &BgpSessionParams = &(&self.peer).into();
let messagelen = msg.encode_to(sesspars, &mut buf[curpos + 19..])?;
let blen = sesspars.prepare_message_buf(
&mut buf[curpos..],
BgpMessageType::Notification,
messagelen,
)?;
curpos += blen;
}
BmpMessagePeerDownReason::Remote => {
buf[curpos] = 4;
curpos += 1;
}
BmpMessagePeerDownReason::BmpDisabled => {
buf[curpos] = 5;
curpos += 1;
}
}
Ok(curpos)
}
}