github.com/contiv/libOpenflow@v0.0.0-20210609050114-d967b14cc688/protocol/ethernet.go (about) 1 package protocol 2 3 import ( 4 "encoding/binary" 5 "errors" 6 "net" 7 8 "github.com/contiv/libOpenflow/util" 9 ) 10 11 // see http://en.wikipedia.org/wiki/EtherType 12 const ( 13 IPv4_MSG = 0x0800 14 ARP_MSG = 0x0806 15 LLDP_MSG = 0x88cc 16 WOL_MSG = 0x0842 17 RARP_MSG = 0x8035 18 VLAN_MSG = 0x8100 19 20 IPv6_MSG = 0x86DD 21 STP_MSG = 0x4242 22 STP_BPDU_MSG = 0xAAAA 23 ) 24 25 type Ethernet struct { 26 Delimiter uint8 27 HWDst net.HardwareAddr 28 HWSrc net.HardwareAddr 29 VLANID VLAN 30 Ethertype uint16 31 Data util.Message 32 } 33 34 func NewEthernet() *Ethernet { 35 eth := new(Ethernet) 36 eth.HWDst = net.HardwareAddr(make([]byte, 6)) 37 eth.HWSrc = net.HardwareAddr(make([]byte, 6)) 38 eth.VLANID = *NewVLAN() 39 eth.Ethertype = 0x800 40 eth.Data = nil 41 return eth 42 } 43 44 func (e *Ethernet) Len() (n uint16) { 45 n = 0 46 n += 12 47 if e.VLANID.VID != 0 { 48 n += 4 49 } 50 n += 2 51 if e.Data != nil { 52 n += e.Data.Len() 53 } 54 return 55 } 56 57 func (e *Ethernet) MarshalBinary() (data []byte, err error) { 58 data = make([]byte, int(e.Len())) 59 bytes := make([]byte, 0) 60 n := 0 61 copy(data[n:], e.HWDst) 62 n += len(e.HWDst) 63 copy(data[n:], e.HWSrc) 64 n += len(e.HWSrc) 65 66 if e.VLANID.VID != 0 { 67 bytes, err = e.VLANID.MarshalBinary() 68 if err != nil { 69 return 70 } 71 copy(data[n:], bytes) 72 n += len(bytes) 73 } 74 75 binary.BigEndian.PutUint16(data[n:n+2], e.Ethertype) 76 n += 2 77 78 if e.Data != nil { 79 bytes, err = e.Data.MarshalBinary() 80 if err != nil { 81 return 82 } 83 copy(data[n:n+len(bytes)], bytes) 84 } 85 return 86 } 87 88 func (e *Ethernet) UnmarshalBinary(data []byte) error { 89 if len(data) < 14 { 90 return errors.New("The []byte is too short to unmarshal a full Ethernet message.") 91 } 92 n := 0 93 e.HWDst = net.HardwareAddr(make([]byte, 6)) 94 copy(e.HWDst, data[n:n+6]) 95 n += 6 96 e.HWSrc = net.HardwareAddr(make([]byte, 6)) 97 copy(e.HWSrc, data[n:n+6]) 98 n += 6 99 100 e.Ethertype = binary.BigEndian.Uint16(data[n:]) 101 if e.Ethertype == VLAN_MSG { 102 e.VLANID = *new(VLAN) 103 err := e.VLANID.UnmarshalBinary(data[n:]) 104 if err != nil { 105 return err 106 } 107 n += int(e.VLANID.Len()) 108 109 e.Ethertype = binary.BigEndian.Uint16(data[n:]) 110 } else { 111 e.VLANID = *new(VLAN) 112 e.VLANID.VID = 0 113 } 114 n += 2 115 116 switch e.Ethertype { 117 case IPv4_MSG: 118 e.Data = new(IPv4) 119 case IPv6_MSG: 120 e.Data = new(IPv6) 121 case ARP_MSG: 122 e.Data = new(ARP) 123 default: 124 e.Data = new(util.Buffer) 125 } 126 return e.Data.UnmarshalBinary(data[n:]) 127 } 128 129 const ( 130 PCP_MASK = 0xe000 131 DEI_MASK = 0x1000 132 VID_MASK = 0x0fff 133 ) 134 135 type VLAN struct { 136 TPID uint16 137 PCP uint8 138 DEI uint8 139 VID uint16 140 } 141 142 func NewVLAN() *VLAN { 143 v := new(VLAN) 144 v.TPID = 0x8100 145 v.VID = 0 146 return v 147 } 148 149 func (v *VLAN) Len() (n uint16) { 150 return 4 151 } 152 153 func (v *VLAN) MarshalBinary() (data []byte, err error) { 154 data = make([]byte, v.Len()) 155 binary.BigEndian.PutUint16(data[:2], v.TPID) 156 var tci uint16 157 tci = (tci | uint16(v.PCP)<<13) + (tci | uint16(v.DEI)<<12) + (tci | v.VID) 158 binary.BigEndian.PutUint16(data[2:], tci) 159 return 160 } 161 162 func (v *VLAN) UnmarshalBinary(data []byte) error { 163 if len(data) < 4 { 164 return errors.New("The []byte is too short to unmarshal a full VLAN header.") 165 } 166 v.TPID = binary.BigEndian.Uint16(data[:2]) 167 var tci uint16 168 tci = binary.BigEndian.Uint16(data[2:]) 169 v.PCP = uint8(PCP_MASK & tci >> 13) 170 v.DEI = uint8(DEI_MASK & tci >> 12) 171 v.VID = VID_MASK & tci 172 return nil 173 }