1/*	$NetBSD: af_iso.c,v 1.13 2008/07/15 21:27:58 dyoung Exp $	*/
2
3/*
4 * Copyright (c) 1983, 1993
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33#ifndef lint
34__RCSID("$NetBSD: af_iso.c,v 1.13 2008/07/15 21:27:58 dyoung Exp $");
35#endif /* not lint */
36
37#include <err.h>
38#include <errno.h>
39#include <string.h>
40#include <stddef.h>
41#include <stdlib.h>
42#include <stdio.h>
43#include <util.h>
44
45#include <sys/param.h>
46#include <sys/ioctl.h>
47#include <sys/socket.h>
48
49#include <net/if.h>
50
51#define EON
52#include <netiso/iso.h>
53#include <netiso/iso_var.h>
54
55#include "env.h"
56#include "parse.h"
57#include "extern.h"
58#include "af_inetany.h"
59#include "prog_ops.h"
60
61#define	DEFNSELLEN	1
62
63static void iso_constructor(void) __attribute__((constructor));
64static int setnsellength(prop_dictionary_t, prop_dictionary_t);
65static void iso_status(prop_dictionary_t, prop_dictionary_t, bool);
66static void iso_commit_address(prop_dictionary_t, prop_dictionary_t);
67
68static struct afswtch isoaf = {
69	.af_name = "iso", .af_af = AF_ISO, .af_status = iso_status,
70	.af_addr_commit = iso_commit_address
71};
72
73struct pinteger parse_snpaoffset = PINTEGER_INITIALIZER1(&snpaoffset,
74    "snpaoffset", INT_MIN, INT_MAX, 10, NULL, "snpaoffset",
75    &command_root.pb_parser);
76struct pinteger parse_nsellength = PINTEGER_INITIALIZER1(&nsellength,
77    "nsellength", 0, UINT8_MAX, 10, setnsellength, "nsellength",
78    &command_root.pb_parser);
79
80static const struct kwinst isokw[] = {
81	  {.k_word = "nsellength", .k_nextparser = &parse_nsellength.pi_parser}
82	, {.k_word = "snpaoffset", .k_nextparser = &parse_snpaoffset.pi_parser}
83};
84
85struct pkw iso = PKW_INITIALIZER(&iso, "ISO", NULL, NULL,
86    isokw, __arraycount(isokw), NULL);
87
88static cmdloop_branch_t branch;
89
90static void
91fixnsel(struct sockaddr_iso *siso, uint8_t nsellength)
92{
93	siso->siso_tlen = nsellength;
94}
95
96/* fixup mask */
97static int
98iso_pre_aifaddr(prop_dictionary_t env, const struct afparam *param)
99{
100	struct sockaddr_iso *siso;
101
102	siso = param->mask.buf;
103	siso->siso_len = TSEL(siso) - (char *)(siso);
104	siso->siso_nlen = 0;
105	return 0;
106}
107
108static void
109iso_commit_address(prop_dictionary_t env, prop_dictionary_t oenv)
110{
111	uint8_t nsellength;
112	struct iso_ifreq ifr = {.ifr_Addr = {.siso_tlen = DEFNSELLEN}};
113	struct iso_aliasreq ifra = {
114		.ifra_dstaddr = {.siso_tlen = DEFNSELLEN},
115		.ifra_addr = {.siso_tlen = DEFNSELLEN}
116	};
117	struct afparam isoparam = {
118		  .req = BUFPARAM(ifra)
119		, .dgreq = BUFPARAM(ifr)
120		, .name = {
121			  {.buf = ifr.ifr_name,
122			   .buflen = sizeof(ifr.ifr_name)}
123			, {.buf = ifra.ifra_name,
124			   .buflen = sizeof(ifra.ifra_name)}
125		  }
126		, .dgaddr = BUFPARAM(ifr.ifr_Addr)
127		, .addr = BUFPARAM(ifra.ifra_addr)
128		, .dst = BUFPARAM(ifra.ifra_dstaddr)
129		, .brd = BUFPARAM(ifra.ifra_broadaddr)
130		, .mask = BUFPARAM(ifra.ifra_mask)
131		, .aifaddr = IFADDR_PARAM(SIOCAIFADDR_ISO)
132		, .difaddr = IFADDR_PARAM(SIOCDIFADDR_ISO)
133		, .gifaddr = IFADDR_PARAM(SIOCGIFADDR_ISO)
134		, .defmask = {.buf = NULL, .buflen = 0}
135		, .pre_aifaddr = iso_pre_aifaddr
136	};
137	int64_t snpaoffset;
138
139	if (prop_dictionary_get_int64(env, "snpaoffset", &snpaoffset))
140		ifra.ifra_snpaoffset = snpaoffset;
141
142	if (prop_dictionary_get_uint8(env, "nsellength", &nsellength)) {
143		fixnsel(&ifr.ifr_Addr, nsellength);
144		fixnsel(&ifra.ifra_addr, nsellength);
145		fixnsel(&ifra.ifra_dstaddr, nsellength);
146	}
147	commit_address(env, oenv, &isoparam);
148}
149
150static int
151setnsellength(prop_dictionary_t env, prop_dictionary_t oenv)
152{
153	int af;
154
155	if ((af = getaf(env)) == -1 || af != AF_ISO)
156		errx(EXIT_FAILURE, "Setting NSEL length valid only for ISO");
157
158	return 0;
159
160}
161
162static void
163iso_status(prop_dictionary_t env, prop_dictionary_t oenv, bool force)
164{
165	struct sockaddr_iso *siso;
166	struct iso_ifreq isoifr;
167	int s;
168	const char *ifname;
169	unsigned short flags;
170
171	if ((ifname = getifinfo(env, oenv, &flags)) == NULL)
172		err(EXIT_FAILURE, "%s: getifinfo", __func__);
173
174	if ((s = getsock(AF_ISO)) == -1) {
175		if (errno == EAFNOSUPPORT)
176			return;
177		err(EXIT_FAILURE, "socket");
178	}
179	memset(&isoifr, 0, sizeof(isoifr));
180	estrlcpy(isoifr.ifr_name, ifname, sizeof(isoifr.ifr_name));
181	if (prog_ioctl(s, SIOCGIFADDR_ISO, &isoifr) == -1) {
182		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
183			if (!force)
184				return;
185			memset(&isoifr.ifr_Addr, 0, sizeof(isoifr.ifr_Addr));
186		} else
187			warn("SIOCGIFADDR_ISO");
188	}
189	strlcpy(isoifr.ifr_name, ifname, sizeof(isoifr.ifr_name));
190	siso = &isoifr.ifr_Addr;
191	printf("\tiso %s", iso_ntoa(&siso->siso_addr));
192	if (prog_ioctl(s, SIOCGIFNETMASK_ISO, &isoifr) == -1) {
193		if (errno == EADDRNOTAVAIL)
194			memset(&isoifr.ifr_Addr, 0, sizeof(isoifr.ifr_Addr));
195		else
196			warn("SIOCGIFNETMASK_ISO");
197	} else {
198		if (siso->siso_len > offsetof(struct sockaddr_iso, siso_addr))
199			siso->siso_addr.isoa_len = siso->siso_len
200			    - offsetof(struct sockaddr_iso, siso_addr);
201		printf(" netmask %s", iso_ntoa(&siso->siso_addr));
202	}
203
204	if (flags & IFF_POINTOPOINT) {
205		if (prog_ioctl(s, SIOCGIFDSTADDR_ISO, &isoifr) == -1) {
206			if (errno == EADDRNOTAVAIL)
207			    memset(&isoifr.ifr_Addr, 0,
208				sizeof(isoifr.ifr_Addr));
209			else
210			    warn("SIOCGIFDSTADDR_ISO");
211		}
212		strlcpy(isoifr.ifr_name, ifname, sizeof(isoifr.ifr_name));
213		siso = &isoifr.ifr_Addr;
214		printf(" --> %s", iso_ntoa(&siso->siso_addr));
215	}
216	printf("\n");
217}
218
219static void
220iso_constructor(void)
221{
222	register_family(&isoaf);
223	cmdloop_branch_init(&branch, &iso.pk_parser);
224	register_cmdloop_branch(&branch);
225}
226