1// Copyright 2013 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
5package ipv6
6
7import (
8	"net"
9
10	"golang.org/x/net/bpf"
11)
12
13// MulticastHopLimit returns the hop limit field value for outgoing
14// multicast packets.
15func (c *dgramOpt) MulticastHopLimit() (int, error) {
16	if !c.ok() {
17		return 0, errInvalidConn
18	}
19	so, ok := sockOpts[ssoMulticastHopLimit]
20	if !ok {
21		return 0, errNotImplemented
22	}
23	return so.GetInt(c.Conn)
24}
25
26// SetMulticastHopLimit sets the hop limit field value for future
27// outgoing multicast packets.
28func (c *dgramOpt) SetMulticastHopLimit(hoplim int) error {
29	if !c.ok() {
30		return errInvalidConn
31	}
32	so, ok := sockOpts[ssoMulticastHopLimit]
33	if !ok {
34		return errNotImplemented
35	}
36	return so.SetInt(c.Conn, hoplim)
37}
38
39// MulticastInterface returns the default interface for multicast
40// packet transmissions.
41func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
42	if !c.ok() {
43		return nil, errInvalidConn
44	}
45	so, ok := sockOpts[ssoMulticastInterface]
46	if !ok {
47		return nil, errNotImplemented
48	}
49	return so.getMulticastInterface(c.Conn)
50}
51
52// SetMulticastInterface sets the default interface for future
53// multicast packet transmissions.
54func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
55	if !c.ok() {
56		return errInvalidConn
57	}
58	so, ok := sockOpts[ssoMulticastInterface]
59	if !ok {
60		return errNotImplemented
61	}
62	return so.setMulticastInterface(c.Conn, ifi)
63}
64
65// MulticastLoopback reports whether transmitted multicast packets
66// should be copied and send back to the originator.
67func (c *dgramOpt) MulticastLoopback() (bool, error) {
68	if !c.ok() {
69		return false, errInvalidConn
70	}
71	so, ok := sockOpts[ssoMulticastLoopback]
72	if !ok {
73		return false, errNotImplemented
74	}
75	on, err := so.GetInt(c.Conn)
76	if err != nil {
77		return false, err
78	}
79	return on == 1, nil
80}
81
82// SetMulticastLoopback sets whether transmitted multicast packets
83// should be copied and send back to the originator.
84func (c *dgramOpt) SetMulticastLoopback(on bool) error {
85	if !c.ok() {
86		return errInvalidConn
87	}
88	so, ok := sockOpts[ssoMulticastLoopback]
89	if !ok {
90		return errNotImplemented
91	}
92	return so.SetInt(c.Conn, boolint(on))
93}
94
95// JoinGroup joins the group address group on the interface ifi.
96// By default all sources that can cast data to group are accepted.
97// It's possible to mute and unmute data transmission from a specific
98// source by using ExcludeSourceSpecificGroup and
99// IncludeSourceSpecificGroup.
100// JoinGroup uses the system assigned multicast interface when ifi is
101// nil, although this is not recommended because the assignment
102// depends on platforms and sometimes it might require routing
103// configuration.
104func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
105	if !c.ok() {
106		return errInvalidConn
107	}
108	so, ok := sockOpts[ssoJoinGroup]
109	if !ok {
110		return errNotImplemented
111	}
112	grp := netAddrToIP16(group)
113	if grp == nil {
114		return errMissingAddress
115	}
116	return so.setGroup(c.Conn, ifi, grp)
117}
118
119// LeaveGroup leaves the group address group on the interface ifi
120// regardless of whether the group is any-source group or
121// source-specific group.
122func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
123	if !c.ok() {
124		return errInvalidConn
125	}
126	so, ok := sockOpts[ssoLeaveGroup]
127	if !ok {
128		return errNotImplemented
129	}
130	grp := netAddrToIP16(group)
131	if grp == nil {
132		return errMissingAddress
133	}
134	return so.setGroup(c.Conn, ifi, grp)
135}
136
137// JoinSourceSpecificGroup joins the source-specific group comprising
138// group and source on the interface ifi.
139// JoinSourceSpecificGroup uses the system assigned multicast
140// interface when ifi is nil, although this is not recommended because
141// the assignment depends on platforms and sometimes it might require
142// routing configuration.
143func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
144	if !c.ok() {
145		return errInvalidConn
146	}
147	so, ok := sockOpts[ssoJoinSourceGroup]
148	if !ok {
149		return errNotImplemented
150	}
151	grp := netAddrToIP16(group)
152	if grp == nil {
153		return errMissingAddress
154	}
155	src := netAddrToIP16(source)
156	if src == nil {
157		return errMissingAddress
158	}
159	return so.setSourceGroup(c.Conn, ifi, grp, src)
160}
161
162// LeaveSourceSpecificGroup leaves the source-specific group on the
163// interface ifi.
164func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
165	if !c.ok() {
166		return errInvalidConn
167	}
168	so, ok := sockOpts[ssoLeaveSourceGroup]
169	if !ok {
170		return errNotImplemented
171	}
172	grp := netAddrToIP16(group)
173	if grp == nil {
174		return errMissingAddress
175	}
176	src := netAddrToIP16(source)
177	if src == nil {
178		return errMissingAddress
179	}
180	return so.setSourceGroup(c.Conn, ifi, grp, src)
181}
182
183// ExcludeSourceSpecificGroup excludes the source-specific group from
184// the already joined any-source groups by JoinGroup on the interface
185// ifi.
186func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
187	if !c.ok() {
188		return errInvalidConn
189	}
190	so, ok := sockOpts[ssoBlockSourceGroup]
191	if !ok {
192		return errNotImplemented
193	}
194	grp := netAddrToIP16(group)
195	if grp == nil {
196		return errMissingAddress
197	}
198	src := netAddrToIP16(source)
199	if src == nil {
200		return errMissingAddress
201	}
202	return so.setSourceGroup(c.Conn, ifi, grp, src)
203}
204
205// IncludeSourceSpecificGroup includes the excluded source-specific
206// group by ExcludeSourceSpecificGroup again on the interface ifi.
207func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
208	if !c.ok() {
209		return errInvalidConn
210	}
211	so, ok := sockOpts[ssoUnblockSourceGroup]
212	if !ok {
213		return errNotImplemented
214	}
215	grp := netAddrToIP16(group)
216	if grp == nil {
217		return errMissingAddress
218	}
219	src := netAddrToIP16(source)
220	if src == nil {
221		return errMissingAddress
222	}
223	return so.setSourceGroup(c.Conn, ifi, grp, src)
224}
225
226// Checksum reports whether the kernel will compute, store or verify a
227// checksum for both incoming and outgoing packets. If on is true, it
228// returns an offset in bytes into the data of where the checksum
229// field is located.
230func (c *dgramOpt) Checksum() (on bool, offset int, err error) {
231	if !c.ok() {
232		return false, 0, errInvalidConn
233	}
234	so, ok := sockOpts[ssoChecksum]
235	if !ok {
236		return false, 0, errNotImplemented
237	}
238	offset, err = so.GetInt(c.Conn)
239	if err != nil {
240		return false, 0, err
241	}
242	if offset < 0 {
243		return false, 0, nil
244	}
245	return true, offset, nil
246}
247
248// SetChecksum enables the kernel checksum processing. If on is ture,
249// the offset should be an offset in bytes into the data of where the
250// checksum field is located.
251func (c *dgramOpt) SetChecksum(on bool, offset int) error {
252	if !c.ok() {
253		return errInvalidConn
254	}
255	so, ok := sockOpts[ssoChecksum]
256	if !ok {
257		return errNotImplemented
258	}
259	if !on {
260		offset = -1
261	}
262	return so.SetInt(c.Conn, offset)
263}
264
265// ICMPFilter returns an ICMP filter.
266func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
267	if !c.ok() {
268		return nil, errInvalidConn
269	}
270	so, ok := sockOpts[ssoICMPFilter]
271	if !ok {
272		return nil, errNotImplemented
273	}
274	return so.getICMPFilter(c.Conn)
275}
276
277// SetICMPFilter deploys the ICMP filter.
278func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
279	if !c.ok() {
280		return errInvalidConn
281	}
282	so, ok := sockOpts[ssoICMPFilter]
283	if !ok {
284		return errNotImplemented
285	}
286	return so.setICMPFilter(c.Conn, f)
287}
288
289// SetBPF attaches a BPF program to the connection.
290//
291// Only supported on Linux.
292func (c *dgramOpt) SetBPF(filter []bpf.RawInstruction) error {
293	if !c.ok() {
294		return errInvalidConn
295	}
296	so, ok := sockOpts[ssoAttachFilter]
297	if !ok {
298		return errNotImplemented
299	}
300	return so.setBPF(c.Conn, filter)
301}
302