code: func (f *Frame) read(b []byte) (int, error) {
  	// S-VLAN must also have accompanying C-VLAN.
  	if f.ServiceVLAN != nil && f.VLAN == nil {
  		return 0, ErrInvalidVLAN
  	}
  
  	copy(b[0:6], f.Destination)
  	copy(b[6:12], f.Source)
  
  	// Marshal each non-nil VLAN tag into bytes, inserting the appropriate
  	// EtherType/TPID before each, so devices know that one or more VLANs
  	// are present.
  	vlans := []struct {
  		vlan *VLAN
  		tpid EtherType
  	}{
  		{vlan: f.ServiceVLAN, tpid: EtherTypeServiceVLAN},
  		{vlan: f.VLAN, tpid: EtherTypeVLAN},
  	}
  
  	n := 12
  	for _, vt := range vlans {
  		if vt.vlan == nil {
  			continue
  		}
  
  		// Add VLAN EtherType and VLAN bytes.
  		binary.BigEndian.PutUint16(b[n:n+2], uint16(vt.tpid))
  		if _, err := vt.vlan.read(b[n+2 : n+4]); err != nil {
  			return 0, err
  		}
  		n += 4
  	}
  
  	// Marshal actual EtherType after any VLANs, copy payload into
  	// output bytes.
  	binary.BigEndian.PutUint16(b[n:n+2], uint16(f.EtherType))
  	copy(b[n+2:], f.Payload)
  
  	return len(b), nil
  }
docs: // read reads data from a Frame into b.  read is used to marshal a Frame
  // into binary form, but does not allocate on its own.