1 /* $NetBSD: af_atalk.c,v 1.14 2008/07/15 21:27:58 dyoung 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.14 2008/07/15 21:27:58 dyoung Exp $");
37 #include <sys/param.h>
38 #include <sys/ioctl.h>
39 #include <sys/socket.h>
43 #include <netatalk/at.h>
54 #include "af_inetany.h"
59 #define satocsat(__sa) ((const struct sockaddr_at *)(__sa))
62 static void at_status(prop_dictionary_t
, prop_dictionary_t
, bool);
63 static void at_commit_address(prop_dictionary_t
, prop_dictionary_t
);
65 static void at_constructor(void) __attribute__((constructor
));
67 static struct afswtch ataf
= {
68 .af_name
= "atalk", .af_af
= AF_APPLETALK
, .af_status
= at_status
,
69 .af_addr_commit
= at_commit_address
71 struct pinteger phase
= PINTEGER_INITIALIZER1(&phase
, "phase",
72 1, 2, 10, NULL
, "phase", &command_root
.pb_parser
);
74 struct pstr parse_range
= PSTR_INITIALIZER(&range
, "range", NULL
, "range",
75 &command_root
.pb_parser
);
77 static const struct kwinst atalkkw
[] = {
78 {.k_word
= "phase", .k_nextparser
= &phase
.pi_parser
}
79 , {.k_word
= "range", .k_nextparser
= &parse_range
.ps_parser
}
82 struct pkw atalk
= PKW_INITIALIZER(&atalk
, "AppleTalk", NULL
, NULL
,
83 atalkkw
, __arraycount(atalkkw
), NULL
);
85 static cmdloop_branch_t branch
;
88 setatrange_impl(prop_dictionary_t env
, prop_dictionary_t oenv
,
92 u_short first
= 123, last
= 123;
94 if (getargstr(env
, "range", range
, sizeof(range
)) == -1)
97 if (sscanf(range
, "%hu-%hu", &first
, &last
) != 2 ||
98 first
== 0 || last
== 0 || first
> last
)
99 errx(EXIT_FAILURE
, "%s: illegal net range: %u-%u", range
,
101 nr
->nr_firstnet
= htons(first
);
102 nr
->nr_lastnet
= htons(last
);
106 at_commit_address(prop_dictionary_t env
, prop_dictionary_t oenv
)
109 struct ifaliasreq ifra
__attribute__((aligned(4)));
110 struct afparam atparam
= {
111 .req
= BUFPARAM(ifra
)
112 , .dgreq
= BUFPARAM(ifr
)
114 {.buf
= ifr
.ifr_name
,
115 .buflen
= sizeof(ifr
.ifr_name
)}
116 , {.buf
= ifra
.ifra_name
,
117 .buflen
= sizeof(ifra
.ifra_name
)}
119 , .dgaddr
= BUFPARAM(ifr
.ifr_addr
)
120 , .addr
= BUFPARAM(ifra
.ifra_addr
)
121 , .dst
= BUFPARAM(ifra
.ifra_dstaddr
)
122 , .brd
= BUFPARAM(ifra
.ifra_broadaddr
)
123 , .mask
= BUFPARAM(ifra
.ifra_mask
)
124 , .aifaddr
= IFADDR_PARAM(SIOCAIFADDR
)
125 , .difaddr
= IFADDR_PARAM(SIOCDIFADDR
)
126 , .gifaddr
= IFADDR_PARAM(SIOCGIFADDR
)
127 , .defmask
= {.buf
= NULL
, .buflen
= 0}
129 struct netrange nr
= {.nr_phase
= 2}; /* AppleTalk net range */
131 prop_dictionary_t ienv
;
132 struct paddr_prefix
*addr
;
133 struct sockaddr_at
*sat
;
135 if ((d0
= (prop_data_t
)prop_dictionary_get(env
, "address")) == NULL
)
138 addr
= prop_data_data(d0
);
140 sat
= (struct sockaddr_at
*)&addr
->pfx_addr
;
142 (void)prop_dictionary_get_uint8(env
, "phase", &nr
.nr_phase
);
143 /* Default range of one */
144 nr
.nr_firstnet
= nr
.nr_lastnet
= sat
->sat_addr
.s_net
;
145 setatrange_impl(env
, oenv
, &nr
);
147 if (ntohs(nr
.nr_firstnet
) > ntohs(sat
->sat_addr
.s_net
) ||
148 ntohs(nr
.nr_lastnet
) < ntohs(sat
->sat_addr
.s_net
))
149 errx(EXIT_FAILURE
, "AppleTalk address is not in range");
150 *((struct netrange
*)&sat
->sat_zero
) = nr
;
152 /* Copy the new address to a temporary input environment */
154 d
= prop_data_create_data_nocopy(addr
, paddr_prefix_size(addr
));
155 ienv
= prop_dictionary_copy_mutable(env
);
158 err(EXIT_FAILURE
, "%s: prop_data_create_data", __func__
);
160 err(EXIT_FAILURE
, "%s: prop_dictionary_copy_mutable", __func__
);
162 if (!prop_dictionary_set(ienv
, "address", (prop_object_t
)d
))
163 err(EXIT_FAILURE
, "%s: prop_dictionary_set", __func__
);
165 /* copy to output environment for good measure */
166 if (!prop_dictionary_set(oenv
, "address", (prop_object_t
)d
))
167 err(EXIT_FAILURE
, "%s: prop_dictionary_set", __func__
);
169 prop_object_release((prop_object_t
)d
);
171 memset(&ifr
, 0, sizeof(ifr
));
172 memset(&ifra
, 0, sizeof(ifra
));
173 commit_address(ienv
, oenv
, &atparam
);
175 /* release temporary input environment */
176 prop_object_release((prop_object_t
)ienv
);
180 sat_print(const char *prefix
, const struct sockaddr
*sa
)
182 const struct sockaddr_at
*sat
= satocsat(sa
);
184 printf("%s%d.%d", prefix
, ntohs(sat
->sat_addr
.s_net
),
185 sat
->sat_addr
.s_node
);
189 at_status(prop_dictionary_t env
, prop_dictionary_t oenv
, bool force
)
191 struct sockaddr_at
*sat
;
196 unsigned short flags
;
198 if ((s
= getsock(AF_APPLETALK
)) == -1) {
199 if (errno
== EAFNOSUPPORT
)
201 err(EXIT_FAILURE
, "getsock");
203 if ((ifname
= getifinfo(env
, oenv
, &flags
)) == NULL
)
204 err(EXIT_FAILURE
, "%s: getifinfo", __func__
);
206 memset(&ifr
, 0, sizeof(ifr
));
207 estrlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
208 ifr
.ifr_addr
.sa_family
= AF_APPLETALK
;
209 if (ioctl(s
, SIOCGIFADDR
, &ifr
) != -1)
211 else if (errno
== EADDRNOTAVAIL
|| errno
== EAFNOSUPPORT
) {
214 memset(&ifr
.ifr_addr
, 0, sizeof(ifr
.ifr_addr
));
217 sat
= (struct sockaddr_at
*)&ifr
.ifr_addr
;
219 nr
= (struct netrange
*)&sat
->sat_zero
;
220 sat_print("\tatalk ", &ifr
.ifr_addr
);
221 printf(" range %d-%d phase %d",
222 ntohs(nr
->nr_firstnet
), ntohs(nr
->nr_lastnet
), nr
->nr_phase
);
224 if (flags
& IFF_POINTOPOINT
) {
225 estrlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
226 if (ioctl(s
, SIOCGIFDSTADDR
, &ifr
) == -1) {
227 if (errno
== EADDRNOTAVAIL
)
228 memset(&ifr
.ifr_addr
, 0, sizeof(ifr
.ifr_addr
));
230 warn("SIOCGIFDSTADDR");
232 sat_print(" --> ", &ifr
.ifr_dstaddr
);
234 if (flags
& IFF_BROADCAST
) {
235 /* note RTAX_BRD overlap with IFF_POINTOPOINT */
236 sat_print(" broadcast ", &ifr
.ifr_broadaddr
);
244 register_family(&ataf
);
245 cmdloop_branch_init(&branch
, &atalk
.pk_parser
);
246 register_cmdloop_branch(&branch
);