1/* 2 * $Id: aarp.c,v 1.4 2005-04-28 20:50:07 bfernhomberg Exp $ 3 */ 4 5#ifdef HAVE_CONFIG_H 6#include "config.h" 7#endif /* HAVE_CONFIG_H */ 8 9#include <sys/types.h> 10#include <sys/socket.h> 11#include <sys/byteorder.h> 12#include <sys/errno.h> 13#include <sys/stream.h> 14#include <sys/ethernet.h> 15#include <sys/kmem.h> 16#include <sys/cmn_err.h> 17#include <sys/ddi.h> 18#include <netinet/arp.h> 19#include <net/if.h> 20 21#ifdef STDC_HEADERS 22#include <strings.h> 23#else 24#include <string.h> 25#endif 26 27#include <netatalk/at.h> 28#include <netatalk/aarp.h> 29#include <netatalk/phase2.h> 30 31#include "if.h" 32 33struct aarplist { 34 struct aarplist *aal_next, *aal_prev; 35 struct at_addr aal_addr; 36 u_char aal_hwaddr[ ETHERADDRL ]; 37 u_char aal_age; 38 u_char aal_flags; 39 mblk_t *aal_m; 40}; 41 42 struct aarplist * 43aarp_find( struct atif_data *aid, ushort net, unchar node ) 44{ 45 struct aarplist *aal; 46 47 for ( aal = aid->aid_aarplist; aal != NULL; aal = aal->aal_next ) { 48 if ( aal->aal_addr.s_net == net && aal->aal_addr.s_node == node ) { 49 break; 50 } 51 } 52 return( aal ); 53} 54 55 struct aarplist * 56aarp_alloc( struct atif_data *aid, ushort net, unchar node ) 57{ 58 struct aarplist *aal; 59 60 for ( aal = aid->aid_aarplist; aal != NULL; aal = aal->aal_next ) { 61 if ( aal->aal_addr.s_net == net && aal->aal_addr.s_node == node ) { 62 return( aal ); 63 } 64 } 65 66 if ( aid->aid_aarpflist == NULL ) { 67 if (( aal = (struct aarplist *)kmem_alloc( sizeof( struct aarplist ), 68 KM_NOSLEEP )) == NULL ) { 69 return( NULL ); 70 } 71 } else { 72 aal = aid->aid_aarpflist; 73 aid->aid_aarpflist = aal->aal_next; 74 if ( aid->aid_aarpflist != NULL ) { 75 aid->aid_aarpflist->aal_prev = NULL; 76 } 77 } 78 79 aal->aal_addr.s_net = net; 80 aal->aal_addr.s_node = node; 81 bzero( aal->aal_hwaddr, sizeof( aal->aal_hwaddr )); 82 aal->aal_age = 0; 83 aal->aal_flags = 0; 84 aal->aal_m = NULL; 85 86 aal->aal_next = aid->aid_aarplist; 87 aal->aal_prev = NULL; 88 if ( aid->aid_aarplist != NULL ) { 89 aid->aid_aarplist->aal_prev = aal; 90 } 91 aid->aid_aarplist = aal; 92 93 return( aal ); 94} 95 96/* 97 * Move entry to free list. 98 */ 99 void 100aarp_free( struct atif_data *aid, struct aarplist *aal ) 101{ 102 if ( aal->aal_next != NULL ) { 103 aal->aal_next->aal_prev = aal->aal_prev; 104 } 105 if ( aal->aal_prev != NULL ) { 106 aal->aal_prev->aal_next = aal->aal_next; 107 } 108 if ( aid->aid_aarplist == aal ) { 109 aid->aid_aarplist = aal->aal_next; 110 } 111 112 if ( aal->aal_m != NULL ) { 113 freemsg( aal->aal_m ); 114 aal->aal_m = NULL; 115 } 116 117 aal->aal_prev = NULL; 118 aal->aal_next = aid->aid_aarpflist; 119 if ( aid->aid_aarpflist != NULL ) { 120 aid->aid_aarpflist->aal_prev = aal; 121 } 122 aid->aid_aarpflist = aal; 123 return; 124} 125 126 void 127aarp_timeout( void *ptr ) 128{ 129 struct atif_data *aid = (struct atif_data *) ptr; 130 struct aarplist *aal, *p; 131 132 aid->aid_aarptimeo = qtimeout( aid->aid_q, aarp_timeout, 133 (caddr_t)aid, 60 * hz ); 134 for ( aal = aid->aid_aarplist; aal != NULL; aal = p ) { 135 p = aal->aal_next; 136 if ( ++aal->aal_age < (( aal->aal_flags ) ? 5 : 3 )) { 137 continue; 138 } 139 aarp_free( aid, aal ); 140 } 141 return; 142} 143 144 void 145aarp_init( struct atif_data *aid ) 146{ 147 aid->aid_aarptimeo = qtimeout( aid->aid_q, aarp_timeout, 148 (caddr_t)aid, 60 * hz ); 149 return; 150} 151 152 void 153aarp_clean( struct atif_data *aid ) 154{ 155 struct aarplist *aal, *p; 156 157 if ( aid->aid_aarptimeo != 0 ) { 158 quntimeout( aid->aid_q, aid->aid_aarptimeo ); 159 aid->aid_aarptimeo = 0; 160 } 161 162 for ( aal = aid->aid_aarplist; aal != NULL; aal = p ) { 163 p = aal->aal_next; 164 if ( aal->aal_m != NULL ) { 165 freemsg( aal->aal_m ); 166 aal->aal_m = NULL; 167 } 168 kmem_free( aal, sizeof( struct aarplist )); 169 } 170 aid->aid_aarplist = NULL; 171 172 for ( aal = aid->aid_aarpflist; aal != NULL; aal = p ) { 173 p = aal->aal_next; 174 if ( aal->aal_m != NULL ) { 175 freemsg( aal->aal_m ); 176 aal->aal_m = NULL; 177 } 178 kmem_free( aal, sizeof( struct aarplist )); 179 } 180 aid->aid_aarpflist = NULL; 181 182 return; 183} 184 185 int 186aarp_rput( queue_t *q, mblk_t *m ) 187{ 188 struct atif_data *aid = (struct atif_data *)q->q_ptr; 189 struct ether_aarp *ea; 190 struct aarplist *aal; 191 ushort tpnet, spnet, op; 192 193 if ( m->b_wptr - m->b_rptr < sizeof( struct ether_aarp )) { 194 cmn_err( CE_NOTE, "aarp_rput short packet\n" ); 195 goto done; 196 } 197 198 ea = (struct ether_aarp *)m->b_rptr; 199 200 if ( ea->aarp_hrd != htons( AARPHRD_ETHER ) || 201 ea->aarp_pro != htons( ETHERTYPE_AT ) || 202 ea->aarp_hln != sizeof( ea->aarp_sha ) || 203 ea->aarp_pln != sizeof( ea->aarp_spu )) { 204 cmn_err( CE_NOTE, "aarp_rput bad constants\n" ); 205 goto done; 206 } 207 208 if ( bcmp( ea->aarp_sha, aid->aid_hwaddr, sizeof( ea->aarp_sha )) == 0 ) { 209 goto done; 210 } 211 212 op = ntohs( ea->aarp_op ); 213 bcopy( ea->aarp_tpnet, &tpnet, sizeof( tpnet )); 214 bcopy( ea->aarp_spnet, &spnet, sizeof( spnet )); 215 216 if ( aid->aid_flags & AIDF_PROBING ) { 217 if ( tpnet == aid->aid_sat.sat_addr.s_net && 218 ea->aarp_tpnode == aid->aid_sat.sat_addr.s_node ) { 219 aid->aid_flags &= ~AIDF_PROBING; 220 aid->aid_flags |= AIDF_PROBEFAILED; 221 cmn_err( CE_NOTE, "aarp_rput probe collision %s\n", aid->aid_name ); 222 } 223 } else { 224 if ( tpnet == aid->aid_sat.sat_addr.s_net && 225 ea->aarp_tpnode == aid->aid_sat.sat_addr.s_node ) { 226 switch ( op ) { 227 case AARPOP_REQUEST : 228 aal = aarp_alloc( aid, spnet, ea->aarp_spnode ); 229 bcopy( ea->aarp_sha, aal->aal_hwaddr, sizeof( ea->aarp_sha )); 230 aal->aal_age = 0; 231 aal->aal_flags = 1; /* complete */ 232 case AARPOP_PROBE : 233 aarp_send( aid, AARPOP_RESPONSE, ea->aarp_sha, 234 spnet, ea->aarp_spnode ); 235 break; 236 237 case AARPOP_RESPONSE : 238 if (( aal = 239 aarp_find( aid, spnet, ea->aarp_spnode )) == NULL ) { 240 break; 241 } 242 bcopy( ea->aarp_sha, aal->aal_hwaddr, sizeof( ea->aarp_sha )); 243 aal->aal_age = 0; 244 aal->aal_flags = 1; /* complete */ 245 if ( aal->aal_m != NULL ) { 246 dl_unitdata_req( WR( q ), aal->aal_m, ETHERTYPE_AT, 247 aal->aal_hwaddr ); 248 aal->aal_m = NULL; 249 } 250 break; 251 252 default : 253 cmn_err( CE_NOTE, "aarp_rput bad op %X\n", op ); 254 break; 255 } 256 } else { 257 switch ( op ) { 258 case AARPOP_REQUEST : 259 break; 260 case AARPOP_PROBE : 261 if (( aal = 262 aarp_find( aid, spnet, ea->aarp_spnode )) != NULL ) { 263 aarp_free( aid, aal ); 264 } 265 break; 266 267 case AARPOP_RESPONSE : 268 cmn_err( CE_NOTE, "aarp_rput someone using our address\n" ); 269 break; 270 271 default : 272 cmn_err( CE_NOTE, "aarp_rput bad op %X\n", op ); 273 break; 274 } 275 } 276 } 277 278done : 279 freemsg( m ); 280 return( 0 ); 281} 282 283 void 284aarp_send( struct atif_data *aid, int op, caddr_t hwaddr, 285 ushort net, unchar node ) 286{ 287 mblk_t *m; 288 struct ether_aarp *ea; 289 290 if (( m = allocb( sizeof( struct ether_aarp ), BPRI_HI )) == NULL ) { 291 return; 292 } 293 m->b_wptr = m->b_rptr + sizeof( struct ether_aarp ); 294 ea = (struct ether_aarp *)m->b_rptr; 295 bzero( (caddr_t)ea, sizeof( struct ether_aarp )); 296 297 ea->aarp_hrd = htons( AARPHRD_ETHER ); 298 ea->aarp_pro = htons( ETHERTYPE_AT ); 299 ea->aarp_hln = sizeof( ea->aarp_sha ); 300 ea->aarp_pln = sizeof( ea->aarp_spu ); 301 ea->aarp_op = htons( op ); 302 bcopy( aid->aid_hwaddr, ea->aarp_sha, sizeof( ea->aarp_sha )); 303 304 if ( hwaddr == NULL ) { 305 bzero( ea->aarp_tha, sizeof( ea->aarp_tha )); 306 } else { 307 bcopy( hwaddr, ea->aarp_tha, sizeof( ea->aarp_tha )); 308 } 309 310 ea->aarp_tpnode = node; 311 bcopy( &aid->aid_sat.sat_addr.s_net, ea->aarp_spnet, 312 sizeof( ea->aarp_spnet )); 313 bcopy( &net, ea->aarp_tpnet, sizeof( ea->aarp_tpnet )); 314 ea->aarp_spnode = aid->aid_sat.sat_addr.s_node; 315 ea->aarp_tpnode = node; 316 317 if ( hwaddr == NULL ) { 318 dl_unitdata_req( WR( aid->aid_q ), m, ETHERTYPE_AARP, 319 at_multicastaddr ); 320 } else { 321 dl_unitdata_req( WR( aid->aid_q ), m, ETHERTYPE_AARP, hwaddr ); 322 } 323 return; 324} 325 326 int 327aarp_resolve( struct atif_data *aid, mblk_t *m, struct sockaddr_at *sat ) 328{ 329 struct aarplist *aal; 330 331 if ( sat->sat_addr.s_node == ATADDR_BCAST ) { 332 dl_unitdata_req( WR( aid->aid_q ), m, ETHERTYPE_AT, at_multicastaddr ); 333 return( 0 ); 334 } 335 336 if (( aal = aarp_alloc( aid, sat->sat_addr.s_net, sat->sat_addr.s_node )) == 337 NULL ) { 338 freemsg( m ); 339 return( ENOMEM ); 340 } 341 aal->aal_age = 0; 342 343 if ( aal->aal_flags ) { /* complete */ 344 dl_unitdata_req( WR( aid->aid_q ), m, ETHERTYPE_AT, aal->aal_hwaddr ); 345 } else { 346 /* send aarp request */ 347 if ( aal->aal_m != NULL ) { 348 freemsg( aal->aal_m ); 349 } 350 /* either freed above, in timeout, or sent in aarp_rput() */ 351 aal->aal_m = m; 352 aarp_send( aid, AARPOP_REQUEST, NULL, 353 sat->sat_addr.s_net, sat->sat_addr.s_node ); 354 } 355 return( 0 ); 356} 357