1/*
2 * Copyright (c) 1983, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#ifndef lint
31static const char rcsid[] =
32  "$FreeBSD$";
33#endif /* not lint */
34
35#include <sys/types.h>
36#include <sys/ioctl.h>
37#include <sys/socket.h>
38#include <net/if.h>
39
40#include <netatalk/at.h>
41
42#include <err.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <unistd.h>
47#include <ifaddrs.h>
48
49#include <arpa/inet.h>
50
51#include "ifconfig.h"
52
53static struct netrange at_nr;		/* AppleTalk net range */
54static struct ifaliasreq at_addreq;
55
56/* XXX  FIXME -- should use strtoul for better parsing. */
57static void
58setatrange(const char *range, int dummy __unused, int s,
59    const struct afswtch *afp)
60{
61	u_int	first = 123, last = 123;
62
63	if (sscanf(range, "%u-%u", &first, &last) != 2
64	    || first == 0 || first > 0xffff
65	    || last == 0 || last > 0xffff || first > last)
66		errx(1, "%s: illegal net range: %u-%u", range, first, last);
67	at_nr.nr_firstnet = htons(first);
68	at_nr.nr_lastnet = htons(last);
69}
70
71static void
72setatphase(const char *phase, int dummy __unused, int s,
73    const struct afswtch *afp)
74{
75	if (!strcmp(phase, "1"))
76		at_nr.nr_phase = 1;
77	else if (!strcmp(phase, "2"))
78		at_nr.nr_phase = 2;
79	else
80		errx(1, "%s: illegal phase", phase);
81}
82
83static void
84at_status(int s __unused, const struct ifaddrs *ifa)
85{
86	struct sockaddr_at *sat, null_sat;
87	struct netrange *nr;
88
89	memset(&null_sat, 0, sizeof(null_sat));
90
91	sat = (struct sockaddr_at *)ifa->ifa_addr;
92	if (sat == NULL)
93		return;
94	nr = &sat->sat_range.r_netrange;
95	printf("\tatalk %d.%d range %d-%d phase %d",
96		ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
97		ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase);
98	if (ifa->ifa_flags & IFF_POINTOPOINT) {
99		sat = (struct sockaddr_at *)ifa->ifa_dstaddr;
100		if (sat == NULL)
101			sat = &null_sat;
102		printf("--> %d.%d",
103			ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
104	}
105	if (ifa->ifa_flags & IFF_BROADCAST) {
106		sat = (struct sockaddr_at *)ifa->ifa_broadaddr;
107		if (sat != NULL)
108			printf(" broadcast %d.%d",
109				ntohs(sat->sat_addr.s_net),
110				sat->sat_addr.s_node);
111	}
112
113	putchar('\n');
114}
115
116static void
117at_getaddr(const char *addr, int which)
118{
119	struct sockaddr_at *sat = (struct sockaddr_at *) &at_addreq.ifra_addr;
120	u_int net, node;
121
122	sat->sat_family = AF_APPLETALK;
123	sat->sat_len = sizeof(*sat);
124	if (which == MASK)
125		errx(1, "AppleTalk does not use netmasks");
126	if (sscanf(addr, "%u.%u", &net, &node) != 2
127	    || net > 0xffff || node > 0xfe)
128		errx(1, "%s: illegal address", addr);
129	sat->sat_addr.s_net = htons(net);
130	sat->sat_addr.s_node = node;
131}
132
133static void
134at_postproc(int s, const struct afswtch *afp)
135{
136	struct sockaddr_at *sat = (struct sockaddr_at *) &at_addreq.ifra_addr;
137
138	if (at_nr.nr_phase == 0)
139		at_nr.nr_phase = 2;	/* Default phase 2 */
140	if (at_nr.nr_firstnet == 0)
141		at_nr.nr_firstnet =	/* Default range of one */
142		at_nr.nr_lastnet = sat->sat_addr.s_net;
143	printf("\tatalk %d.%d range %d-%d phase %d\n",
144		ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
145		ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet),
146		at_nr.nr_phase);
147	if ((u_short) ntohs(at_nr.nr_firstnet) >
148			(u_short) ntohs(sat->sat_addr.s_net)
149		    || (u_short) ntohs(at_nr.nr_lastnet) <
150			(u_short) ntohs(sat->sat_addr.s_net))
151		errx(1, "AppleTalk address is not in range");
152	sat->sat_range.r_netrange = at_nr;
153}
154
155static struct cmd atalk_cmds[] = {
156	DEF_CMD_ARG("range",	setatrange),
157	DEF_CMD_ARG("phase",	setatphase),
158};
159
160static struct afswtch af_atalk = {
161	.af_name	= "atalk",
162	.af_af		= AF_APPLETALK,
163	.af_status	= at_status,
164	.af_getaddr	= at_getaddr,
165	.af_postproc	= at_postproc,
166	.af_difaddr	= SIOCDIFADDR,
167	.af_aifaddr	= SIOCAIFADDR,
168	.af_ridreq	= &at_addreq,
169	.af_addreq	= &at_addreq,
170};
171
172static __constructor void
173atalk_ctor(void)
174{
175#define	N(a)	(sizeof(a) / sizeof(a[0]))
176	size_t i;
177
178	for (i = 0; i < N(atalk_cmds);  i++)
179		cmd_register(&atalk_cmds[i]);
180	af_register(&af_atalk);
181#undef N
182}
183