control_unix.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. // Copyright 2013 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build darwin dragonfly freebsd linux netbsd openbsd
  5. package ipv6
  6. import (
  7. "os"
  8. "syscall"
  9. )
  10. func setControlMessage(fd int, opt *rawOpt, cf ControlFlags, on bool) error {
  11. opt.Lock()
  12. defer opt.Unlock()
  13. if cf&FlagTrafficClass != 0 && sockOpts[ssoReceiveTrafficClass].name > 0 {
  14. if err := setInt(fd, &sockOpts[ssoReceiveTrafficClass], boolint(on)); err != nil {
  15. return err
  16. }
  17. if on {
  18. opt.set(FlagTrafficClass)
  19. } else {
  20. opt.clear(FlagTrafficClass)
  21. }
  22. }
  23. if cf&FlagHopLimit != 0 && sockOpts[ssoReceiveHopLimit].name > 0 {
  24. if err := setInt(fd, &sockOpts[ssoReceiveHopLimit], boolint(on)); err != nil {
  25. return err
  26. }
  27. if on {
  28. opt.set(FlagHopLimit)
  29. } else {
  30. opt.clear(FlagHopLimit)
  31. }
  32. }
  33. if cf&flagPacketInfo != 0 && sockOpts[ssoReceivePacketInfo].name > 0 {
  34. if err := setInt(fd, &sockOpts[ssoReceivePacketInfo], boolint(on)); err != nil {
  35. return err
  36. }
  37. if on {
  38. opt.set(cf & flagPacketInfo)
  39. } else {
  40. opt.clear(cf & flagPacketInfo)
  41. }
  42. }
  43. if cf&FlagPathMTU != 0 && sockOpts[ssoReceivePathMTU].name > 0 {
  44. if err := setInt(fd, &sockOpts[ssoReceivePathMTU], boolint(on)); err != nil {
  45. return err
  46. }
  47. if on {
  48. opt.set(FlagPathMTU)
  49. } else {
  50. opt.clear(FlagPathMTU)
  51. }
  52. }
  53. return nil
  54. }
  55. func newControlMessage(opt *rawOpt) (oob []byte) {
  56. opt.RLock()
  57. var l int
  58. if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 {
  59. l += syscall.CmsgSpace(ctlOpts[ctlTrafficClass].length)
  60. }
  61. if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 {
  62. l += syscall.CmsgSpace(ctlOpts[ctlHopLimit].length)
  63. }
  64. if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 {
  65. l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
  66. }
  67. if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 {
  68. l += syscall.CmsgSpace(ctlOpts[ctlPathMTU].length)
  69. }
  70. if l > 0 {
  71. oob = make([]byte, l)
  72. b := oob
  73. if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 {
  74. b = ctlOpts[ctlTrafficClass].marshal(b, nil)
  75. }
  76. if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 {
  77. b = ctlOpts[ctlHopLimit].marshal(b, nil)
  78. }
  79. if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 {
  80. b = ctlOpts[ctlPacketInfo].marshal(b, nil)
  81. }
  82. if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 {
  83. b = ctlOpts[ctlPathMTU].marshal(b, nil)
  84. }
  85. }
  86. opt.RUnlock()
  87. return
  88. }
  89. func parseControlMessage(b []byte) (*ControlMessage, error) {
  90. if len(b) == 0 {
  91. return nil, nil
  92. }
  93. cmsgs, err := syscall.ParseSocketControlMessage(b)
  94. if err != nil {
  95. return nil, os.NewSyscallError("parse socket control message", err)
  96. }
  97. cm := &ControlMessage{}
  98. for _, m := range cmsgs {
  99. if m.Header.Level != ianaProtocolIPv6 {
  100. continue
  101. }
  102. switch int(m.Header.Type) {
  103. case ctlOpts[ctlTrafficClass].name:
  104. ctlOpts[ctlTrafficClass].parse(cm, m.Data[:])
  105. case ctlOpts[ctlHopLimit].name:
  106. ctlOpts[ctlHopLimit].parse(cm, m.Data[:])
  107. case ctlOpts[ctlPacketInfo].name:
  108. ctlOpts[ctlPacketInfo].parse(cm, m.Data[:])
  109. case ctlOpts[ctlPathMTU].name:
  110. ctlOpts[ctlPathMTU].parse(cm, m.Data[:])
  111. }
  112. }
  113. return cm, nil
  114. }
  115. func marshalControlMessage(cm *ControlMessage) (oob []byte) {
  116. if cm == nil {
  117. return
  118. }
  119. var l int
  120. tclass := false
  121. if ctlOpts[ctlTrafficClass].name > 0 && cm.TrafficClass > 0 {
  122. tclass = true
  123. l += syscall.CmsgSpace(ctlOpts[ctlTrafficClass].length)
  124. }
  125. hoplimit := false
  126. if ctlOpts[ctlHopLimit].name > 0 && cm.HopLimit > 0 {
  127. hoplimit = true
  128. l += syscall.CmsgSpace(ctlOpts[ctlHopLimit].length)
  129. }
  130. pktinfo := false
  131. if ctlOpts[ctlPacketInfo].name > 0 && cm.Src.To16() != nil && cm.Src.To4() == nil || cm.IfIndex > 0 {
  132. pktinfo = true
  133. l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
  134. }
  135. nexthop := false
  136. if ctlOpts[ctlNextHop].name > 0 && cm.NextHop.To16() != nil && cm.NextHop.To4() == nil {
  137. nexthop = true
  138. l += syscall.CmsgSpace(ctlOpts[ctlNextHop].length)
  139. }
  140. if l > 0 {
  141. oob = make([]byte, l)
  142. b := oob
  143. if tclass {
  144. b = ctlOpts[ctlTrafficClass].marshal(b, cm)
  145. }
  146. if hoplimit {
  147. b = ctlOpts[ctlHopLimit].marshal(b, cm)
  148. }
  149. if pktinfo {
  150. b = ctlOpts[ctlPacketInfo].marshal(b, cm)
  151. }
  152. if nexthop {
  153. b = ctlOpts[ctlNextHop].marshal(b, cm)
  154. }
  155. }
  156. return
  157. }