1// Copyright 2016 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
5//go:build solaris
6// +build solaris
7
8package lif
9
10import (
11	"errors"
12	"unsafe"
13)
14
15// An Addr represents an address associated with packet routing.
16type Addr interface {
17	// Family returns an address family.
18	Family() int
19}
20
21// An Inet4Addr represents an internet address for IPv4.
22type Inet4Addr struct {
23	IP        [4]byte // IP address
24	PrefixLen int     // address prefix length
25}
26
27// Family implements the Family method of Addr interface.
28func (a *Inet4Addr) Family() int { return sysAF_INET }
29
30// An Inet6Addr represents an internet address for IPv6.
31type Inet6Addr struct {
32	IP        [16]byte // IP address
33	PrefixLen int      // address prefix length
34	ZoneID    int      // zone identifier
35}
36
37// Family implements the Family method of Addr interface.
38func (a *Inet6Addr) Family() int { return sysAF_INET6 }
39
40// Addrs returns a list of interface addresses.
41//
42// The provided af must be an address family and name must be a data
43// link name. The zero value of af or name means a wildcard.
44func Addrs(af int, name string) ([]Addr, error) {
45	eps, err := newEndpoints(af)
46	if len(eps) == 0 {
47		return nil, err
48	}
49	defer func() {
50		for _, ep := range eps {
51			ep.close()
52		}
53	}()
54	lls, err := links(eps, name)
55	if len(lls) == 0 {
56		return nil, err
57	}
58	var as []Addr
59	for _, ll := range lls {
60		var lifr lifreq
61		for i := 0; i < len(ll.Name); i++ {
62			lifr.Name[i] = int8(ll.Name[i])
63		}
64		for _, ep := range eps {
65			ioc := int64(sysSIOCGLIFADDR)
66			err := ioctl(ep.s, uintptr(ioc), unsafe.Pointer(&lifr))
67			if err != nil {
68				continue
69			}
70			sa := (*sockaddrStorage)(unsafe.Pointer(&lifr.Lifru[0]))
71			l := int(nativeEndian.Uint32(lifr.Lifru1[:4]))
72			if l == 0 {
73				continue
74			}
75			switch sa.Family {
76			case sysAF_INET:
77				a := &Inet4Addr{PrefixLen: l}
78				copy(a.IP[:], lifr.Lifru[4:8])
79				as = append(as, a)
80			case sysAF_INET6:
81				a := &Inet6Addr{PrefixLen: l, ZoneID: int(nativeEndian.Uint32(lifr.Lifru[24:28]))}
82				copy(a.IP[:], lifr.Lifru[8:24])
83				as = append(as, a)
84			}
85		}
86	}
87	return as, nil
88}
89
90func parseLinkAddr(b []byte) ([]byte, error) {
91	nlen, alen, slen := int(b[1]), int(b[2]), int(b[3])
92	l := 4 + nlen + alen + slen
93	if len(b) < l {
94		return nil, errors.New("invalid address")
95	}
96	b = b[4:]
97	var addr []byte
98	if nlen > 0 {
99		b = b[nlen:]
100	}
101	if alen > 0 {
102		addr = make([]byte, alen)
103		copy(addr, b[:alen])
104	}
105	return addr, nil
106}
107