// Copyright 2011 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 (
	"internal/syscall/windows"
	"os"
	"syscall"
	"unsafe"
)

// supportsVistaIP reports whether the platform implements new IP
// stack and ABIs supported on Windows Vista and above.
var supportsVistaIP bool

func init() {
	supportsVistaIP = probeWindowsIPStack()
}

func probeWindowsIPStack() (supportsVistaIP bool) {
	v, err := syscall.GetVersion()
	if err != nil {
		return true // Windows 10 and above will deprecate this API
	}
	if byte(v) < 6 { // major version of Windows Vista is 6
		return false
	}
	return true
}

// adapterAddresses returns a list of IP adapter and address
// structures. The structure contains an IP adapter and flattened
// multiple IP addresses including unicast, anycast and multicast
// addresses.
func adapterAddresses() ([]*windows.IpAdapterAddresses, error) {
	var b []byte
	l := uint32(15000) // recommended initial size
	for {
		b = make([]byte, l)
		err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l)
		if err == nil {
			if l == 0 {
				return nil, nil
			}
			break
		}
		if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW {
			return nil, os.NewSyscallError("getadaptersaddresses", err)
		}
		if l <= uint32(len(b)) {
			return nil, os.NewSyscallError("getadaptersaddresses", err)
		}
	}
	var aas []*windows.IpAdapterAddresses
	for aa := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); aa != nil; aa = aa.Next {
		aas = append(aas, aa)
	}
	return aas, nil
}

// 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) {
	aas, err := adapterAddresses()
	if err != nil {
		return nil, err
	}
	var ift []Interface
	for _, aa := range aas {
		index := aa.IfIndex
		if index == 0 { // ipv6IfIndex is a substitute for ifIndex
			index = aa.Ipv6IfIndex
		}
		if ifindex == 0 || ifindex == int(index) {
			ifi := Interface{
				Index: int(index),
				Name:  syscall.UTF16ToString((*(*[10000]uint16)(unsafe.Pointer(aa.FriendlyName)))[:]),
			}
			if aa.OperStatus == windows.IfOperStatusUp {
				ifi.Flags |= FlagUp
			}
			// For now we need to infer link-layer service
			// capabilities from media types.
			// We will be able to use
			// MIB_IF_ROW2.AccessType once we drop support
			// for Windows XP.
			switch aa.IfType {
			case windows.IF_TYPE_ETHERNET_CSMACD, windows.IF_TYPE_ISO88025_TOKENRING, windows.IF_TYPE_IEEE80211, windows.IF_TYPE_IEEE1394:
				ifi.Flags |= FlagBroadcast | FlagMulticast
			case windows.IF_TYPE_PPP, windows.IF_TYPE_TUNNEL:
				ifi.Flags |= FlagPointToPoint | FlagMulticast
			case windows.IF_TYPE_SOFTWARE_LOOPBACK:
				ifi.Flags |= FlagLoopback | FlagMulticast
			case windows.IF_TYPE_ATM:
				ifi.Flags |= FlagBroadcast |
					FlagPointToPoint |
					FlagMulticast // assume all services available; LANE, point-to-point and point-to-multipoint
			}
			if aa.Mtu == 0xffffffff {
				ifi.MTU = -1
			} else {
				ifi.MTU = int(aa.Mtu)
			}
			if aa.PhysicalAddressLength > 0 {
				ifi.HardwareAddr = make(HardwareAddr, aa.PhysicalAddressLength)
				copy(ifi.HardwareAddr, aa.PhysicalAddress[:])
			}
			ift = append(ift, ifi)
			if ifindex == ifi.Index {
				break
			}
		}
	}
	return ift, 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) {
	aas, err := adapterAddresses()
	if err != nil {
		return nil, err
	}
	var ifat []Addr
	for _, aa := range aas {
		index := aa.IfIndex
		if index == 0 { // ipv6IfIndex is a substitute for ifIndex
			index = aa.Ipv6IfIndex
		}
		var pfx4, pfx6 []IPNet
		if !supportsVistaIP {
			pfx4, pfx6, err = addrPrefixTable(aa)
			if err != nil {
				return nil, err
			}
		}
		if ifi == nil || ifi.Index == int(index) {
			for puni := aa.FirstUnicastAddress; puni != nil; puni = puni.Next {
				sa, err := puni.Address.Sockaddr.Sockaddr()
				if err != nil {
					return nil, os.NewSyscallError("sockaddr", err)
				}
				var l int
				switch sa := sa.(type) {
				case *syscall.SockaddrInet4:
					if supportsVistaIP {
						l = int(puni.OnLinkPrefixLength)
					} else {
						l = addrPrefixLen(pfx4, IP(sa.Addr[:]))
					}
					ifa := &IPNet{IP: make(IP, IPv4len), Mask: CIDRMask(l, 8*IPv4len)}
					copy(ifa.IP, sa.Addr[:])
					ifat = append(ifat, ifa)
				case *syscall.SockaddrInet6:
					if supportsVistaIP {
						l = int(puni.OnLinkPrefixLength)
					} else {
						l = addrPrefixLen(pfx6, IP(sa.Addr[:]))
					}
					ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(l, 8*IPv6len)}
					copy(ifa.IP, sa.Addr[:])
					ifat = append(ifat, ifa)
				}
			}
			for pany := aa.FirstAnycastAddress; pany != nil; pany = pany.Next {
				sa, err := pany.Address.Sockaddr.Sockaddr()
				if err != nil {
					return nil, os.NewSyscallError("sockaddr", err)
				}
				switch sa := sa.(type) {
				case *syscall.SockaddrInet4:
					ifa := &IPAddr{IP: make(IP, IPv4len)}
					copy(ifa.IP, sa.Addr[:])
					ifat = append(ifat, ifa)
				case *syscall.SockaddrInet6:
					ifa := &IPAddr{IP: make(IP, IPv6len)}
					copy(ifa.IP, sa.Addr[:])
					ifat = append(ifat, ifa)
				}
			}
		}
	}
	return ifat, nil
}

func addrPrefixTable(aa *windows.IpAdapterAddresses) (pfx4, pfx6 []IPNet, err error) {
	for p := aa.FirstPrefix; p != nil; p = p.Next {
		sa, err := p.Address.Sockaddr.Sockaddr()
		if err != nil {
			return nil, nil, os.NewSyscallError("sockaddr", err)
		}
		switch sa := sa.(type) {
		case *syscall.SockaddrInet4:
			pfx := IPNet{IP: IP(sa.Addr[:]), Mask: CIDRMask(int(p.PrefixLength), 8*IPv4len)}
			pfx4 = append(pfx4, pfx)
		case *syscall.SockaddrInet6:
			pfx := IPNet{IP: IP(sa.Addr[:]), Mask: CIDRMask(int(p.PrefixLength), 8*IPv6len)}
			pfx6 = append(pfx6, pfx)
		}
	}
	return
}

// addrPrefixLen returns an appropriate prefix length in bits for ip
// from pfxs. It returns 32 or 128 when no appropriate on-link address
// prefix found.
//
// NOTE: This is pretty naive implementation that contains many
// allocations and non-effective linear search, and should not be used
// freely.
func addrPrefixLen(pfxs []IPNet, ip IP) int {
	var l int
	var cand *IPNet
	for i := range pfxs {
		if !pfxs[i].Contains(ip) {
			continue
		}
		if cand == nil {
			l, _ = pfxs[i].Mask.Size()
			cand = &pfxs[i]
			continue
		}
		m, _ := pfxs[i].Mask.Size()
		if m > l {
			l = m
			cand = &pfxs[i]
			continue
		}
	}
	if l > 0 {
		return l
	}
	if ip.To4() != nil {
		return 8 * IPv4len
	}
	return 8 * IPv6len
}

// interfaceMulticastAddrTable returns addresses for a specific
// interface.
func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
	aas, err := adapterAddresses()
	if err != nil {
		return nil, err
	}
	var ifat []Addr
	for _, aa := range aas {
		index := aa.IfIndex
		if index == 0 { // ipv6IfIndex is a substitute for ifIndex
			index = aa.Ipv6IfIndex
		}
		if ifi == nil || ifi.Index == int(index) {
			for pmul := aa.FirstMulticastAddress; pmul != nil; pmul = pmul.Next {
				sa, err := pmul.Address.Sockaddr.Sockaddr()
				if err != nil {
					return nil, os.NewSyscallError("sockaddr", err)
				}
				switch sa := sa.(type) {
				case *syscall.SockaddrInet4:
					ifa := &IPAddr{IP: make(IP, IPv4len)}
					copy(ifa.IP, sa.Addr[:])
					ifat = append(ifat, ifa)
				case *syscall.SockaddrInet6:
					ifa := &IPAddr{IP: make(IP, IPv6len)}
					copy(ifa.IP, sa.Addr[:])
					ifat = append(ifat, ifa)
				}
			}
		}
	}
	return ifat, nil
}
