at_control.c (194619) | at_control.c (194819) |
---|---|
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> | 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 $"); | 29__FBSDID("$FreeBSD: head/sys/netatalk/at_control.c 194819 2009-06-24 10:32:44Z 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; | 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; | 82 struct at_ifaddr *aa_temp; 83 struct at_ifaddr *aa; |
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 */ | 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(); | 90 aa = NULL; 91 AT_IFADDR_RLOCK(); |
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 } | 92 if (ifp != NULL) { 93 for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) { 94 if (aa->aa_ifp == ifp) 95 break; 96 } 97 } |
98 if (aa != NULL) 99 ifa_ref(&aa->aa_ifa); 100 AT_IFADDR_RUNLOCK(); |
|
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 */ | 101 102 /* 103 * In this first switch table we are basically getting ready for 104 * the second one, by getting the atalk-specific things set up 105 * so that they start to look more similar to other protocols etc. 106 */ |
103 | 107 error = 0; |
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) { | 108 switch (cmd) { 109 case SIOCAIFADDR: 110 case SIOCDIFADDR: 111 /* 112 * If we have an appletalk sockaddr, scan forward of where we 113 * are now on the at_ifaddr list to find one with a matching 114 * address on this interface. This may leave aa pointing to 115 * the first address on the NEXT interface! 116 */ 117 if (ifra->ifra_addr.sat_family == AF_APPLETALK) { |
114 for (; aa; aa = aa->aa_next) { | 118 struct at_ifaddr *oaa; 119 120 AT_IFADDR_RLOCK(); 121 for (oaa = aa; aa; aa = aa->aa_next) { |
115 if (aa->aa_ifp == ifp && 116 sateqaddr(&aa->aa_addr, &ifra->ifra_addr)) 117 break; 118 } | 122 if (aa->aa_ifp == ifp && 123 sateqaddr(&aa->aa_addr, &ifra->ifra_addr)) 124 break; 125 } |
126 if (oaa != NULL && oaa != aa) 127 ifa_free(&oaa->aa_ifa); 128 if (aa != NULL && oaa != aa) 129 ifa_ref(&aa->aa_ifa); 130 AT_IFADDR_RUNLOCK(); |
|
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) { | 131 } 132 /* 133 * If we a retrying to delete an addres but didn't find such, 134 * then rewurn with an error 135 */ 136 if (cmd == SIOCDIFADDR && aa == NULL) { |
125 AT_IFADDR_WUNLOCK(); 126 return (EADDRNOTAVAIL); | 137 error = EADDRNOTAVAIL; 138 goto out; |
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)) { | 139 } 140 /*FALLTHROUGH*/ 141 142 case SIOCSIFADDR: 143 /* 144 * If we are not superuser, then we don't get to do these ops. 145 * 146 * XXXRW: Layering? 147 */ 148 if (priv_check(td, PRIV_NET_ADDIFADDR)) { |
137 AT_IFADDR_WUNLOCK(); 138 return (EPERM); | 149 error = EPERM; 150 goto out; |
139 } 140 141 sat = satosat(&ifr->ifr_addr); 142 nr = (struct netrange *)sat->sat_zero; 143 if (nr->nr_phase == 1) { | 151 } 152 153 sat = satosat(&ifr->ifr_addr); 154 nr = (struct netrange *)sat->sat_zero; 155 if (nr->nr_phase == 1) { |
156 struct at_ifaddr *oaa; 157 |
|
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 */ | 158 /* 159 * Look for a phase 1 address on this interface. 160 * This may leave aa pointing to the first address on 161 * the NEXT interface! 162 */ |
149 for (; aa; aa = aa->aa_next) { | 163 AT_IFADDR_RLOCK(); 164 for (oaa = aa; aa; aa = aa->aa_next) { |
150 if (aa->aa_ifp == ifp && 151 (aa->aa_flags & AFA_PHASE2) == 0) 152 break; 153 } | 165 if (aa->aa_ifp == ifp && 166 (aa->aa_flags & AFA_PHASE2) == 0) 167 break; 168 } |
169 if (oaa != NULL && oaa != aa) 170 ifa_free(&oaa->aa_ifa); 171 if (aa != NULL && oaa != aa) 172 ifa_ref(&aa->aa_ifa); 173 AT_IFADDR_RUNLOCK(); |
|
154 } else { /* default to phase 2 */ | 174 } else { /* default to phase 2 */ |
175 struct at_ifaddr *oaa; 176 |
|
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 */ | 177 /* 178 * Look for a phase 2 address on this interface. 179 * This may leave aa pointing to the first address on 180 * the NEXT interface! 181 */ |
160 for (; aa; aa = aa->aa_next) { | 182 AT_IFADDR_RLOCK(); 183 for (oaa = aa; aa; aa = aa->aa_next) { |
161 if (aa->aa_ifp == ifp && (aa->aa_flags & 162 AFA_PHASE2)) 163 break; 164 } | 184 if (aa->aa_ifp == ifp && (aa->aa_flags & 185 AFA_PHASE2)) 186 break; 187 } |
188 if (oaa != NULL && oaa != aa) 189 ifa_free(&oaa->aa_ifa); 190 if (aa != NULL && oaa != aa) 191 ifa_ref(&aa->aa_ifa); 192 AT_IFADDR_RUNLOCK(); |
|
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) { | 193 } 194 195 if (ifp == NULL) 196 panic("at_control"); 197 198 /* 199 * If we failed to find an existing at_ifaddr entry, then we 200 * allocate a fresh one. 201 */ 202 if (aa == NULL) { |
175 aa0 = malloc(sizeof(struct at_ifaddr), M_IFADDR, | 203 aa = malloc(sizeof(struct at_ifaddr), M_IFADDR, |
176 M_NOWAIT | M_ZERO); | 204 M_NOWAIT | M_ZERO); |
177 if (aa0 == NULL) { 178 AT_IFADDR_WUNLOCK(); 179 return (ENOBUFS); | 205 if (aa == NULL) { 206 error = ENOBUFS; 207 goto out; |
180 } | 208 } |
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; | 209 callout_init(&aa->aa_callout, CALLOUT_MPSAFE); |
203 | 210 |
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, | 211 ifa = (struct ifaddr *)aa; 212 ifa_init(ifa); 213 214 /* 215 * As the at_ifaddr contains the actual sockaddrs, |
213 * and the ifaddr itself, link them al together | 216 * and the ifaddr itself, link them all 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 | 217 * correctly. 218 */ 219 ifa->ifa_addr = (struct sockaddr *)&aa->aa_addr; 220 ifa->ifa_dstaddr = (struct sockaddr *)&aa->aa_addr; 221 ifa->ifa_netmask = (struct sockaddr *)&aa->aa_netmask; 222 223 /* 224 * Set/clear the phase 2 bit. 225 */ 226 if (nr->nr_phase == 1) 227 aa->aa_flags &= ~AFA_PHASE2; 228 else 229 aa->aa_flags |= AFA_PHASE2; 230 |
231 ifa_ref(&aa->aa_ifa); /* at_ifaddr_list */ 232 AT_IFADDR_WLOCK(); 233 if ((aa_temp = at_ifaddr_list) != NULL) { 234 /* 235 * Don't let the loopback be first, since the 236 * first address is the machine's default 237 * address for binding. If it is, stick 238 * ourself in front, otherwise go to the back 239 * of the list. 240 */ 241 if (at_ifaddr_list->aa_ifp->if_flags & 242 IFF_LOOPBACK) { 243 aa->aa_next = at_ifaddr_list; 244 at_ifaddr_list = aa; 245 } else { 246 for (; aa_temp->aa_next; aa_temp = 247 aa_temp->aa_next) 248 ; 249 aa_temp->aa_next = aa; 250 } 251 } else 252 at_ifaddr_list = aa; 253 AT_IFADDR_WUNLOCK(); 254 |
|
228 /* 229 * and link it all together 230 */ 231 aa->aa_ifp = ifp; | 255 /* 256 * and link it all together 257 */ 258 aa->aa_ifp = ifp; |
259 ifa_ref(&aa->aa_ifa); /* if_addrhead */ |
|
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.. | 260 IF_ADDR_LOCK(ifp); 261 TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); 262 IF_ADDR_UNLOCK(ifp); 263 } else { 264 /* 265 * If we DID find one then we clobber any routes 266 * dependent on it.. |
239 * 240 * XXXRW: While we ref the ifaddr, there are 241 * potential races here still. | |
242 */ | 267 */ |
243 ifa_ref(&aa->aa_ifa); 244 AT_IFADDR_WUNLOCK(); | |
245 at_scrub(ifp, aa); | 268 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) { | 269 } 270 break; 271 272 case SIOCGIFADDR : 273 sat = satosat(&ifr->ifr_addr); 274 nr = (struct netrange *)sat->sat_zero; 275 if (nr->nr_phase == 1) { |
276 struct at_ifaddr *oaa; 277 |
|
255 /* 256 * If the request is specifying phase 1, then 257 * only look at a phase one address 258 */ | 278 /* 279 * If the request is specifying phase 1, then 280 * only look at a phase one address 281 */ |
259 for (; aa; aa = aa->aa_next) { | 282 AT_IFADDR_RUNLOCK(); 283 for (oaa = aa; aa; aa = aa->aa_next) { |
260 if (aa->aa_ifp == ifp && 261 (aa->aa_flags & AFA_PHASE2) == 0) 262 break; 263 } | 284 if (aa->aa_ifp == ifp && 285 (aa->aa_flags & AFA_PHASE2) == 0) 286 break; 287 } |
288 if (oaa != NULL && oaa != aa) 289 ifa_free(&oaa->aa_ifa); 290 if (aa != NULL && oaa != aa) 291 ifa_ref(&aa->aa_ifa); 292 AT_IFADDR_RLOCK(); |
|
264 } else { | 293 } else { |
294 struct at_ifaddr *oaa; 295 |
|
265 /* 266 * default to phase 2 267 */ | 296 /* 297 * default to phase 2 298 */ |
268 for (; aa; aa = aa->aa_next) { | 299 AT_IFADDR_RLOCK(); 300 for (oaa = aa; aa; aa = aa->aa_next) { |
269 if (aa->aa_ifp == ifp && (aa->aa_flags & 270 AFA_PHASE2)) 271 break; 272 } | 301 if (aa->aa_ifp == ifp && (aa->aa_flags & 302 AFA_PHASE2)) 303 break; 304 } |
305 if (oaa != NULL && oaa != aa) 306 ifa_free(&oaa->aa_ifa); 307 if (aa != NULL && oaa != aa) 308 ifa_ref(&aa->aa_ifa); 309 AT_IFADDR_RUNLOCK(); |
|
273 } 274 275 if (aa == NULL) { | 310 } 311 312 if (aa == NULL) { |
276 AT_IFADDR_WUNLOCK(); 277 return (EADDRNOTAVAIL); | 313 error = EADDRNOTAVAIL; 314 goto out; |
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; | 315 } 316 break; 317 } 318 319 /* 320 * By the time this switch is run we should be able to assume that 321 * the "aa" pointer is valid when needed. 322 */ --- 10 unchanged lines hidden (view full) --- 333 * and do some cleanups 334 */ 335 ((struct netrange *)&sat->sat_zero)->nr_phase 336 = (aa->aa_flags & AFA_PHASE2) ? 2 : 1; 337 ((struct netrange *)&sat->sat_zero)->nr_firstnet = 338 aa->aa_firstnet; 339 ((struct netrange *)&sat->sat_zero)->nr_lastnet = 340 aa->aa_lastnet; |
304 AT_IFADDR_WUNLOCK(); | |
305 break; 306 307 case SIOCSIFADDR: | 341 break; 342 343 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); | 344 error = at_ifinit(ifp, aa, 345 (struct sockaddr_at *)&ifr->ifr_addr); |
312 ifa_free(&aa->aa_ifa); 313 return (error); | 346 goto out; |
314 315 case SIOCAIFADDR: 316 if (sateqaddr(&ifra->ifra_addr, &aa->aa_addr)) { | 347 348 case SIOCAIFADDR: 349 if (sateqaddr(&ifra->ifra_addr, &aa->aa_addr)) { |
317 AT_IFADDR_WUNLOCK(); 318 return (0); | 350 error = 0; 351 goto out; |
319 } | 352 } |
320 ifa_ref(&aa->aa_ifa); 321 AT_IFADDR_WUNLOCK(); | |
322 error = at_ifinit(ifp, aa, 323 (struct sockaddr_at *)&ifr->ifr_addr); | 353 error = at_ifinit(ifp, aa, 354 (struct sockaddr_at *)&ifr->ifr_addr); |
324 ifa_free(&aa->aa_ifa); 325 return (error); | 355 goto out; |
326 327 case SIOCDIFADDR: | 356 357 case SIOCDIFADDR: |
358 |
|
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); | 359 /* 360 * remove the ifaddr from the interface 361 */ 362 ifa0 = (struct ifaddr *)aa; 363 IF_ADDR_LOCK(ifp); 364 TAILQ_REMOVE(&ifp->if_addrhead, ifa0, ifa_link); 365 IF_ADDR_UNLOCK(ifp); |
366 ifa_free(ifa0); /* if_addrhead */ |
|
335 336 /* 337 * Now remove the at_ifaddr from the parallel structure 338 * as well, or we'd be in deep trouble 339 */ | 367 368 /* 369 * Now remove the at_ifaddr from the parallel structure 370 * as well, or we'd be in deep trouble 371 */ |
340 aa0 = aa; 341 if (aa0 == (aa = at_ifaddr_list)) { | 372 373 AT_IFADDR_WLOCK(); 374 if (aa == (aa_temp = at_ifaddr_list)) { |
342 at_ifaddr_list = aa->aa_next; 343 } else { | 375 at_ifaddr_list = aa->aa_next; 376 } else { |
344 while (aa->aa_next && (aa->aa_next != aa0)) 345 aa = aa->aa_next; | 377 while (aa_temp->aa_next && (aa_temp->aa_next != aa)) 378 aa_temp = aa_temp->aa_next; |
346 347 /* | 379 380 /* |
348 * if we found it, remove it, otherwise we screwed up. | 381 * if we found it, remove it, otherwise we 382 * screwed up. |
349 */ | 383 */ |
350 if (aa->aa_next) 351 aa->aa_next = aa0->aa_next; | 384 if (aa_temp->aa_next) 385 aa_temp->aa_next = aa->aa_next; |
352 else 353 panic("at_control"); 354 } 355 AT_IFADDR_WUNLOCK(); | 386 else 387 panic("at_control"); 388 } 389 AT_IFADDR_WUNLOCK(); |
356 357 /* 358 * Now reclaim the reference. 359 */ 360 ifa_free(ifa0); | 390 ifa_free(ifa0); /* at_ifaddr_list */ 391 aa = aa_temp; |
361 break; 362 363 default: | 392 break; 393 394 default: |
364 AT_IFADDR_WUNLOCK(); 365 if (ifp == NULL || ifp->if_ioctl == NULL) 366 return (EOPNOTSUPP); 367 return ((*ifp->if_ioctl)(ifp, cmd, data)); | 395 if (ifp == NULL || ifp->if_ioctl == NULL) { 396 error = EOPNOTSUPP; 397 goto out; 398 } 399 error = ((*ifp->if_ioctl)(ifp, cmd, data)); |
368 } | 400 } |
369 return (0); | 401 402out: 403 if (aa != NULL) 404 ifa_free(&aa->aa_ifa); 405 return (error); |
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 --- | 406} 407 408/* 409 * Given an interface and an at_ifaddr (supposedly on that interface) 410 * remove any routes that depend on this. 411 * Why ifp is needed I'm not sure, 412 * as aa->at_ifaddr.ifa_ifp should be the same. 413 */ --- 499 unchanged lines hidden --- |