123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- // Copyright 2013 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // +build darwin dragonfly freebsd linux netbsd openbsd solaris
- package ipv6
- import (
- "os"
- "syscall"
- "golang.org/x/net/internal/iana"
- )
- func setControlMessage(s uintptr, opt *rawOpt, cf ControlFlags, on bool) error {
- opt.Lock()
- defer opt.Unlock()
- if cf&FlagTrafficClass != 0 && sockOpts[ssoReceiveTrafficClass].name > 0 {
- if err := setInt(s, &sockOpts[ssoReceiveTrafficClass], boolint(on)); err != nil {
- return err
- }
- if on {
- opt.set(FlagTrafficClass)
- } else {
- opt.clear(FlagTrafficClass)
- }
- }
- if cf&FlagHopLimit != 0 && sockOpts[ssoReceiveHopLimit].name > 0 {
- if err := setInt(s, &sockOpts[ssoReceiveHopLimit], boolint(on)); err != nil {
- return err
- }
- if on {
- opt.set(FlagHopLimit)
- } else {
- opt.clear(FlagHopLimit)
- }
- }
- if cf&flagPacketInfo != 0 && sockOpts[ssoReceivePacketInfo].name > 0 {
- if err := setInt(s, &sockOpts[ssoReceivePacketInfo], boolint(on)); err != nil {
- return err
- }
- if on {
- opt.set(cf & flagPacketInfo)
- } else {
- opt.clear(cf & flagPacketInfo)
- }
- }
- if cf&FlagPathMTU != 0 && sockOpts[ssoReceivePathMTU].name > 0 {
- if err := setInt(s, &sockOpts[ssoReceivePathMTU], boolint(on)); err != nil {
- return err
- }
- if on {
- opt.set(FlagPathMTU)
- } else {
- opt.clear(FlagPathMTU)
- }
- }
- return nil
- }
- func newControlMessage(opt *rawOpt) (oob []byte) {
- opt.RLock()
- var l int
- if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 {
- l += syscall.CmsgSpace(ctlOpts[ctlTrafficClass].length)
- }
- if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 {
- l += syscall.CmsgSpace(ctlOpts[ctlHopLimit].length)
- }
- if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 {
- l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
- }
- if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 {
- l += syscall.CmsgSpace(ctlOpts[ctlPathMTU].length)
- }
- if l > 0 {
- oob = make([]byte, l)
- }
- opt.RUnlock()
- return
- }
- func parseControlMessage(b []byte) (*ControlMessage, error) {
- if len(b) == 0 {
- return nil, nil
- }
- cmsgs, err := syscall.ParseSocketControlMessage(b)
- if err != nil {
- return nil, os.NewSyscallError("parse socket control message", err)
- }
- cm := &ControlMessage{}
- for _, m := range cmsgs {
- if m.Header.Level != iana.ProtocolIPv6 {
- continue
- }
- switch int(m.Header.Type) {
- case ctlOpts[ctlTrafficClass].name:
- ctlOpts[ctlTrafficClass].parse(cm, m.Data[:])
- case ctlOpts[ctlHopLimit].name:
- ctlOpts[ctlHopLimit].parse(cm, m.Data[:])
- case ctlOpts[ctlPacketInfo].name:
- ctlOpts[ctlPacketInfo].parse(cm, m.Data[:])
- case ctlOpts[ctlPathMTU].name:
- ctlOpts[ctlPathMTU].parse(cm, m.Data[:])
- }
- }
- return cm, nil
- }
- func marshalControlMessage(cm *ControlMessage) (oob []byte) {
- if cm == nil {
- return
- }
- var l int
- tclass := false
- if ctlOpts[ctlTrafficClass].name > 0 && cm.TrafficClass > 0 {
- tclass = true
- l += syscall.CmsgSpace(ctlOpts[ctlTrafficClass].length)
- }
- hoplimit := false
- if ctlOpts[ctlHopLimit].name > 0 && cm.HopLimit > 0 {
- hoplimit = true
- l += syscall.CmsgSpace(ctlOpts[ctlHopLimit].length)
- }
- pktinfo := false
- if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To16() != nil && cm.Src.To4() == nil || cm.IfIndex > 0) {
- pktinfo = true
- l += syscall.CmsgSpace(ctlOpts[ctlPacketInfo].length)
- }
- nexthop := false
- if ctlOpts[ctlNextHop].name > 0 && cm.NextHop.To16() != nil && cm.NextHop.To4() == nil {
- nexthop = true
- l += syscall.CmsgSpace(ctlOpts[ctlNextHop].length)
- }
- if l > 0 {
- oob = make([]byte, l)
- b := oob
- if tclass {
- b = ctlOpts[ctlTrafficClass].marshal(b, cm)
- }
- if hoplimit {
- b = ctlOpts[ctlHopLimit].marshal(b, cm)
- }
- if pktinfo {
- b = ctlOpts[ctlPacketInfo].marshal(b, cm)
- }
- if nexthop {
- b = ctlOpts[ctlNextHop].marshal(b, cm)
- }
- }
- return
- }
|