1 /* 2 * Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved. 3 * Copyright (c) 2004-2008 Qing Li. All rights reserved. 4 * Copyright (c) 2008 Kip Macy. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include "opt_inet.h" 31 #include "opt_inet6.h" 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/malloc.h> 36 #include <sys/mbuf.h> 37 #include <sys/syslog.h> 38 #include <sys/sysctl.h> 39 #include <sys/socket.h> 40 #include <sys/kernel.h> 41 #include <sys/lock.h> 42 #include <sys/mutex.h> 43 #include <sys/rwlock.h> 44 45 #include <vm/uma.h> 46 47 #include <netinet/in.h> 48 #include <net/if_llatbl.h> 49 #include <net/if.h> 50 #include <net/if_dl.h> 51 #include <net/if_var.h> 52 #include <net/route.h> 53 #include <net/vnet.h> 54 #include <netinet/if_ether.h> 55 #include <netinet6/in6_var.h> 56 #include <netinet6/nd6.h> 57 58 MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables"); 59 60 static SLIST_HEAD(, lltable) lltables = SLIST_HEAD_INITIALIZER(lltables); 61 62 extern void arprequest(struct ifnet *, struct in_addr *, struct in_addr *, 63 u_char *); 64 65 struct rwlock lltable_rwlock; 66 RW_SYSINIT(lltable_rwlock, &lltable_rwlock, "lltable_rwlock"); 67 68 /* 69 * Dump arp state for a specific address family. 70 */ 71 int 72 lltable_sysctl_dumparp(int af, struct sysctl_req *wr) 73 { 74 struct lltable *llt; 75 int error = 0; 76 77 LLTABLE_RLOCK(); 78 SLIST_FOREACH(llt, &lltables, llt_link) { 79 if (llt->llt_af == af) { 80 error = llt->llt_dump(llt, wr); 81 if (error != 0) 82 goto done; 83 } 84 } 85 done: 86 LLTABLE_RUNLOCK(); 87 return (error); 88 } 89 90 /* 91 * Deletes an address from the address table. 92 * This function is called by the timer functions 93 * such as arptimer() and nd6_llinfo_timer(), and 94 * the caller does the locking. 95 */ 96 void 97 llentry_free(struct llentry *lle) 98 { 99 100 LLE_WLOCK_ASSERT(lle); 101 LIST_REMOVE(lle, lle_next); 102 103 if (lle->la_hold != NULL) 104 m_freem(lle->la_hold); 105 106 LLE_FREE_LOCKED(lle); 107 } 108 109 /* 110 * Update an llentry for address dst (equivalent to rtalloc for new-arp) 111 * Caller must pass in a valid struct llentry * 112 * 113 * if found the llentry * is returned referenced and unlocked 114 */ 115 int 116 llentry_update(struct llentry **llep, struct lltable *lt, 117 struct sockaddr *dst, struct ifnet *ifp) 118 { 119 struct llentry *la; 120 121 IF_AFDATA_RLOCK(ifp); 122 la = lla_lookup(lt, LLE_EXCLUSIVE, 123 (struct sockaddr *)dst); 124 IF_AFDATA_RUNLOCK(ifp); 125 if ((la == NULL) && 126 (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) { 127 IF_AFDATA_WLOCK(ifp); 128 la = lla_lookup(lt, 129 (LLE_CREATE | LLE_EXCLUSIVE), 130 (struct sockaddr *)dst); 131 IF_AFDATA_WUNLOCK(ifp); 132 } 133 if (la != NULL && (*llep != la)) { 134 if (*llep != NULL) 135 LLE_FREE(*llep); 136 LLE_ADDREF(la); 137 LLE_WUNLOCK(la); 138 *llep = la; 139 } else if (la != NULL) 140 LLE_WUNLOCK(la); 141 142 if (la == NULL) 143 return (ENOENT); 144 145 return (0); 146 } 147 148 /* 149 * Free all entries from given table and free itself. 150 */ 151 void 152 lltable_free(struct lltable *llt) 153 { 154 struct llentry *lle, *next; 155 int i; 156 157 KASSERT(llt != NULL, ("%s: llt is NULL", __func__)); 158 159 LLTABLE_WLOCK(); 160 SLIST_REMOVE(&lltables, llt, lltable, llt_link); 161 LLTABLE_WUNLOCK(); 162 163 for (i=0; i < LLTBL_HASHTBL_SIZE; i++) { 164 LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { 165 166 callout_drain(&lle->la_timer); 167 LLE_WLOCK(lle); 168 llentry_free(lle); 169 } 170 } 171 172 free(llt, M_LLTABLE); 173 } 174 175 void 176 lltable_drain(int af) 177 { 178 struct lltable *llt; 179 struct llentry *lle; 180 register int i; 181 182 LLTABLE_RLOCK(); 183 SLIST_FOREACH(llt, &lltables, llt_link) { 184 if (llt->llt_af != af) 185 continue; 186 187 for (i=0; i < LLTBL_HASHTBL_SIZE; i++) { 188 LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 189 if (lle->la_hold) { 190 m_freem(lle->la_hold); 191 lle->la_hold = NULL; 192 } 193 } 194 } 195 } 196 LLTABLE_RUNLOCK(); 197 } 198 199 void 200 lltable_prefix_free(int af, struct sockaddr *prefix, struct sockaddr *mask) 201 { 202 struct lltable *llt; 203 204 LLTABLE_RLOCK(); 205 SLIST_FOREACH(llt, &lltables, llt_link) { 206 if (llt->llt_af != af) 207 continue; 208 209 llt->llt_prefix_free(llt, prefix, mask); 210 } 211 LLTABLE_RUNLOCK(); 212 } 213 214 215 216 /* 217 * Create a new lltable. 218 */ 219 struct lltable * 220 lltable_init(struct ifnet *ifp, int af) 221 { 222 struct lltable *llt; 223 register int i; 224 225 llt = malloc(sizeof(struct lltable), M_LLTABLE, M_WAITOK); 226 if (llt == NULL) 227 return (NULL); 228 229 llt->llt_af = af; 230 llt->llt_ifp = ifp; 231 for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) 232 LIST_INIT(&llt->lle_head[i]); 233 234 LLTABLE_WLOCK(); 235 SLIST_INSERT_HEAD(&lltables, llt, llt_link); 236 LLTABLE_WUNLOCK(); 237 238 return (llt); 239 } 240 241 /* 242 * Called in route_output when adding/deleting a route to an interface. 243 */ 244 int 245 lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) 246 { 247 struct sockaddr_dl *dl = 248 (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY]; 249 struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST]; 250 struct ifnet *ifp; 251 struct lltable *llt; 252 struct llentry *lle; 253 u_int laflags = 0, flags = 0; 254 int error = 0; 255 256 if (dl == NULL || dl->sdl_family != AF_LINK) { 257 log(LOG_INFO, "%s: invalid dl\n", __func__); 258 return EINVAL; 259 } 260 ifp = ifnet_byindex(dl->sdl_index); 261 if (ifp == NULL) { 262 log(LOG_INFO, "%s: invalid ifp (sdl_index %d)\n", 263 __func__, dl->sdl_index); 264 return EINVAL; 265 } 266 267 switch (rtm->rtm_type) { 268 case RTM_ADD: 269 if (rtm->rtm_flags & RTF_ANNOUNCE) { 270 flags |= LLE_PUB; 271 #ifdef INET 272 if (dst->sa_family == AF_INET && 273 ((struct sockaddr_inarp *)dst)->sin_other != 0) { 274 struct rtentry *rt = rtalloc1(dst, 0, 0); 275 if (rt == NULL || !(rt->rt_flags & RTF_HOST)) { 276 log(LOG_INFO, "%s: RTM_ADD publish " 277 "(proxy only) is invalid\n", 278 __func__); 279 if (rt) 280 RTFREE_LOCKED(rt); 281 return EINVAL; 282 } 283 RTFREE_LOCKED(rt); 284 285 flags |= LLE_PROXY; 286 } 287 #endif 288 } 289 flags |= LLE_CREATE; 290 break; 291 292 case RTM_DELETE: 293 flags |= LLE_DELETE; 294 break; 295 296 case RTM_CHANGE: 297 break; 298 299 default: 300 return EINVAL; /* XXX not implemented yet */ 301 } 302 303 /* XXX linked list may be too expensive */ 304 LLTABLE_RLOCK(); 305 SLIST_FOREACH(llt, &lltables, llt_link) { 306 if (llt->llt_af == dst->sa_family && 307 llt->llt_ifp == ifp) 308 break; 309 } 310 LLTABLE_RUNLOCK(); 311 KASSERT(llt != NULL, ("Yep, ugly hacks are bad\n")); 312 313 if (flags && LLE_CREATE) 314 flags |= LLE_EXCLUSIVE; 315 316 IF_AFDATA_LOCK(ifp); 317 lle = lla_lookup(llt, flags, dst); 318 IF_AFDATA_UNLOCK(ifp); 319 if (LLE_IS_VALID(lle)) { 320 if (flags & LLE_CREATE) { 321 /* 322 * If we delay the delete, then a subsequent 323 * "arp add" should look up this entry, reset the 324 * LLE_DELETED flag, and reset the expiration timer 325 */ 326 bcopy(LLADDR(dl), &lle->ll_addr, ifp->if_addrlen); 327 lle->la_flags |= LLE_VALID; 328 lle->la_flags &= ~LLE_DELETED; 329 #ifdef INET6 330 /* 331 * ND6 332 */ 333 if (dst->sa_family == AF_INET6) 334 lle->ln_state = ND6_LLINFO_REACHABLE; 335 #endif 336 /* 337 * NB: arp and ndp always set (RTF_STATIC | RTF_HOST) 338 */ 339 340 if (rtm->rtm_rmx.rmx_expire == 0) { 341 lle->la_flags |= LLE_STATIC; 342 lle->la_expire = 0; 343 } else 344 lle->la_expire = rtm->rtm_rmx.rmx_expire; 345 laflags = lle->la_flags; 346 LLE_WUNLOCK(lle); 347 #ifdef INET 348 /* gratuitous ARP */ 349 if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) { 350 arprequest(ifp, 351 &((struct sockaddr_in *)dst)->sin_addr, 352 &((struct sockaddr_in *)dst)->sin_addr, 353 ((laflags & LLE_PROXY) ? 354 (u_char *)IF_LLADDR(ifp) : 355 (u_char *)LLADDR(dl))); 356 } 357 #endif 358 } else { 359 if (flags & LLE_EXCLUSIVE) 360 LLE_WUNLOCK(lle); 361 else 362 LLE_RUNLOCK(lle); 363 } 364 } else if ((lle == NULL) && (flags & LLE_DELETE)) 365 error = EINVAL; 366 367 368 return (error); 369 } 370