github.com/contiv/libOpenflow@v0.0.0-20210609050114-d967b14cc688/protocol/ipv6.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  const (
    12  	Type_HBH      = 0x0
    13  	Type_Routing  = 0x2b
    14  	Type_Fragment = 0x2c
    15  )
    16  
    17  type IPv6 struct {
    18  	Version        uint8 //4-bits
    19  	TrafficClass   uint8
    20  	FlowLabel      uint32 //20-bits
    21  	Length         uint16
    22  	NextHeader     uint8
    23  	HopLimit       uint8
    24  	NWSrc          net.IP
    25  	NWDst          net.IP
    26  	HbhHeader      *HopByHopHeader
    27  	RoutingHeader  *RoutingHeader
    28  	FragmentHeader *FragmentHeader
    29  	Data           util.Message
    30  }
    31  
    32  func (i *IPv6) Len() (n uint16) {
    33  	length := uint16(40)
    34  	if i.HbhHeader != nil {
    35  		length += i.HbhHeader.Len()
    36  	}
    37  	if i.RoutingHeader != nil {
    38  		length += i.RoutingHeader.Len()
    39  	}
    40  	if i.FragmentHeader != nil {
    41  		length += i.FragmentHeader.Len()
    42  	}
    43  	length += i.Data.Len()
    44  	return length
    45  }
    46  
    47  func (i *IPv6) MarshalBinary() (data []byte, err error) {
    48  	data = make([]byte, int(i.Len()))
    49  	b := make([]byte, 0)
    50  	n := 0
    51  
    52  	ihl := (i.Version << 4) | (i.TrafficClass>>4)&0x0f
    53  	data[n] = ihl
    54  	n += 1
    55  	data[n] = (i.TrafficClass<<4)&0xf0 | uint8(i.FlowLabel>>16)
    56  	n += 1
    57  	binary.BigEndian.PutUint16(data[n:], uint16(i.FlowLabel))
    58  	n += 2
    59  	binary.BigEndian.PutUint16(data[n:], i.Length)
    60  	n += 2
    61  	data[n] = i.NextHeader
    62  	n += 1
    63  	data[n] = i.HopLimit
    64  	n += 1
    65  	copy(data[n:], i.NWSrc)
    66  	n += 16
    67  	copy(data[n:], i.NWDst)
    68  	n += 16
    69  
    70  	checkExtHeader := true
    71  	nxtHeader := i.NextHeader
    72  	for checkExtHeader {
    73  		var err error
    74  		var hBytes []byte
    75  		switch nxtHeader {
    76  		case Type_HBH:
    77  			checkExtHeader = true
    78  			nxtHeader = i.HbhHeader.NextHeader
    79  			hBytes, err = i.HbhHeader.MarshalBinary()
    80  		case Type_Routing:
    81  			checkExtHeader = true
    82  			nxtHeader = i.RoutingHeader.NextHeader
    83  			hBytes, err = i.RoutingHeader.MarshalBinary()
    84  		case Type_Fragment:
    85  			checkExtHeader = true
    86  			nxtHeader = i.FragmentHeader.NextHeader
    87  			hBytes, err = i.FragmentHeader.MarshalBinary()
    88  		default:
    89  			checkExtHeader = false
    90  			break
    91  		}
    92  		if err != nil {
    93  			return nil, err
    94  		}
    95  		copy(data[n:], hBytes)
    96  		n += len(hBytes)
    97  	}
    98  
    99  	if i.Data != nil {
   100  		b, err = i.Data.MarshalBinary()
   101  		if err != nil {
   102  			return
   103  		}
   104  		copy(data[n:], b)
   105  		n += len(b)
   106  	}
   107  	return
   108  }
   109  
   110  func (i *IPv6) UnmarshalBinary(data []byte) error {
   111  	if len(data) < 40 {
   112  		return errors.New("The []byte is too short to unmarshal a full IPv6 message.")
   113  	}
   114  	n := 0
   115  
   116  	var ihl uint8
   117  	ihl = data[n]
   118  	i.Version = ihl >> 4
   119  	tcLeft := (ihl & 0x0f) << 4
   120  	n += 1
   121  	tc := data[n]
   122  	i.TrafficClass = tcLeft | (tc >> 4)
   123  	n += 1
   124  	i.FlowLabel = binary.BigEndian.Uint32(data[0:4]) & 0x000FFFFF
   125  	n += 2
   126  	i.Length = binary.BigEndian.Uint16(data[n:])
   127  	n += 2
   128  	i.NextHeader = data[n]
   129  	n += 1
   130  	i.HopLimit = data[n]
   131  	n += 1
   132  	i.NWSrc = data[n : n+16]
   133  	n += 16
   134  	i.NWDst = data[n : n+16]
   135  	n += 16
   136  
   137  	checkExtHeader := true
   138  	nxtHeader := i.NextHeader
   139  checkXHeader:
   140  	for checkExtHeader {
   141  		switch nxtHeader {
   142  		case Type_HBH:
   143  			checkExtHeader = true
   144  			i.HbhHeader = NewHopByHopHeader()
   145  			err := i.HbhHeader.UnmarshalBinary(data[n:])
   146  			if err != nil {
   147  				return err
   148  			}
   149  			nxtHeader = i.HbhHeader.NextHeader
   150  			n += int(i.HbhHeader.Len())
   151  		case Type_Routing:
   152  			checkExtHeader = true
   153  			i.RoutingHeader = NewRoutingHeader()
   154  			err := i.RoutingHeader.UnmarshalBinary(data[n:])
   155  			if err != nil {
   156  				return err
   157  			}
   158  			nxtHeader = i.RoutingHeader.NextHeader
   159  			n += int(i.RoutingHeader.Len())
   160  		case Type_Fragment:
   161  			checkExtHeader = true
   162  			i.FragmentHeader = NewFragmentHeader()
   163  			err := i.FragmentHeader.UnmarshalBinary(data[n:])
   164  			if err != nil {
   165  				return err
   166  			}
   167  			nxtHeader = i.FragmentHeader.NextHeader
   168  			n += int(i.FragmentHeader.Len())
   169  		case Type_IPv6ICMP:
   170  			i.Data = NewICMP()
   171  			break checkXHeader
   172  		case Type_UDP:
   173  			i.Data = NewUDP()
   174  			break checkXHeader
   175  		default:
   176  			i.Data = new(util.Buffer)
   177  			break checkXHeader
   178  		}
   179  	}
   180  	return i.Data.UnmarshalBinary(data[n:])
   181  }
   182  
   183  type Option struct {
   184  	Type   uint8
   185  	Length uint8
   186  	Data   []byte
   187  }
   188  
   189  func (o *Option) Len() uint16 {
   190  	return uint16(o.Length + 2)
   191  }
   192  
   193  func (o *Option) MarshalBinary() (data []byte, err error) {
   194  	data = make([]byte, int(o.Len()))
   195  	n := 0
   196  	data[n] = o.Type
   197  	n += 1
   198  	data[n] = o.Length
   199  	n += 1
   200  	copy(data[n:], o.Data)
   201  	return data, nil
   202  }
   203  
   204  func (o *Option) UnmarshalBinary(data []byte) error {
   205  	n := 0
   206  	o.Type = data[n]
   207  	n += 1
   208  	o.Length = data[n]
   209  	n += 1
   210  	if (len(data) - 2) < int(o.Length) {
   211  		return errors.New("The []byte is too short to unmarshal a full Option message.")
   212  	}
   213  	o.Data = make([]byte, o.Length)
   214  	copy(o.Data, data[n:n+int(o.Length)])
   215  	return nil
   216  }
   217  
   218  type HopByHopHeader struct {
   219  	NextHeader uint8
   220  	HEL        uint8
   221  	Options    []*Option
   222  }
   223  
   224  func (h *HopByHopHeader) Len() uint16 {
   225  	return 8 * uint16(h.HEL+1)
   226  }
   227  
   228  func (h *HopByHopHeader) MarshalBinary() (data []byte, err error) {
   229  	data = make([]byte, int(h.Len()))
   230  	n := 0
   231  	data[n] = h.NextHeader
   232  	n += 1
   233  	data[n] = h.HEL
   234  	n += 1
   235  	for _, o := range h.Options {
   236  		ob, err := o.MarshalBinary()
   237  		if err != nil {
   238  			return data, err
   239  		}
   240  		copy(data[n:], ob)
   241  		n += int(o.Len())
   242  	}
   243  	return data, nil
   244  }
   245  
   246  func (h *HopByHopHeader) UnmarshalBinary(data []byte) error {
   247  	n := 0
   248  	h.NextHeader = data[n]
   249  	n += 1
   250  	h.HEL = data[n]
   251  	if len(data) < 8*int(h.HEL+1) {
   252  		return errors.New("The []byte is too short to unmarshal a full HopByHopHeader message.")
   253  	}
   254  	n += 1
   255  	for n < int(h.Len()) {
   256  		o := new(Option)
   257  		err := o.UnmarshalBinary(data[n:])
   258  		if err != nil {
   259  			return err
   260  		}
   261  		n += int(o.Len())
   262  		h.Options = append(h.Options, o)
   263  	}
   264  	return nil
   265  }
   266  
   267  func NewHopByHopHeader() *HopByHopHeader {
   268  	return new(HopByHopHeader)
   269  }
   270  
   271  type RoutingHeader struct {
   272  	NextHeader   uint8
   273  	HEL          uint8
   274  	RoutingType  uint8
   275  	SegmentsLeft uint8
   276  	Data         *util.Buffer
   277  }
   278  
   279  func (h *RoutingHeader) Len() uint16 {
   280  	return 8 * uint16(h.HEL+1)
   281  }
   282  
   283  func (h *RoutingHeader) MarshalBinary() (data []byte, err error) {
   284  	data = make([]byte, int(h.Len()))
   285  	n := 0
   286  	data[n] = h.NextHeader
   287  	n += 1
   288  	data[n] = h.HEL
   289  	n += 1
   290  	data[n] = h.RoutingType
   291  	n += 1
   292  	data[n] = h.SegmentsLeft
   293  	n += 1
   294  	copy(data[n:], h.Data.Bytes())
   295  	return data, nil
   296  }
   297  
   298  func (h *RoutingHeader) UnmarshalBinary(data []byte) error {
   299  	n := 0
   300  	h.NextHeader = data[n]
   301  	n += 1
   302  	h.HEL = data[n]
   303  	if len(data) < 8*int(h.HEL+1) {
   304  		return errors.New("The []byte is too short to unmarshal a full RoutingHeader message.")
   305  	}
   306  	n += 1
   307  	h.RoutingType = data[n]
   308  	n += 1
   309  	h.SegmentsLeft = data[n]
   310  	n += 1
   311  	h.Data = new(util.Buffer)
   312  	err := h.Data.UnmarshalBinary(data[n:h.Len()])
   313  	if err != nil {
   314  		return err
   315  	}
   316  	return nil
   317  }
   318  
   319  func NewRoutingHeader() *RoutingHeader {
   320  	return new(RoutingHeader)
   321  }
   322  
   323  type FragmentHeader struct {
   324  	NextHeader     uint8
   325  	Reserved       uint8
   326  	FragmentOffset uint16
   327  	MoreFragments  bool
   328  	Identification uint32
   329  }
   330  
   331  func (h *FragmentHeader) Len() uint16 {
   332  	return uint16(8)
   333  }
   334  
   335  func (h *FragmentHeader) MarshalBinary() (data []byte, err error) {
   336  	data = make([]byte, int(h.Len()))
   337  	n := 0
   338  	data[n] = h.NextHeader
   339  	n += 1
   340  	data[n] = h.Reserved
   341  	n += 1
   342  	fragment := h.FragmentOffset << 3
   343  	if h.MoreFragments {
   344  		fragment |= uint16(1)
   345  	}
   346  	binary.BigEndian.PutUint16(data[n:], fragment)
   347  	n += 2
   348  	binary.BigEndian.PutUint32(data[n:], h.Identification)
   349  	return data, nil
   350  }
   351  
   352  func (h *FragmentHeader) UnmarshalBinary(data []byte) error {
   353  	if len(data) < int(h.Len()) {
   354  		return errors.New("The []byte is too short to unmarshal a full FragmentHeader message.")
   355  	}
   356  	n := 0
   357  	h.NextHeader = data[n]
   358  	n += 1
   359  	h.Reserved = data[n]
   360  	n += 1
   361  	fragment := binary.BigEndian.Uint16(data[n:])
   362  	n += 2
   363  	h.FragmentOffset = fragment >> 3
   364  	h.MoreFragments = (fragment & uint16(1)) == uint16(1)
   365  	h.Identification = binary.BigEndian.Uint32(data[n:])
   366  	n += 4
   367  	return nil
   368  }
   369  
   370  func NewFragmentHeader() *FragmentHeader {
   371  	return new(FragmentHeader)
   372  }