github.com/gopacket/gopacket@v1.1.0/layers/gtp.go (about) 1 // Copyright 2017 Google, Inc. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style license 4 // that can be found in the LICENSE file in the root of the source 5 // tree. 6 // 7 8 package layers 9 10 import ( 11 "encoding/binary" 12 "fmt" 13 14 "github.com/gopacket/gopacket" 15 ) 16 17 const gtpMinimumSizeInBytes int = 8 18 19 // GTPExtensionHeader is used to carry extra data and enable future extensions of the GTP without the need to use another version number. 20 type GTPExtensionHeader struct { 21 Type uint8 22 Content []byte 23 } 24 25 // GTPv1U protocol is used to exchange user data over GTP tunnels across the Sx interfaces. 26 // Defined in https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=1595 27 type GTPv1U struct { 28 BaseLayer 29 Version uint8 30 ProtocolType uint8 31 Reserved uint8 32 ExtensionHeaderFlag bool 33 SequenceNumberFlag bool 34 NPDUFlag bool 35 MessageType uint8 36 MessageLength uint16 37 TEID uint32 38 SequenceNumber uint16 39 NPDU uint8 40 GTPExtensionHeaders []GTPExtensionHeader 41 } 42 43 // LayerType returns LayerTypeGTPV1U 44 func (g *GTPv1U) LayerType() gopacket.LayerType { return LayerTypeGTPv1U } 45 46 // DecodeFromBytes analyses a byte slice and attempts to decode it as a GTPv1U packet 47 func (g *GTPv1U) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { 48 hLen := gtpMinimumSizeInBytes 49 dLen := len(data) 50 if dLen < hLen { 51 return fmt.Errorf("GTP packet too small: %d bytes", dLen) 52 } 53 g.Version = (data[0] >> 5) & 0x07 54 g.ProtocolType = (data[0] >> 4) & 0x01 55 g.Reserved = (data[0] >> 3) & 0x01 56 g.SequenceNumberFlag = ((data[0] >> 1) & 0x01) == 1 57 g.NPDUFlag = (data[0] & 0x01) == 1 58 g.ExtensionHeaderFlag = ((data[0] >> 2) & 0x01) == 1 59 g.MessageType = data[1] 60 g.MessageLength = binary.BigEndian.Uint16(data[2:4]) 61 pLen := 8 + g.MessageLength 62 if uint16(dLen) < pLen { 63 return fmt.Errorf("GTP packet too small: %d bytes", dLen) 64 } 65 // Field used to multiplex different connections in the same GTP tunnel. 66 g.TEID = binary.BigEndian.Uint32(data[4:8]) 67 cIndex := uint16(hLen) 68 if g.SequenceNumberFlag || g.NPDUFlag || g.ExtensionHeaderFlag { 69 hLen += 4 70 cIndex += 4 71 if dLen < hLen { 72 return fmt.Errorf("GTP packet too small: %d bytes", dLen) 73 } 74 if g.SequenceNumberFlag { 75 g.SequenceNumber = binary.BigEndian.Uint16(data[8:10]) 76 } 77 if g.NPDUFlag { 78 g.NPDU = data[10] 79 } 80 if g.ExtensionHeaderFlag { 81 extensionFlag := true 82 for extensionFlag { 83 extensionType := uint8(data[cIndex-1]) 84 extensionLength := uint(data[cIndex]) 85 if extensionLength == 0 { 86 return fmt.Errorf("GTP packet with invalid extension header") 87 } 88 // extensionLength is in 4-octet units 89 lIndex := cIndex + (uint16(extensionLength) * 4) 90 if uint16(dLen) < lIndex { 91 return fmt.Errorf("GTP packet with small extension header: %d bytes", dLen) 92 } 93 content := data[cIndex+1 : lIndex-1] 94 eh := GTPExtensionHeader{Type: extensionType, Content: content} 95 g.GTPExtensionHeaders = append(g.GTPExtensionHeaders, eh) 96 cIndex = lIndex 97 // Check if coming bytes are from an extension header 98 extensionFlag = data[cIndex-1] != 0 99 100 } 101 } 102 } 103 g.BaseLayer = BaseLayer{Contents: data[:cIndex], Payload: data[cIndex:]} 104 return nil 105 106 } 107 108 // SerializeTo writes the serialized form of this layer into the 109 // SerializationBuffer, implementing gopacket.SerializableLayer. 110 // See the docs for gopacket.SerializableLayer for more info. 111 func (g *GTPv1U) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error { 112 data, err := b.PrependBytes(gtpMinimumSizeInBytes) 113 if err != nil { 114 return err 115 } 116 data[0] |= (g.Version << 5) 117 data[0] |= (1 << 4) 118 if len(g.GTPExtensionHeaders) > 0 { 119 data[0] |= 0x04 120 g.ExtensionHeaderFlag = true 121 } 122 if g.SequenceNumberFlag { 123 data[0] |= 0x02 124 } 125 if g.NPDUFlag { 126 data[0] |= 0x01 127 } 128 data[1] = g.MessageType 129 binary.BigEndian.PutUint16(data[2:4], g.MessageLength) 130 binary.BigEndian.PutUint32(data[4:8], g.TEID) 131 if g.ExtensionHeaderFlag || g.SequenceNumberFlag || g.NPDUFlag { 132 data, err := b.AppendBytes(4) 133 if err != nil { 134 return err 135 } 136 binary.BigEndian.PutUint16(data[:2], g.SequenceNumber) 137 data[2] = g.NPDU 138 for _, eh := range g.GTPExtensionHeaders { 139 data[len(data)-1] = eh.Type 140 lContent := len(eh.Content) 141 // extensionLength is in 4-octet units 142 extensionLength := (lContent + 2) / 4 143 // Get two extra byte for the next extension header type and length 144 data, err = b.AppendBytes(lContent + 2) 145 if err != nil { 146 return err 147 } 148 data[0] = byte(extensionLength) 149 copy(data[1:lContent+1], eh.Content) 150 } 151 } 152 return nil 153 154 } 155 156 // CanDecode returns a set of layers that GTP objects can decode. 157 func (g *GTPv1U) CanDecode() gopacket.LayerClass { 158 return LayerTypeGTPv1U 159 } 160 161 // NextLayerType specifies the next layer that GoPacket should attempt to 162 func (g *GTPv1U) NextLayerType() gopacket.LayerType { 163 if len(g.LayerPayload()) == 0 { 164 return gopacket.LayerTypeZero 165 } 166 version := uint8(g.LayerPayload()[0]) >> 4 167 if version == 4 { 168 return LayerTypeIPv4 169 } else if version == 6 { 170 return LayerTypeIPv6 171 } else { 172 return LayerTypePPP 173 } 174 } 175 176 func decodeGTPv1u(data []byte, p gopacket.PacketBuilder) error { 177 gtp := >Pv1U{} 178 err := gtp.DecodeFromBytes(data, p) 179 if err != nil { 180 return err 181 } 182 p.AddLayer(gtp) 183 return p.NextDecoder(gtp.NextLayerType()) 184 }