mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			199 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			199 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
// Copyright 2016 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.
 | 
						|
 | 
						|
package net
 | 
						|
 | 
						|
import (
 | 
						|
	"errors"
 | 
						|
	"os"
 | 
						|
)
 | 
						|
 | 
						|
// If the ifindex is zero, interfaceTable returns mappings of all
 | 
						|
// network interfaces. Otherwise it returns a mapping of a specific
 | 
						|
// interface.
 | 
						|
func interfaceTable(ifindex int) ([]Interface, error) {
 | 
						|
	if ifindex == 0 {
 | 
						|
		n, err := interfaceCount()
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		ifcs := make([]Interface, n)
 | 
						|
		for i := range ifcs {
 | 
						|
			ifc, err := readInterface(i)
 | 
						|
			if err != nil {
 | 
						|
				return nil, err
 | 
						|
			}
 | 
						|
			ifcs[i] = *ifc
 | 
						|
		}
 | 
						|
		return ifcs, nil
 | 
						|
	}
 | 
						|
 | 
						|
	ifc, err := readInterface(ifindex - 1)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	return []Interface{*ifc}, nil
 | 
						|
}
 | 
						|
 | 
						|
func readInterface(i int) (*Interface, error) {
 | 
						|
	ifc := &Interface{
 | 
						|
		Index: i + 1,                        // Offset the index by one to suit the contract
 | 
						|
		Name:  netdir + "/ipifc/" + itoa(i), // Name is the full path to the interface path in plan9
 | 
						|
	}
 | 
						|
 | 
						|
	ifcstat := ifc.Name + "/status"
 | 
						|
	ifcstatf, err := open(ifcstat)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer ifcstatf.close()
 | 
						|
 | 
						|
	line, ok := ifcstatf.readLine()
 | 
						|
	if !ok {
 | 
						|
		return nil, errors.New("invalid interface status file: " + ifcstat)
 | 
						|
	}
 | 
						|
 | 
						|
	fields := getFields(line)
 | 
						|
	if len(fields) < 4 {
 | 
						|
		return nil, errors.New("invalid interface status file: " + ifcstat)
 | 
						|
	}
 | 
						|
 | 
						|
	device := fields[1]
 | 
						|
	mtustr := fields[3]
 | 
						|
 | 
						|
	mtu, _, ok := dtoi(mtustr)
 | 
						|
	if !ok {
 | 
						|
		return nil, errors.New("invalid status file of interface: " + ifcstat)
 | 
						|
	}
 | 
						|
	ifc.MTU = mtu
 | 
						|
 | 
						|
	// Not a loopback device
 | 
						|
	if device != "/dev/null" {
 | 
						|
		deviceaddrf, err := open(device + "/addr")
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		defer deviceaddrf.close()
 | 
						|
 | 
						|
		line, ok = deviceaddrf.readLine()
 | 
						|
		if !ok {
 | 
						|
			return nil, errors.New("invalid address file for interface: " + device + "/addr")
 | 
						|
		}
 | 
						|
 | 
						|
		if len(line) > 0 && len(line)%2 == 0 {
 | 
						|
			ifc.HardwareAddr = make([]byte, len(line)/2)
 | 
						|
			var ok bool
 | 
						|
			for i := range ifc.HardwareAddr {
 | 
						|
				j := (i + 1) * 2
 | 
						|
				ifc.HardwareAddr[i], ok = xtoi2(line[i*2:j], 0)
 | 
						|
				if !ok {
 | 
						|
					ifc.HardwareAddr = ifc.HardwareAddr[:i]
 | 
						|
					break
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		ifc.Flags = FlagUp | FlagBroadcast | FlagMulticast
 | 
						|
	} else {
 | 
						|
		ifc.Flags = FlagUp | FlagMulticast | FlagLoopback
 | 
						|
	}
 | 
						|
 | 
						|
	return ifc, nil
 | 
						|
}
 | 
						|
 | 
						|
func interfaceCount() (int, error) {
 | 
						|
	d, err := os.Open(netdir + "/ipifc")
 | 
						|
	if err != nil {
 | 
						|
		return -1, err
 | 
						|
	}
 | 
						|
	defer d.Close()
 | 
						|
 | 
						|
	names, err := d.Readdirnames(0)
 | 
						|
	if err != nil {
 | 
						|
		return -1, err
 | 
						|
	}
 | 
						|
 | 
						|
	// Assumes that numbered files in ipifc are strictly
 | 
						|
	// the incrementing numbered directories for the
 | 
						|
	// interfaces
 | 
						|
	c := 0
 | 
						|
	for _, name := range names {
 | 
						|
		if _, _, ok := dtoi(name); !ok {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		c++
 | 
						|
	}
 | 
						|
 | 
						|
	return c, nil
 | 
						|
}
 | 
						|
 | 
						|
// If the ifi is nil, interfaceAddrTable returns addresses for all
 | 
						|
// network interfaces. Otherwise it returns addresses for a specific
 | 
						|
// interface.
 | 
						|
func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
 | 
						|
	var ifcs []Interface
 | 
						|
	if ifi == nil {
 | 
						|
		var err error
 | 
						|
		ifcs, err = interfaceTable(0)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		ifcs = []Interface{*ifi}
 | 
						|
	}
 | 
						|
 | 
						|
	addrs := make([]Addr, len(ifcs))
 | 
						|
	for i, ifc := range ifcs {
 | 
						|
		status := ifc.Name + "/status"
 | 
						|
		statusf, err := open(status)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		defer statusf.close()
 | 
						|
 | 
						|
		line, ok := statusf.readLine()
 | 
						|
		line, ok = statusf.readLine()
 | 
						|
		if !ok {
 | 
						|
			return nil, errors.New("cannot parse IP address for interface: " + status)
 | 
						|
		}
 | 
						|
 | 
						|
		// This assumes only a single address for the interface.
 | 
						|
		fields := getFields(line)
 | 
						|
		if len(fields) < 1 {
 | 
						|
			return nil, errors.New("cannot parse IP address for interface: " + status)
 | 
						|
		}
 | 
						|
		addr := fields[0]
 | 
						|
		ip := ParseIP(addr)
 | 
						|
		if ip == nil {
 | 
						|
			return nil, errors.New("cannot parse IP address for interface: " + status)
 | 
						|
		}
 | 
						|
 | 
						|
		// The mask is represented as CIDR relative to the IPv6 address.
 | 
						|
		// Plan 9 internal representation is always IPv6.
 | 
						|
		maskfld := fields[1]
 | 
						|
		maskfld = maskfld[1:]
 | 
						|
		pfxlen, _, ok := dtoi(maskfld)
 | 
						|
		if !ok {
 | 
						|
			return nil, errors.New("cannot parse network mask for interface: " + status)
 | 
						|
		}
 | 
						|
		var mask IPMask
 | 
						|
		if ip.To4() != nil { // IPv4 or IPv6 IPv4-mapped address
 | 
						|
			mask = CIDRMask(pfxlen-8*len(v4InV6Prefix), 8*IPv4len)
 | 
						|
		}
 | 
						|
		if ip.To16() != nil && ip.To4() == nil { // IPv6 address
 | 
						|
			mask = CIDRMask(pfxlen, 8*IPv6len)
 | 
						|
		}
 | 
						|
 | 
						|
		addrs[i] = &IPNet{IP: ip, Mask: mask}
 | 
						|
	}
 | 
						|
 | 
						|
	return addrs, nil
 | 
						|
}
 | 
						|
 | 
						|
// interfaceMulticastAddrTable returns addresses for a specific
 | 
						|
// interface.
 | 
						|
func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
 | 
						|
	return nil, nil
 | 
						|
}
 |