1 /* $NetBSD: af_atalk.c,v 1.19 2013/10/19 00:35:30 christos Exp $ */
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
32 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: af_atalk.c,v 1.19 2013/10/19 00:35:30 christos Exp $");
37 #include <sys/param.h>
38 #include <sys/ioctl.h>
39 #include <sys/socket.h>
43 #include <netatalk/at.h>
56 #include "af_inetany.h"
62 #define satocsat(__sa) ((const struct sockaddr_at *)(__sa))
65 static void at_status(prop_dictionary_t
, prop_dictionary_t
, bool);
66 static void at_commit_address(prop_dictionary_t
, prop_dictionary_t
);
68 static void at_constructor(void) __attribute__((constructor
));
70 static struct afswtch ataf
= {
71 .af_name
= "atalk", .af_af
= AF_APPLETALK
, .af_status
= at_status
,
72 .af_addr_commit
= at_commit_address
74 struct pinteger phase
= PINTEGER_INITIALIZER1(&phase
, "phase",
75 1, 2, 10, NULL
, "phase", &command_root
.pb_parser
);
77 struct pstr parse_range
= PSTR_INITIALIZER(&range
, "range", NULL
, "range",
78 &command_root
.pb_parser
);
80 static const struct kwinst atalkkw
[] = {
81 {.k_word
= "phase", .k_nextparser
= &phase
.pi_parser
}
82 , {.k_word
= "range", .k_nextparser
= &parse_range
.ps_parser
}
85 struct pkw atalk
= PKW_INITIALIZER(&atalk
, "AppleTalk", NULL
, NULL
,
86 atalkkw
, __arraycount(atalkkw
), NULL
);
88 static cmdloop_branch_t branch
;
91 setatrange_impl(prop_dictionary_t env
, prop_dictionary_t oenv
,
95 u_short first
= 123, last
= 123;
97 if (getargstr(env
, "range", range
, sizeof(range
)) == -1)
100 if (sscanf(range
, "%hu-%hu", &first
, &last
) != 2 ||
101 first
== 0 || last
== 0 || first
> last
)
102 errx(EXIT_FAILURE
, "%s: illegal net range: %u-%u", range
,
104 nr
->nr_firstnet
= htons(first
);
105 nr
->nr_lastnet
= htons(last
);
109 at_commit_address(prop_dictionary_t env
, prop_dictionary_t oenv
)
112 struct ifaliasreq ifra
__attribute__((aligned(4)));
113 struct afparam atparam
= {
114 .req
= BUFPARAM(ifra
)
115 , .dgreq
= BUFPARAM(ifr
)
117 {.buf
= ifr
.ifr_name
,
118 .buflen
= sizeof(ifr
.ifr_name
)}
119 , {.buf
= ifra
.ifra_name
,
120 .buflen
= sizeof(ifra
.ifra_name
)}
122 , .dgaddr
= BUFPARAM(ifr
.ifr_addr
)
123 , .addr
= BUFPARAM(ifra
.ifra_addr
)
124 , .dst
= BUFPARAM(ifra
.ifra_dstaddr
)
125 , .brd
= BUFPARAM(ifra
.ifra_broadaddr
)
126 , .mask
= BUFPARAM(ifra
.ifra_mask
)
127 , .aifaddr
= IFADDR_PARAM(SIOCAIFADDR
)
128 , .difaddr
= IFADDR_PARAM(SIOCDIFADDR
)
129 , .gifaddr
= IFADDR_PARAM(SIOCGIFADDR
)
130 , .defmask
= {.buf
= NULL
, .buflen
= 0}
132 struct netrange nr
= {.nr_phase
= 2}; /* AppleTalk net range */
134 prop_dictionary_t ienv
;
135 struct paddr_prefix
*addr
;
136 struct sockaddr_at
*sat
;
138 if ((d0
= (prop_data_t
)prop_dictionary_get(env
, "address")) == NULL
)
141 addr
= prop_data_data(d0
);
143 sat
= (struct sockaddr_at
*)&addr
->pfx_addr
;
145 (void)prop_dictionary_get_uint8(env
, "phase", &nr
.nr_phase
);
146 /* Default range of one */
147 nr
.nr_firstnet
= nr
.nr_lastnet
= sat
->sat_addr
.s_net
;
148 setatrange_impl(env
, oenv
, &nr
);
150 if (ntohs(nr
.nr_firstnet
) > ntohs(sat
->sat_addr
.s_net
) ||
151 ntohs(nr
.nr_lastnet
) < ntohs(sat
->sat_addr
.s_net
))
152 errx(EXIT_FAILURE
, "AppleTalk address is not in range");
153 memcpy(&sat
->sat_zero
, &nr
, sizeof(nr
));
155 /* Copy the new address to a temporary input environment */
157 d
= prop_data_create_data_nocopy(addr
, paddr_prefix_size(addr
));
158 ienv
= prop_dictionary_copy_mutable(env
);
161 err(EXIT_FAILURE
, "%s: prop_data_create_data", __func__
);
163 err(EXIT_FAILURE
, "%s: prop_dictionary_copy_mutable", __func__
);
165 if (!prop_dictionary_set(ienv
, "address", (prop_object_t
)d
))
166 err(EXIT_FAILURE
, "%s: prop_dictionary_set", __func__
);
168 /* copy to output environment for good measure */
169 if (!prop_dictionary_set(oenv
, "address", (prop_object_t
)d
))
170 err(EXIT_FAILURE
, "%s: prop_dictionary_set", __func__
);
172 prop_object_release((prop_object_t
)d
);
174 memset(&ifr
, 0, sizeof(ifr
));
175 memset(&ifra
, 0, sizeof(ifra
));
176 commit_address(ienv
, oenv
, &atparam
);
178 /* release temporary input environment */
179 prop_object_release((prop_object_t
)ienv
);
183 sat_print1(const char *prefix
, const struct sockaddr
*sa
)
187 (void)getnameinfo(sa
, sa
->sa_len
, buf
, sizeof(buf
), NULL
, 0, 0);
189 printf("%s%s", prefix
, buf
);
193 at_status(prop_dictionary_t env
, prop_dictionary_t oenv
, bool force
)
195 struct sockaddr_at
*sat
;
199 unsigned short flags
;
201 if ((s
= getsock(AF_APPLETALK
)) == -1) {
202 if (errno
== EAFNOSUPPORT
)
204 err(EXIT_FAILURE
, "getsock");
206 if ((ifname
= getifinfo(env
, oenv
, &flags
)) == NULL
)
207 err(EXIT_FAILURE
, "%s: getifinfo", __func__
);
209 memset(&ifr
, 0, sizeof(ifr
));
210 estrlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
211 ifr
.ifr_addr
.sa_family
= AF_APPLETALK
;
212 if (prog_ioctl(s
, SIOCGIFADDR
, &ifr
) != -1)
214 else if (errno
== EADDRNOTAVAIL
|| errno
== EAFNOSUPPORT
) {
217 memset(&ifr
.ifr_addr
, 0, sizeof(ifr
.ifr_addr
));
220 sat
= (struct sockaddr_at
*)&ifr
.ifr_addr
;
222 sat_print1("\tatalk ", &ifr
.ifr_addr
);
224 if (flags
& IFF_POINTOPOINT
) {
225 estrlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
226 if (prog_ioctl(s
, SIOCGIFDSTADDR
, &ifr
) == -1) {
227 if (errno
== EADDRNOTAVAIL
)
228 memset(&ifr
.ifr_addr
, 0, sizeof(ifr
.ifr_addr
));
230 warn("SIOCGIFDSTADDR");
232 sat_print1(" --> ", &ifr
.ifr_dstaddr
);
234 if (flags
& IFF_BROADCAST
) {
235 /* note RTAX_BRD overlap with IFF_POINTOPOINT */
236 /* note Appletalk broadcast is fixed. */
237 printf(" broadcast %u.%u", ntohs(sat
->sat_addr
.s_net
),
246 register_family(&ataf
);
247 cmdloop_branch_init(&branch
, &atalk
.pk_parser
);
248 register_cmdloop_branch(&branch
);