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// +build solaris
6
7package lif
8
9import "unsafe"
10
11// A Link represents logical data link information.
12//
13// It also represents base information for logical network interface.
14// On Solaris, each logical network interface represents network layer
15// adjacency information and the interface has a only single network
16// address or address pair for tunneling. It's usual that multiple
17// logical network interfaces share the same logical data link.
18type Link struct {
19	Name  string // name, equivalent to IP interface name
20	Index int    // index, equivalent to IP interface index
21	Type  int    // type
22	Flags int    // flags
23	MTU   int    // maximum transmission unit, basically link MTU but may differ between IP address families
24	Addr  []byte // address
25}
26
27func (ll *Link) fetch(s uintptr) {
28	var lifr lifreq
29	for i := 0; i < len(ll.Name); i++ {
30		lifr.Name[i] = int8(ll.Name[i])
31	}
32	ioc := int64(sysSIOCGLIFINDEX)
33	if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
34		ll.Index = int(nativeEndian.Uint32(lifr.Lifru[:4]))
35	}
36	ioc = int64(sysSIOCGLIFFLAGS)
37	if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
38		ll.Flags = int(nativeEndian.Uint64(lifr.Lifru[:8]))
39	}
40	ioc = int64(sysSIOCGLIFMTU)
41	if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
42		ll.MTU = int(nativeEndian.Uint32(lifr.Lifru[:4]))
43	}
44	switch ll.Type {
45	case sysIFT_IPV4, sysIFT_IPV6, sysIFT_6TO4:
46	default:
47		ioc = int64(sysSIOCGLIFHWADDR)
48		if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
49			ll.Addr, _ = parseLinkAddr(lifr.Lifru[4:])
50		}
51	}
52}
53
54// Links returns a list of logical data links.
55//
56// The provided af must be an address family and name must be a data
57// link name. The zero value of af or name means a wildcard.
58func Links(af int, name string) ([]Link, error) {
59	eps, err := newEndpoints(af)
60	if len(eps) == 0 {
61		return nil, err
62	}
63	defer func() {
64		for _, ep := range eps {
65			ep.close()
66		}
67	}()
68	return links(eps, name)
69}
70
71func links(eps []endpoint, name string) ([]Link, error) {
72	var lls []Link
73	lifn := lifnum{Flags: sysLIFC_NOXMIT | sysLIFC_TEMPORARY | sysLIFC_ALLZONES | sysLIFC_UNDER_IPMP}
74	lifc := lifconf{Flags: sysLIFC_NOXMIT | sysLIFC_TEMPORARY | sysLIFC_ALLZONES | sysLIFC_UNDER_IPMP}
75	for _, ep := range eps {
76		lifn.Family = uint16(ep.af)
77		ioc := int64(sysSIOCGLIFNUM)
78		if err := ioctl(ep.s, uintptr(ioc), unsafe.Pointer(&lifn)); err != nil {
79			continue
80		}
81		if lifn.Count == 0 {
82			continue
83		}
84		b := make([]byte, lifn.Count*sizeofLifreq)
85		lifc.Family = uint16(ep.af)
86		lifc.Len = lifn.Count * sizeofLifreq
87		if len(lifc.Lifcu) == 8 {
88			nativeEndian.PutUint64(lifc.Lifcu[:], uint64(uintptr(unsafe.Pointer(&b[0]))))
89		} else {
90			nativeEndian.PutUint32(lifc.Lifcu[:], uint32(uintptr(unsafe.Pointer(&b[0]))))
91		}
92		ioc = int64(sysSIOCGLIFCONF)
93		if err := ioctl(ep.s, uintptr(ioc), unsafe.Pointer(&lifc)); err != nil {
94			continue
95		}
96		nb := make([]byte, 32) // see LIFNAMSIZ in net/if.h
97		for i := 0; i < int(lifn.Count); i++ {
98			lifr := (*lifreq)(unsafe.Pointer(&b[i*sizeofLifreq]))
99			for i := 0; i < 32; i++ {
100				if lifr.Name[i] == 0 {
101					nb = nb[:i]
102					break
103				}
104				nb[i] = byte(lifr.Name[i])
105			}
106			llname := string(nb)
107			nb = nb[:32]
108			if isDupLink(lls, llname) || name != "" && name != llname {
109				continue
110			}
111			ll := Link{Name: llname, Type: int(lifr.Type)}
112			ll.fetch(ep.s)
113			lls = append(lls, ll)
114		}
115	}
116	return lls, nil
117}
118
119func isDupLink(lls []Link, name string) bool {
120	for _, ll := range lls {
121		if ll.Name == name {
122			return true
123		}
124	}
125	return false
126}
127