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 := &GTPv1U{}
   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  }