1use nom::{rest,be_u16};
2
3use {ParseOps,ConvError};
4use packet_writer::{PacketWriter,WriteFields};
5
6named!(bytes_to_ethernet<&[u8], EthHdr>, do_parse!(
7 src: take!(6) >>
8 dest: take!(6) >>
9 eth_type: be_u16 >>
10 (EthHdr { mac_src: src, mac_dest: dest, eth_type: EthType::from(eth_type) })
11));
12named!(strip_ethernet<&[u8]>, do_parse!(
13 take!(14) >>
14 inner_bytes: rest >>
15 (inner_bytes)
16));
17
18c_enum!(EthType, u16, {
19 IPv4 => 0x0800
20});
21
22#[derive(Debug,PartialEq)]
23pub struct EthHdr<'a> {
24 mac_src: &'a [u8],
25 mac_dest: &'a [u8],
26 eth_type: EthType,
27}
28
29impl<'a> ParseOps<'a> for EthHdr<'a> {
30 fn to_bytes(self) -> Result<Vec<u8>, ConvError> {
31 let mut pw = PacketWriter::new();
32 pw.write_bytes(self.mac_src)?;
33 pw.write_bytes(self.mac_dest)?;
34 <PacketWriter as WriteFields<Vec<u8>>>::write_u16::<u16>(
35 &mut pw, self.eth_type as u16
36 )?;
37 Ok(pw.get_result())
38 }
39
40 fn from_bytes(buf: &'a [u8]) -> Result<Self, ConvError> {
41 match bytes_to_ethernet(buf) {
42 Ok((_, ip)) => Ok(ip),
43 Err(e) => {
44 Err(ConvError(
45 format!("Failed to parse - here is the remaining output: {:?}", e)
46 ))
47 },
48 }
49 }
50
51 fn strip_header(buf: &[u8]) -> Result<&[u8], ConvError> {
52 match strip_ethernet(buf) {
53 Ok((_, eth)) => Ok(eth),
54 Err(e) => {
55 Err(ConvError(
56 format!("Failed to parse - here is the remaining output: {:?}", e)
57 ))
58 },
59 }
60 }
61}
62
63#[cfg(test)]
64mod test {
65 use super::*;
66
67 #[test]
68 fn test_write_header() {
69 assert_eq!(EthHdr { mac_src: &[1, 2, 3, 4, 5, 6],
70 mac_dest: &[7, 8, 9, 10, 11, 12],
71 eth_type: EthType::IPv4,
72 }.to_bytes().unwrap(), &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0x08, 0x00])
73 }
74
75 #[test]
76 fn test_parse_header() {
77 let s = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0x08, 0x00, 15, 16, 17];
78 assert_eq!(EthHdr { mac_src: &[1, 2, 3, 4, 5, 6],
79 mac_dest: &[7, 8, 9, 10, 11, 12],
80 eth_type: EthType::IPv4 },
81 EthHdr::from_bytes(s).unwrap())
82 }
83
84 #[test]
85 fn test_strip_header() {
86 let s = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17];
87 assert_eq!(EthHdr::strip_header(s).unwrap(), &[15, 16, 17])
88 }
89}