frame.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. package ethernet
  2. import "net"
  3. // Frame represents an ethernet frame. The length of the underlying slice of a
  4. // Frame should always reflect the ethernet frame length.
  5. type Frame []byte
  6. // Tagging is a type used to indicate whether/how a frame is tagged. The value
  7. // is number of bytes taken by tagging.
  8. type Tagging byte
  9. // Const values for different taggings
  10. const (
  11. NotTagged Tagging = 0
  12. Tagged Tagging = 4
  13. DoubleTagged Tagging = 8
  14. )
  15. // Destination returns the destination address field of the frame. The address
  16. // references a slice on the frame.
  17. //
  18. // It is not safe to use this method if f is nil or an invalid ethernet frame.
  19. func (f Frame) Destination() net.HardwareAddr {
  20. return net.HardwareAddr(f[:6:6])
  21. }
  22. // Source returns the source address field of the frame. The address references
  23. // a slice on the frame.
  24. //
  25. // It is not safe to use this method if f is nil or an invalid ethernet frame.
  26. func (f Frame) Source() net.HardwareAddr {
  27. return net.HardwareAddr(f[6:12:12])
  28. }
  29. // Tagging returns whether/how the frame has 802.1Q tag(s).
  30. //
  31. // It is not safe to use this method if f is nil or an invalid ethernet frame.
  32. func (f Frame) Tagging() Tagging {
  33. if f[12] == 0x81 && f[13] == 0x00 {
  34. return Tagged
  35. } else if f[12] == 0x88 && f[13] == 0xa8 {
  36. return DoubleTagged
  37. }
  38. return NotTagged
  39. }
  40. // Tag returns a slice holding the tag part of the frame, if any. Note that
  41. // this includes the Tag Protocol Identifier (TPID), e.g. 0x8100 or 0x88a8.
  42. // Upper layer should use the returned slice for both reading and writing.
  43. //
  44. // It is not safe to use this method if f is nil or an invalid ethernet frame.
  45. func (f Frame) Tags() []byte {
  46. tagging := f.Tagging()
  47. return f[12 : 12+tagging : 12+tagging]
  48. }
  49. // Ethertype returns the ethertype field of the frame.
  50. //
  51. // It is not safe to use this method if f is nil or an invalid ethernet frame.
  52. func (f Frame) Ethertype() Ethertype {
  53. ethertypePos := 12 + f.Tagging()
  54. return Ethertype{f[ethertypePos], f[ethertypePos+1]}
  55. }
  56. // Payload returns a slice holding the payload part of the frame. Upper layer
  57. // should use the returned slice for both reading and writing purposes.
  58. //
  59. // It is not safe to use this method if f is nil or an invalid ethernet frame.
  60. func (f Frame) Payload() []byte {
  61. return f[12+f.Tagging()+2:]
  62. }
  63. // Resize re-slices (*f) so that len(*f) holds exactly payloadSize bytes of
  64. // payload. If cap(*f) is not large enough, a new slice is made and content
  65. // from old slice is copied to the new one.
  66. //
  67. // If len(*f) is less than 14 bytes, it is assumed to be not tagged.
  68. //
  69. // It is safe to call Resize on a pointer to a nil Frame.
  70. func (f *Frame) Resize(payloadSize int) {
  71. tagging := NotTagged
  72. if len(*f) > 6+6+2 {
  73. tagging = f.Tagging()
  74. }
  75. f.resize(6 + 6 + int(tagging) + 2 + payloadSize)
  76. }
  77. // Prepare prepares *f to be used, by filling in dst/src address, setting up
  78. // proper tagging and ethertype, and resizing it to proper length.
  79. //
  80. // It is safe to call Prepare on a pointer to a nil Frame or invalid Frame.
  81. func (f *Frame) Prepare(dst net.HardwareAddr, src net.HardwareAddr, tagging Tagging, ethertype Ethertype, payloadSize int) {
  82. f.resize(6 + 6 + int(tagging) + 2 + payloadSize)
  83. copy((*f)[0:6:6], dst)
  84. copy((*f)[6:12:12], src)
  85. if tagging == Tagged {
  86. (*f)[12] = 0x81
  87. (*f)[13] = 0x00
  88. } else if tagging == DoubleTagged {
  89. (*f)[12] = 0x88
  90. (*f)[13] = 0xa8
  91. }
  92. (*f)[12+tagging] = ethertype[0]
  93. (*f)[12+tagging+1] = ethertype[1]
  94. return
  95. }
  96. func (f *Frame) resize(length int) {
  97. if cap(*f) < length {
  98. old := *f
  99. *f = make(Frame, length, length)
  100. copy(*f, old)
  101. } else {
  102. *f = (*f)[:length]
  103. }
  104. }