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 8package layers 9 10import ( 11 "encoding/binary" 12 "fmt" 13 "github.com/google/gopacket" 14) 15 16const gtpMinimumSizeInBytes int = 8 17 18// GTPExtensionHeader is used to carry extra data and enable future extensions of the GTP without the need to use another version number. 19type GTPExtensionHeader struct { 20 Type uint8 21 Content []byte 22} 23 24// GTPv1U protocol is used to exchange user data over GTP tunnels across the Sx interfaces. 25// Defined in https://portal.3gpp.org/desktopmodules/Specifications/SpecificationDetails.aspx?specificationId=1595 26type GTPv1U struct { 27 BaseLayer 28 Version uint8 29 ProtocolType uint8 30 Reserved uint8 31 ExtensionHeaderFlag bool 32 SequenceNumberFlag bool 33 NPDUFlag bool 34 MessageType uint8 35 MessageLength uint16 36 TEID uint32 37 SequenceNumber uint16 38 NPDU uint8 39 GTPExtensionHeaders []GTPExtensionHeader 40} 41 42// LayerType returns LayerTypeGTPV1U 43func (g *GTPv1U) LayerType() gopacket.LayerType { return LayerTypeGTPv1U } 44 45// DecodeFromBytes analyses a byte slice and attempts to decode it as a GTPv1U packet 46func (g *GTPv1U) DecodeFromBytes(data []byte, df gopacket.DecodeFeedback) error { 47 hLen := gtpMinimumSizeInBytes 48 dLen := len(data) 49 if dLen < hLen { 50 return fmt.Errorf("GTP packet too small: %d bytes", dLen) 51 } 52 g.Version = (data[0] >> 5) & 0x07 53 g.ProtocolType = (data[0] >> 4) & 0x01 54 g.Reserved = (data[0] >> 3) & 0x01 55 g.SequenceNumberFlag = ((data[0] >> 1) & 0x01) == 1 56 g.NPDUFlag = (data[0] & 0x01) == 1 57 g.ExtensionHeaderFlag = ((data[0] >> 2) & 0x01) == 1 58 g.MessageType = data[1] 59 g.MessageLength = binary.BigEndian.Uint16(data[2:4]) 60 pLen := 8 + g.MessageLength 61 if uint16(dLen) < pLen { 62 return fmt.Errorf("GTP packet too small: %d bytes", dLen) 63 } 64 // Field used to multiplex different connections in the same GTP tunnel. 65 g.TEID = binary.BigEndian.Uint32(data[4:8]) 66 cIndex := uint16(hLen) 67 if g.SequenceNumberFlag || g.NPDUFlag || g.ExtensionHeaderFlag { 68 hLen += 4 69 cIndex += 4 70 if dLen < hLen { 71 return fmt.Errorf("GTP packet too small: %d bytes", dLen) 72 } 73 if g.SequenceNumberFlag { 74 g.SequenceNumber = binary.BigEndian.Uint16(data[8:10]) 75 } 76 if g.NPDUFlag { 77 g.NPDU = data[10] 78 } 79 if g.ExtensionHeaderFlag { 80 extensionFlag := true 81 for extensionFlag { 82 extensionType := uint8(data[cIndex-1]) 83 extensionLength := uint(data[cIndex]) 84 if extensionLength == 0 { 85 return fmt.Errorf("GTP packet with invalid extension header") 86 } 87 // extensionLength is in 4-octet units 88 lIndex := cIndex + (uint16(extensionLength) * 4) 89 if uint16(dLen) < lIndex { 90 fmt.Println(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. 111func (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. 157func (g *GTPv1U) CanDecode() gopacket.LayerClass { 158 return LayerTypeGTPv1U 159} 160 161// NextLayerType specifies the next layer that GoPacket should attempt to 162func (g *GTPv1U) NextLayerType() gopacket.LayerType { 163 version := uint8(g.LayerPayload()[0]) >> 4 164 if version == 4 { 165 return LayerTypeIPv4 166 } else if version == 6 { 167 return LayerTypeIPv6 168 } else { 169 return LayerTypePPP 170 } 171} 172 173func decodeGTPv1u(data []byte, p gopacket.PacketBuilder) error { 174 gtp := >Pv1U{} 175 err := gtp.DecodeFromBytes(data, p) 176 if err != nil { 177 return err 178 } 179 p.AddLayer(gtp) 180 return p.NextDecoder(gtp.NextLayerType()) 181} 182