コード例 #1
0
ファイル: sctp.go プロジェクト: npe9/minimega
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPData) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	length := 16 + len(sc.PayloadData)
	bytes, err := b.PrependBytes(roundUpToNearest4(length))
	if err != nil {
		return err
	}
	bytes[0] = uint8(sc.Type)
	flags := uint8(0)
	if sc.Unordered {
		flags |= 0x4
	}
	if sc.BeginFragment {
		flags |= 0x2
	}
	if sc.EndFragment {
		flags |= 0x1
	}
	bytes[1] = flags
	binary.BigEndian.PutUint16(bytes[2:4], uint16(length))
	binary.BigEndian.PutUint32(bytes[4:8], sc.TSN)
	binary.BigEndian.PutUint16(bytes[8:10], sc.StreamId)
	binary.BigEndian.PutUint16(bytes[10:12], sc.StreamSequence)
	binary.BigEndian.PutUint32(bytes[12:16], sc.PayloadProtocol)
	copy(bytes[16:], sc.PayloadData)
	return nil
}
コード例 #2
0
ファイル: arp.go プロジェクト: npe9/minimega
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (arp *ARP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	size := 8 + len(arp.SourceHwAddress) + len(arp.SourceProtAddress) + len(arp.DstHwAddress) + len(arp.DstProtAddress)
	bytes, err := b.PrependBytes(size)
	if err != nil {
		return err
	}
	if opts.FixLengths {
		if len(arp.SourceHwAddress) != len(arp.DstHwAddress) {
			return fmt.Errorf("mismatched hardware address sizes")
		}
		arp.HwAddressSize = uint8(len(arp.SourceHwAddress))
		if len(arp.SourceProtAddress) != len(arp.DstProtAddress) {
			return fmt.Errorf("mismatched prot address sizes")
		}
		arp.ProtAddressSize = uint8(len(arp.SourceProtAddress))
	}
	binary.BigEndian.PutUint16(bytes, uint16(arp.AddrType))
	binary.BigEndian.PutUint16(bytes[2:], uint16(arp.Protocol))
	bytes[4] = arp.HwAddressSize
	bytes[5] = arp.ProtAddressSize
	binary.BigEndian.PutUint16(bytes[6:], arp.Operation)
	start := 8
	for _, addr := range [][]byte{
		arp.SourceHwAddress,
		arp.SourceProtAddress,
		arp.DstHwAddress,
		arp.DstProtAddress,
	} {
		copy(bytes[start:], addr)
		start += len(addr)
	}
	return nil
}
コード例 #3
0
ファイル: ip6.go プロジェクト: npe9/minimega
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (ip6 *IPv6) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	payload := b.Bytes()
	if ip6.HopByHop != nil {
		return fmt.Errorf("unable to serialize hopbyhop for now")
	}
	bytes, err := b.PrependBytes(40)
	if err != nil {
		return err
	}
	bytes[0] = (ip6.Version << 4) | (ip6.TrafficClass >> 4)
	bytes[1] = (ip6.TrafficClass << 4) | uint8(ip6.FlowLabel>>16)
	binary.BigEndian.PutUint16(bytes[2:], uint16(ip6.FlowLabel))
	if opts.FixLengths {
		ip6.Length = uint16(len(payload))
	}
	binary.BigEndian.PutUint16(bytes[4:], ip6.Length)
	bytes[6] = byte(ip6.NextHeader)
	bytes[7] = byte(ip6.HopLimit)
	if len(ip6.SrcIP) != 16 {
		return fmt.Errorf("invalid src ip %v", ip6.SrcIP)
	}
	if len(ip6.DstIP) != 16 {
		return fmt.Errorf("invalid dst ip %v", ip6.DstIP)
	}
	copy(bytes[8:], ip6.SrcIP)
	copy(bytes[24:], ip6.DstIP)
	return nil
}
コード例 #4
0
ファイル: sctp.go プロジェクト: npe9/minimega
// SerializeTo is for gopacket.SerializableLayer.
func (s SCTPUnknownChunkType) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	bytes, err := b.PrependBytes(s.ActualLength)
	if err != nil {
		return err
	}
	copy(bytes, s.bytes)
	return nil
}
コード例 #5
0
ファイル: sctp.go プロジェクト: npe9/minimega
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPEmptyLayer) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	bytes, err := b.PrependBytes(4)
	if err != nil {
		return err
	}
	bytes[0] = uint8(sc.Type)
	bytes[1] = sc.Flags
	binary.BigEndian.PutUint16(bytes[2:4], 4)
	return nil
}
コード例 #6
0
ファイル: sctp.go プロジェクト: npe9/minimega
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPShutdown) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	bytes, err := b.PrependBytes(8)
	if err != nil {
		return err
	}
	bytes[0] = uint8(sc.Type)
	bytes[1] = sc.Flags
	binary.BigEndian.PutUint16(bytes[2:4], 8)
	binary.BigEndian.PutUint32(bytes[4:8], sc.CumulativeTSNAck)
	return nil
}
コード例 #7
0
ファイル: tcp.go プロジェクト: npe9/minimega
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (t *TCP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	var optionLength int
	for _, o := range t.Options {
		switch o.OptionType {
		case 0, 1:
			optionLength += 1
		default:
			optionLength += 2 + len(o.OptionData)
		}
	}
	if opts.FixLengths {
		t.Padding = lotsOfZeros[:optionLength%4]
		t.DataOffset = uint8((len(t.Padding) + optionLength + 20) / 4)
	}
	bytes, err := b.PrependBytes(20 + optionLength + len(t.Padding))
	if err != nil {
		return err
	}
	binary.BigEndian.PutUint16(bytes, uint16(t.SrcPort))
	binary.BigEndian.PutUint16(bytes[2:], uint16(t.DstPort))
	binary.BigEndian.PutUint32(bytes[4:], t.Seq)
	binary.BigEndian.PutUint32(bytes[8:], t.Ack)
	binary.BigEndian.PutUint16(bytes[12:], t.flagsAndOffset())
	binary.BigEndian.PutUint16(bytes[14:], t.Window)
	binary.BigEndian.PutUint16(bytes[18:], t.Urgent)
	start := 20
	for _, o := range t.Options {
		bytes[start] = o.OptionType
		switch o.OptionType {
		case 0, 1:
			start++
		default:
			if opts.FixLengths {
				o.OptionLength = uint8(len(o.OptionData) + 2)
			}
			bytes[start+1] = o.OptionLength
			copy(bytes[start+2:start+len(o.OptionData)+2], o.OptionData)
			start += int(o.OptionLength)
		}
	}
	copy(bytes[start:], t.Padding)
	if opts.ComputeChecksums {
		// zero out checksum bytes in current serialization.
		bytes[16] = 0
		bytes[17] = 0
		csum, err := t.computeChecksum(b.Bytes())
		if err != nil {
			return err
		}
		t.Checksum = csum
	}
	binary.BigEndian.PutUint16(bytes[16:], t.Checksum)
	return nil
}
コード例 #8
0
ファイル: dot11.go プロジェクト: npe9/minimega
func (m Dot11InformationElement) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	length := len(m.Info) + len(m.OUI)
	if buf, err := b.PrependBytes(2 + length); err != nil {
		return err
	} else {
		buf[0] = uint8(m.ID)
		buf[1] = uint8(length)
		copy(buf[2:], m.OUI)
		copy(buf[2+len(m.OUI):], m.Info)
	}
	return nil
}
コード例 #9
0
ファイル: sctp.go プロジェクト: npe9/minimega
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPCookieEcho) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	length := 4 + len(sc.Cookie)
	bytes, err := b.PrependBytes(roundUpToNearest4(length))
	if err != nil {
		return err
	}
	bytes[0] = uint8(sc.Type)
	bytes[1] = sc.Flags
	binary.BigEndian.PutUint16(bytes[2:4], uint16(length))
	copy(bytes[4:], sc.Cookie)
	return nil
}
コード例 #10
0
ファイル: ip6.go プロジェクト: npe9/minimega
func (h *ipv6HeaderTLVOption) serializeTo(b gopacket.SerializeBuffer, fixLengths bool) (int, error) {
	if fixLengths {
		h.OptionLength = uint8(len(h.OptionData))
	}
	length := int(h.OptionLength) + 2
	data, err := b.PrependBytes(length)
	if err != nil {
		return 0, err
	}
	data[0] = h.OptionType
	data[1] = h.OptionLength
	copy(data[2:], h.OptionData)
	return length, nil
}
コード例 #11
0
ファイル: mpls.go プロジェクト: npe9/minimega
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (m *MPLS) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	bytes, err := b.PrependBytes(4)
	if err != nil {
		return err
	}
	encoded := m.Label << 12
	encoded |= uint32(m.TrafficClass) << 9
	encoded |= uint32(m.TTL)
	if m.StackBottom {
		encoded |= 0x100
	}
	binary.BigEndian.PutUint32(bytes, encoded)
	return nil
}
コード例 #12
0
ファイル: pppoe.go プロジェクト: npe9/minimega
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (p *PPPoE) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	payload := b.Bytes()
	bytes, err := b.PrependBytes(6)
	if err != nil {
		return err
	}
	bytes[0] = (p.Version << 4) | p.Type
	bytes[1] = byte(p.Code)
	binary.BigEndian.PutUint16(bytes[2:], p.SessionId)
	if opts.FixLengths {
		p.Length = uint16(len(payload))
	}
	binary.BigEndian.PutUint16(bytes[4:], p.Length)
	return nil
}
コード例 #13
0
ファイル: dot1q.go プロジェクト: npe9/minimega
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (d *Dot1Q) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	bytes, err := b.PrependBytes(4)
	if err != nil {
		return err
	}
	if d.VLANIdentifier > 0xFFF {
		return fmt.Errorf("vlan identifier %v is too high", d.VLANIdentifier)
	}
	firstBytes := uint16(d.Priority)<<13 | d.VLANIdentifier
	if d.DropEligible {
		firstBytes |= 0x10
	}
	binary.BigEndian.PutUint16(bytes, firstBytes)
	binary.BigEndian.PutUint16(bytes[2:], uint16(d.Type))
	return nil
}
コード例 #14
0
ファイル: icmp4.go プロジェクト: npe9/minimega
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (i *ICMPv4) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	bytes, err := b.PrependBytes(8)
	if err != nil {
		return err
	}
	binary.BigEndian.PutUint16(bytes, uint16(i.TypeCode))
	binary.BigEndian.PutUint16(bytes[4:], i.Id)
	binary.BigEndian.PutUint16(bytes[6:], i.Seq)
	if opts.ComputeChecksums {
		bytes[2] = 0
		bytes[3] = 0
		i.Checksum = tcpipChecksum(b.Bytes(), 0)
	}
	binary.BigEndian.PutUint16(bytes[2:], i.Checksum)
	return nil
}
コード例 #15
0
ファイル: sctp.go プロジェクト: npe9/minimega
// SerializeTo is for gopacket.SerializableLayer.
func (s SCTP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	bytes, err := b.PrependBytes(12)
	if err != nil {
		return err
	}
	binary.BigEndian.PutUint16(bytes[0:2], uint16(s.SrcPort))
	binary.BigEndian.PutUint16(bytes[2:4], uint16(s.DstPort))
	binary.BigEndian.PutUint32(bytes[4:8], s.VerificationTag)
	if opts.ComputeChecksums {
		// Note:  MakeTable(Castagnoli) actually only creates the table once, then
		// passes back a singleton on every other call, so this shouldn't cause
		// excessive memory allocation.
		binary.LittleEndian.PutUint32(bytes[8:12], crc32.Checksum(b.Bytes(), crc32.MakeTable(crc32.Castagnoli)))
	}
	return nil
}
コード例 #16
0
ファイル: sctp.go プロジェクト: npe9/minimega
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPError) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	var payload []byte
	for _, param := range sc.Parameters {
		payload = append(payload, SCTPParameter(param).Bytes()...)
	}
	length := 4 + len(payload)

	bytes, err := b.PrependBytes(roundUpToNearest4(length))
	if err != nil {
		return err
	}
	bytes[0] = uint8(sc.Type)
	bytes[1] = sc.Flags
	binary.BigEndian.PutUint16(bytes[2:4], uint16(length))
	copy(bytes[4:], payload)
	return nil
}
コード例 #17
0
ファイル: ip4.go プロジェクト: npe9/minimega
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
func (ip *IPv4) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	if len(ip.Options) > 0 {
		return fmt.Errorf("cannot currently serialize IPv4 options")
	}
	bytes, err := b.PrependBytes(20)
	if err != nil {
		return err
	}
	if opts.FixLengths {
		ip.IHL = 5 // Fix when we add support for options.
		ip.Length = uint16(len(b.Bytes()))
	}
	bytes[0] = (ip.Version << 4) | ip.IHL
	bytes[1] = ip.TOS
	binary.BigEndian.PutUint16(bytes[2:], ip.Length)
	binary.BigEndian.PutUint16(bytes[4:], ip.Id)
	binary.BigEndian.PutUint16(bytes[6:], ip.flagsfrags())
	bytes[8] = ip.TTL
	bytes[9] = byte(ip.Protocol)
	if len(ip.SrcIP) != 4 {
		return fmt.Errorf("invalid src IP %v", ip.SrcIP)
	}
	if len(ip.DstIP) != 4 {
		return fmt.Errorf("invalid dst IP %v", ip.DstIP)
	}
	copy(bytes[12:16], ip.SrcIP)
	copy(bytes[16:20], ip.DstIP)
	if opts.ComputeChecksums {
		// Clear checksum bytes
		bytes[10] = 0
		bytes[11] = 0
		// Compute checksum
		var csum uint32
		for i := 0; i < len(bytes); i += 2 {
			csum += uint32(bytes[i]) << 8
			csum += uint32(bytes[i+1])
		}
		ip.Checksum = ^uint16((csum >> 16) + csum)
	}
	binary.BigEndian.PutUint16(bytes[10:], ip.Checksum)
	return nil
}
コード例 #18
0
ファイル: ip6.go プロジェクト: npe9/minimega
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (i *IPv6Destination) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	optionLength := 0
	for _, opt := range i.Options {
		l, err := opt.serializeTo(b, opts.FixLengths)
		if err != nil {
			return err
		}
		optionLength += l
	}
	bytes, err := b.PrependBytes(2)
	if err != nil {
		return err
	}
	bytes[0] = uint8(i.NextHeader)
	if opts.FixLengths {
		i.HeaderLength = uint8((optionLength + 2) / 8)
	}
	bytes[1] = i.HeaderLength
	return nil
}
コード例 #19
0
ファイル: eap.go プロジェクト: npe9/minimega
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (e *EAP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	if opts.FixLengths {
		e.Length = uint16(len(e.TypeData) + 1)
	}
	size := len(e.TypeData) + 4
	if size > 4 {
		size++
	}
	bytes, err := b.PrependBytes(size)
	if err != nil {
		return err
	}
	bytes[0] = byte(e.Code)
	bytes[1] = e.Id
	binary.BigEndian.PutUint16(bytes[2:], e.Length)
	if size > 4 {
		bytes[4] = byte(e.Type)
		copy(bytes[5:], e.TypeData)
	}
	return nil
}
コード例 #20
0
ファイル: udp.go プロジェクト: npe9/minimega
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (u *UDP) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	payload := b.Bytes()
	bytes, err := b.PrependBytes(8)
	if err != nil {
		return err
	}
	binary.BigEndian.PutUint16(bytes, uint16(u.SrcPort))
	binary.BigEndian.PutUint16(bytes[2:], uint16(u.DstPort))
	if opts.FixLengths {
		u.Length = uint16(len(payload)) + 8
	}
	binary.BigEndian.PutUint16(bytes[4:], u.Length)
	if opts.ComputeChecksums {
		// zero out checksum bytes
		bytes[6] = 0
		bytes[7] = 0
		csum, err := u.computeChecksum(b.Bytes())
		if err != nil {
			return err
		}
		u.Checksum = csum
	}
	binary.BigEndian.PutUint16(bytes[6:], u.Checksum)
	return nil
}
コード例 #21
0
ファイル: sctp.go プロジェクト: npe9/minimega
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPInit) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	var payload []byte
	for _, param := range sc.Parameters {
		payload = append(payload, SCTPParameter(param).Bytes()...)
	}
	length := 20 + len(payload)

	bytes, err := b.PrependBytes(roundUpToNearest4(length))
	if err != nil {
		return err
	}
	bytes[0] = uint8(sc.Type)
	bytes[1] = sc.Flags
	binary.BigEndian.PutUint16(bytes[2:4], uint16(length))
	binary.BigEndian.PutUint32(bytes[4:8], sc.InitiateTag)
	binary.BigEndian.PutUint32(bytes[8:12], sc.AdvertisedReceiverWindowCredit)
	binary.BigEndian.PutUint16(bytes[12:14], sc.OutboundStreams)
	binary.BigEndian.PutUint16(bytes[14:16], sc.InboundStreams)
	binary.BigEndian.PutUint32(bytes[16:20], sc.InitialTSN)
	copy(bytes[20:], payload)
	return nil
}
コード例 #22
0
ファイル: sctp.go プロジェクト: npe9/minimega
// SerializeTo is for gopacket.SerializableLayer.
func (sc SCTPSack) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	length := 16 + 2*len(sc.GapACKs) + 4*len(sc.DuplicateTSNs)
	bytes, err := b.PrependBytes(roundUpToNearest4(length))
	if err != nil {
		return err
	}
	bytes[0] = uint8(sc.Type)
	bytes[1] = sc.Flags
	binary.BigEndian.PutUint16(bytes[2:4], uint16(length))
	binary.BigEndian.PutUint32(bytes[4:8], sc.CumulativeTSNAck)
	binary.BigEndian.PutUint32(bytes[8:12], sc.AdvertisedReceiverWindowCredit)
	binary.BigEndian.PutUint16(bytes[12:14], uint16(len(sc.GapACKs)))
	binary.BigEndian.PutUint16(bytes[14:16], uint16(len(sc.DuplicateTSNs)))
	for i, v := range sc.GapACKs {
		binary.BigEndian.PutUint16(bytes[16+i*2:], v)
	}
	offset := 16 + 2*len(sc.GapACKs)
	for i, v := range sc.DuplicateTSNs {
		binary.BigEndian.PutUint32(bytes[offset+i*4:], v)
	}
	return nil
}
コード例 #23
0
ファイル: icmp6.go プロジェクト: npe9/minimega
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (i *ICMPv6) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	if i.TypeBytes == nil {
		i.TypeBytes = lotsOfZeros[:4]
	} else if len(i.TypeBytes) != 4 {
		return fmt.Errorf("invalid type bytes for ICMPv6 packet: %v", i.TypeBytes)
	}
	bytes, err := b.PrependBytes(8)
	if err != nil {
		return err
	}
	binary.BigEndian.PutUint16(bytes, uint16(i.TypeCode))
	copy(bytes[4:8], i.TypeBytes)
	if opts.ComputeChecksums {
		bytes[2] = 0
		bytes[3] = 0
		csum, err := i.computeChecksum(b.Bytes())
		if err != nil {
			return err
		}
		i.Checksum = csum
	}
	binary.BigEndian.PutUint16(bytes[2:], i.Checksum)
	return nil
}
コード例 #24
0
ファイル: ethernet.go プロジェクト: npe9/minimega
// SerializeTo writes the serialized form of this layer into the
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (eth *Ethernet) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
	if len(eth.DstMAC) != 6 {
		return fmt.Errorf("invalid dst MAC: %v", eth.DstMAC)
	}
	if len(eth.SrcMAC) != 6 {
		return fmt.Errorf("invalid src MAC: %v", eth.SrcMAC)
	}
	payload := b.Bytes()
	bytes, err := b.PrependBytes(14)
	if err != nil {
		return err
	}
	copy(bytes, eth.DstMAC)
	copy(bytes[6:], eth.SrcMAC)
	if eth.Length != 0 || eth.EthernetType == EthernetTypeLLC {
		if opts.FixLengths {
			eth.Length = uint16(len(payload))
		}
		if eth.EthernetType != EthernetTypeLLC {
			return fmt.Errorf("ethernet type %v not compatible with length value %v", eth.EthernetType, eth.Length)
		} else if eth.Length > 0x0600 {
			return fmt.Errorf("invalid ethernet length %v", eth.Length)
		}
		binary.BigEndian.PutUint16(bytes[12:], eth.Length)
	} else {
		binary.BigEndian.PutUint16(bytes[12:], uint16(eth.EthernetType))
	}
	length := len(b.Bytes())
	if length < 60 {
		// Pad out to 60 bytes.
		padding, err := b.AppendBytes(60 - length)
		if err != nil {
			return err
		}
		copy(padding, lotsOfZeros[:])
	}
	return nil
}