1 package ethernet 2 3 import ( 4 "encoding/binary" 5 "errors" 6 "io" 7 ) 8 9 const ( 10 // VLANNone is a special VLAN ID which indicates that no VLAN is being 11 // used in a Frame. In this case, the VLAN's other fields may be used 12 // to indicate a Frame's priority. 13 VLANNone = 0x000 14 15 // VLANMax is a reserved VLAN ID which may indicate a wildcard in some 16 // management systems, but may not be configured or transmitted in a 17 // VLAN tag. 18 VLANMax = 0xfff 19 ) 20 21 // ErrInvalidVLAN is returned when a VLAN tag is invalid due to one of the 22 // following reasons: 23 // - Priority of greater than 7 is detected 24 // - ID of greater than 4094 (0xffe) is detected 25 // - A customer VLAN does not follow a service VLAN (when using Q-in-Q) 26 var ErrInvalidVLAN = errors.New("invalid VLAN") 27 28 // Priority is an IEEE P802.1p priority level. Priority can be any value from 29 // 0 to 7. 30 // 31 // It is important to note that priority 1 (PriorityBackground) actually has 32 // a lower priority than 0 (PriorityBestEffort). All other Priority constants 33 // indicate higher priority as the integer values increase. 34 type Priority uint8 35 36 // IEEE P802.1p recommended priority levels. Note that PriorityBackground has 37 // a lower priority than PriorityBestEffort. 38 const ( 39 PriorityBackground Priority = 1 40 PriorityBestEffort Priority = 0 41 PriorityExcellentEffort Priority = 2 42 PriorityCriticalApplications Priority = 3 43 PriorityVideo Priority = 4 44 PriorityVoice Priority = 5 45 PriorityInternetworkControl Priority = 6 46 PriorityNetworkControl Priority = 7 47 ) 48 49 // A VLAN is an IEEE 802.1Q Virtual LAN (VLAN) tag. A VLAN contains 50 // information regarding traffic priority and a VLAN identifier for 51 // a given Frame. 52 type VLAN struct { 53 // Priority specifies a IEEE P802.1p priority level. Priority can be any 54 // value from 0 to 7. 55 Priority Priority 56 57 // DropEligible indicates if a Frame is eligible to be dropped in the 58 // presence of network congestion. 59 DropEligible bool 60 61 // ID specifies the VLAN ID for a Frame. ID can be any value from 0 to 62 // 4094 (0x000 to 0xffe), allowing up to 4094 VLANs. 63 // 64 // If ID is 0 (0x000, VLANNone), no VLAN is specified, and the other fields 65 // simply indicate a Frame's priority. 66 ID uint16 67 } 68 69 // MarshalBinary allocates a byte slice and marshals a VLAN into binary form. 70 func (v *VLAN) MarshalBinary() ([]byte, error) { 71 b := make([]byte, 2) 72 _, err := v.read(b) 73 return b, err 74 } 75 76 // read reads data from a VLAN into b. read is used to marshal a VLAN into 77 // binary form, but does not allocate on its own. 78 func (v *VLAN) read(b []byte) (int, error) { 79 // Check for VLAN priority in valid range 80 if v.Priority > PriorityNetworkControl { 81 return 0, ErrInvalidVLAN 82 } 83 84 // Check for VLAN ID in valid range 85 if v.ID >= VLANMax { 86 return 0, ErrInvalidVLAN 87 } 88 89 // 3 bits: priority 90 ub := uint16(v.Priority) << 13 91 92 // 1 bit: drop eligible 93 var drop uint16 94 if v.DropEligible { 95 drop = 1 96 } 97 ub |= drop << 12 98 99 // 12 bits: VLAN ID 100 ub |= v.ID 101 102 binary.BigEndian.PutUint16(b, ub) 103 return 2, nil 104 } 105 106 // UnmarshalBinary unmarshals a byte slice into a VLAN. 107 func (v *VLAN) UnmarshalBinary(b []byte) error { 108 // VLAN tag is always 2 bytes 109 if len(b) != 2 { 110 return io.ErrUnexpectedEOF 111 } 112 113 // 3 bits: priority 114 // 1 bit : drop eligible 115 // 12 bits: VLAN ID 116 ub := binary.BigEndian.Uint16(b[0:2]) 117 v.Priority = Priority(uint8(ub >> 13)) 118 v.DropEligible = ub&0x1000 != 0 119 v.ID = ub & 0x0fff 120 121 // Check for VLAN ID in valid range 122 if v.ID >= VLANMax { 123 return ErrInvalidVLAN 124 } 125 126 return nil 127 } 128