Deleted Added
sdiff udiff text old ( 194619 ) new ( 194819 )
full compact
1/*-
2 * Copyright (c) 1990,1991 Regents of The University of Michigan.
3 * Copyright (c) 2009 Robert N. M. Watson
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and distribute this software and
7 * its documentation for any purpose and without fee is hereby granted,
8 * provided that the above copyright notice appears in all copies and

--- 12 unchanged lines hidden (view full) ---

21 * c/o Wesley Craig
22 * 535 W. William Street
23 * Ann Arbor, Michigan
24 * +1-313-764-2278
25 * netatalk@umich.edu
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/netatalk/at_control.c 194619 2009-06-22 10:23:54Z rwatson $");
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/sockio.h>
34#include <sys/lock.h>
35#include <sys/malloc.h>
36#include <sys/kernel.h>
37#include <sys/priv.h>

--- 36 unchanged lines hidden (view full) ---

74int
75at_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
76 struct thread *td)
77{
78 struct ifreq *ifr = (struct ifreq *)data;
79 struct sockaddr_at *sat;
80 struct netrange *nr;
81 struct at_aliasreq *ifra = (struct at_aliasreq *)data;
82 struct at_ifaddr *aa0;
83 struct at_ifaddr *aa = NULL;
84 struct ifaddr *ifa, *ifa0;
85 int error;
86
87 /*
88 * If we have an ifp, then find the matching at_ifaddr if it exists
89 */
90 AT_IFADDR_WLOCK();
91 if (ifp != NULL) {
92 for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) {
93 if (aa->aa_ifp == ifp)
94 break;
95 }
96 }
97
98 /*
99 * In this first switch table we are basically getting ready for
100 * the second one, by getting the atalk-specific things set up
101 * so that they start to look more similar to other protocols etc.
102 */
103
104 switch (cmd) {
105 case SIOCAIFADDR:
106 case SIOCDIFADDR:
107 /*
108 * If we have an appletalk sockaddr, scan forward of where we
109 * are now on the at_ifaddr list to find one with a matching
110 * address on this interface. This may leave aa pointing to
111 * the first address on the NEXT interface!
112 */
113 if (ifra->ifra_addr.sat_family == AF_APPLETALK) {
114 for (; aa; aa = aa->aa_next) {
115 if (aa->aa_ifp == ifp &&
116 sateqaddr(&aa->aa_addr, &ifra->ifra_addr))
117 break;
118 }
119 }
120 /*
121 * If we a retrying to delete an addres but didn't find such,
122 * then rewurn with an error
123 */
124 if (cmd == SIOCDIFADDR && aa == NULL) {
125 AT_IFADDR_WUNLOCK();
126 return (EADDRNOTAVAIL);
127 }
128 /*FALLTHROUGH*/
129
130 case SIOCSIFADDR:
131 /*
132 * If we are not superuser, then we don't get to do these ops.
133 *
134 * XXXRW: Layering?
135 */
136 if (priv_check(td, PRIV_NET_ADDIFADDR)) {
137 AT_IFADDR_WUNLOCK();
138 return (EPERM);
139 }
140
141 sat = satosat(&ifr->ifr_addr);
142 nr = (struct netrange *)sat->sat_zero;
143 if (nr->nr_phase == 1) {
144 /*
145 * Look for a phase 1 address on this interface.
146 * This may leave aa pointing to the first address on
147 * the NEXT interface!
148 */
149 for (; aa; aa = aa->aa_next) {
150 if (aa->aa_ifp == ifp &&
151 (aa->aa_flags & AFA_PHASE2) == 0)
152 break;
153 }
154 } else { /* default to phase 2 */
155 /*
156 * Look for a phase 2 address on this interface.
157 * This may leave aa pointing to the first address on
158 * the NEXT interface!
159 */
160 for (; aa; aa = aa->aa_next) {
161 if (aa->aa_ifp == ifp && (aa->aa_flags &
162 AFA_PHASE2))
163 break;
164 }
165 }
166
167 if (ifp == NULL)
168 panic("at_control");
169
170 /*
171 * If we failed to find an existing at_ifaddr entry, then we
172 * allocate a fresh one.
173 */
174 if (aa == NULL) {
175 aa0 = malloc(sizeof(struct at_ifaddr), M_IFADDR,
176 M_NOWAIT | M_ZERO);
177 if (aa0 == NULL) {
178 AT_IFADDR_WUNLOCK();
179 return (ENOBUFS);
180 }
181 callout_init(&aa0->aa_callout, CALLOUT_MPSAFE);
182 if ((aa = at_ifaddr_list) != NULL) {
183 /*
184 * Don't let the loopback be first, since the
185 * first address is the machine's default
186 * address for binding. If it is, stick
187 * ourself in front, otherwise go to the back
188 * of the list.
189 */
190 if (at_ifaddr_list->aa_ifp->if_flags &
191 IFF_LOOPBACK) {
192 aa = aa0;
193 aa->aa_next = at_ifaddr_list;
194 at_ifaddr_list = aa;
195 } else {
196 for (; aa->aa_next; aa = aa->aa_next)
197 ;
198 aa->aa_next = aa0;
199 }
200 } else
201 at_ifaddr_list = aa0;
202 aa = aa0;
203
204 /*
205 * Find the end of the interface's addresses
206 * and link our new one on the end
207 */
208 ifa = (struct ifaddr *)aa;
209 ifa_init(ifa);
210
211 /*
212 * As the at_ifaddr contains the actual sockaddrs,
213 * and the ifaddr itself, link them al together
214 * correctly.
215 */
216 ifa->ifa_addr = (struct sockaddr *)&aa->aa_addr;
217 ifa->ifa_dstaddr = (struct sockaddr *)&aa->aa_addr;
218 ifa->ifa_netmask = (struct sockaddr *)&aa->aa_netmask;
219
220 /*
221 * Set/clear the phase 2 bit.
222 */
223 if (nr->nr_phase == 1)
224 aa->aa_flags &= ~AFA_PHASE2;
225 else
226 aa->aa_flags |= AFA_PHASE2;
227
228 /*
229 * and link it all together
230 */
231 aa->aa_ifp = ifp;
232 IF_ADDR_LOCK(ifp);
233 TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
234 IF_ADDR_UNLOCK(ifp);
235 } else {
236 /*
237 * If we DID find one then we clobber any routes
238 * dependent on it..
239 *
240 * XXXRW: While we ref the ifaddr, there are
241 * potential races here still.
242 */
243 ifa_ref(&aa->aa_ifa);
244 AT_IFADDR_WUNLOCK();
245 at_scrub(ifp, aa);
246 AT_IFADDR_WLOCK();
247 ifa_free(&aa->aa_ifa);
248 }
249 break;
250
251 case SIOCGIFADDR :
252 sat = satosat(&ifr->ifr_addr);
253 nr = (struct netrange *)sat->sat_zero;
254 if (nr->nr_phase == 1) {
255 /*
256 * If the request is specifying phase 1, then
257 * only look at a phase one address
258 */
259 for (; aa; aa = aa->aa_next) {
260 if (aa->aa_ifp == ifp &&
261 (aa->aa_flags & AFA_PHASE2) == 0)
262 break;
263 }
264 } else {
265 /*
266 * default to phase 2
267 */
268 for (; aa; aa = aa->aa_next) {
269 if (aa->aa_ifp == ifp && (aa->aa_flags &
270 AFA_PHASE2))
271 break;
272 }
273 }
274
275 if (aa == NULL) {
276 AT_IFADDR_WUNLOCK();
277 return (EADDRNOTAVAIL);
278 }
279 break;
280 }
281
282 /*
283 * By the time this switch is run we should be able to assume that
284 * the "aa" pointer is valid when needed.
285 */

--- 10 unchanged lines hidden (view full) ---

296 * and do some cleanups
297 */
298 ((struct netrange *)&sat->sat_zero)->nr_phase
299 = (aa->aa_flags & AFA_PHASE2) ? 2 : 1;
300 ((struct netrange *)&sat->sat_zero)->nr_firstnet =
301 aa->aa_firstnet;
302 ((struct netrange *)&sat->sat_zero)->nr_lastnet =
303 aa->aa_lastnet;
304 AT_IFADDR_WUNLOCK();
305 break;
306
307 case SIOCSIFADDR:
308 ifa_ref(&aa->aa_ifa);
309 AT_IFADDR_WUNLOCK();
310 error = at_ifinit(ifp, aa,
311 (struct sockaddr_at *)&ifr->ifr_addr);
312 ifa_free(&aa->aa_ifa);
313 return (error);
314
315 case SIOCAIFADDR:
316 if (sateqaddr(&ifra->ifra_addr, &aa->aa_addr)) {
317 AT_IFADDR_WUNLOCK();
318 return (0);
319 }
320 ifa_ref(&aa->aa_ifa);
321 AT_IFADDR_WUNLOCK();
322 error = at_ifinit(ifp, aa,
323 (struct sockaddr_at *)&ifr->ifr_addr);
324 ifa_free(&aa->aa_ifa);
325 return (error);
326
327 case SIOCDIFADDR:
328 /*
329 * remove the ifaddr from the interface
330 */
331 ifa0 = (struct ifaddr *)aa;
332 IF_ADDR_LOCK(ifp);
333 TAILQ_REMOVE(&ifp->if_addrhead, ifa0, ifa_link);
334 IF_ADDR_UNLOCK(ifp);
335
336 /*
337 * Now remove the at_ifaddr from the parallel structure
338 * as well, or we'd be in deep trouble
339 */
340 aa0 = aa;
341 if (aa0 == (aa = at_ifaddr_list)) {
342 at_ifaddr_list = aa->aa_next;
343 } else {
344 while (aa->aa_next && (aa->aa_next != aa0))
345 aa = aa->aa_next;
346
347 /*
348 * if we found it, remove it, otherwise we screwed up.
349 */
350 if (aa->aa_next)
351 aa->aa_next = aa0->aa_next;
352 else
353 panic("at_control");
354 }
355 AT_IFADDR_WUNLOCK();
356
357 /*
358 * Now reclaim the reference.
359 */
360 ifa_free(ifa0);
361 break;
362
363 default:
364 AT_IFADDR_WUNLOCK();
365 if (ifp == NULL || ifp->if_ioctl == NULL)
366 return (EOPNOTSUPP);
367 return ((*ifp->if_ioctl)(ifp, cmd, data));
368 }
369 return (0);
370}
371
372/*
373 * Given an interface and an at_ifaddr (supposedly on that interface)
374 * remove any routes that depend on this.
375 * Why ifp is needed I'm not sure,
376 * as aa->at_ifaddr.ifa_ifp should be the same.
377 */

--- 499 unchanged lines hidden ---