1/* $Id: if.c,v 1.3 2005-04-28 20:50:07 bfernhomberg Exp $ 2 */ 3 4#ifdef HAVE_CONFIG_H 5#include "config.h" 6#endif /* HAVE_CONFIG_H */ 7 8#include <sys/types.h> 9#include <sys/socket.h> 10#include <sys/sockio.h> 11#include <sys/stream.h> 12#include <sys/kmem.h> 13#include <sys/dlpi.h> 14#include <sys/cmn_err.h> 15#include <sys/errno.h> 16#include <sys/byteorder.h> 17#include <sys/ethernet.h> 18#include <sys/ddi.h> 19#include <net/if.h> 20#include <netinet/arp.h> 21 22#ifdef STDC_HEADERS 23#include <strings.h> 24#else 25#include <string.h> 26#endif 27 28#include <netatalk/at.h> 29#include <netatalk/aarp.h> 30 31#include "if.h" 32#include "rt.h" 33#include "ioc.h" 34 35static struct atif_data *interfaces = NULL; 36 37 struct atif_data * 38if_primary() 39{ 40 return( interfaces ); 41} 42 43 struct atif_data * 44if_alloc( queue_t *q ) 45{ 46 struct atif_data *aid; 47 48 if (( aid = kmem_zalloc( sizeof( struct atif_data ), KM_SLEEP )) == NULL ) { 49 return( NULL ); 50 } 51 aid->aid_q = q; 52 aid->aid_state = DL_UNATTACHED; 53 54 return( aid ); 55} 56 57/* 58 * Name an interface, insert it in our list of interfaces. If this is the 59 * first interface, create the loopback interface. If it's not the first 60 * interfaces, keep the first interface the same, i.e. the first configured 61 * interface should be the primary interface. 62 */ 63 int 64if_name( struct atif_data *aid, char *name, ulong ppa ) 65{ 66 sprintf( aid->aid_name, "%s%ld", name, ppa ); 67 68 if ( interfaces == NULL ) { /* create fake loopback */ 69 if (( interfaces = if_alloc( NULL )) == NULL ) { 70 return( ENOMEM ); 71 } 72 strcpy( interfaces->aid_name, "lo0" ); 73 interfaces->aid_state = DL_IDLE; 74 bzero( interfaces->aid_hwaddr, sizeof( interfaces->aid_hwaddr )); 75 interfaces->aid_flags = AIDF_LOOPBACK; 76 interfaces->aid_c.c_type = 0; 77 78 aid->aid_next = interfaces; 79 aid->aid_next->aid_prev = aid; 80 interfaces = aid; 81 } else { 82 aid->aid_next = interfaces->aid_next; 83 aid->aid_prev = interfaces; 84 aid->aid_next->aid_prev = aid; 85 interfaces->aid_next = aid; 86 } 87 88 aarp_init( aid ); 89 return( 0 ); 90} 91 92 void 93if_free( struct atif_data *aid ) 94{ 95 if ( aid->aid_c.c_type != 0 ) { 96 cmn_err( CE_NOTE, "if_free context %x\n", aid->aid_c.c_type ); 97 return; 98 } 99 100 aarp_clean( aid ); 101 102 if ( aid->aid_next != NULL ) { 103 aid->aid_next->aid_prev = aid->aid_prev; 104 } 105 if ( aid->aid_prev != NULL ) { 106 aid->aid_prev->aid_next = aid->aid_next; 107 } 108 if ( aid == interfaces ) { 109 interfaces = aid->aid_next; 110 } 111 kmem_free( aid, sizeof( struct atif_data )); 112 113 if ( interfaces != NULL && interfaces->aid_next == NULL ) { 114 kmem_free( interfaces, sizeof( struct atif_data )); 115 interfaces = NULL; 116 } 117 return; 118} 119 120 int 121if_getaddr( char *name, struct sockaddr_at *sat ) 122{ 123 struct atif_data *aid; 124 125 for ( aid = interfaces; aid != NULL; aid = aid->aid_next ) { 126 if ( strcmp( name, aid->aid_name ) == 0 ) { 127 break; 128 } 129 } 130 if ( aid == NULL ) { 131 return( EADDRNOTAVAIL ); 132 } 133 134 bcopy( &aid->aid_sat, sat, sizeof( struct sockaddr_at )); 135 return( 0 ); 136} 137 138 int 139if_addmulti( queue_t *q, mblk_t *m, char *name, struct sockaddr *sa ) 140{ 141 struct atif_data *aid; 142 143 for ( aid = interfaces; aid != NULL; aid = aid->aid_next ) { 144 if ( strcmp( name, aid->aid_name ) == 0 ) { 145 break; 146 } 147 } 148 if ( aid == NULL ) { 149 return( EADDRNOTAVAIL ); 150 } 151 152 if ( aid->aid_c.c_type != 0 ) { 153 cmn_err( CE_NOTE, "if_addmulti context %x\n", aid->aid_c.c_type ); 154 return( EINVAL ); 155 } 156 157 aid->aid_c.c_type = SIOCADDMULTI; 158 aid->aid_c.c_u.u_multi.um_q = q; 159 aid->aid_c.c_u.u_multi.um_m = m; 160 dl_enabmulti_req( WR( aid->aid_q ), sa->sa_data ); 161 162 return( 0 ); 163} 164 165 void 166if_pickaddr( void *ptr ) 167{ 168 struct atif_data *aid = (struct atif_data*) ptr; 169 170 if ( aid->aid_c.c_type != SIOCSIFADDR ) { 171 cmn_err( CE_NOTE, "if_pickaddr context %x\n", aid->aid_c.c_type ); 172 return; 173 } 174 175 if ( aid->aid_flags & AIDF_PROBEFAILED ) { 176 aid->aid_flags &= ~AIDF_PROBEFAILED; 177 /* choose new address */ 178 for (;;) { 179 if ( aid->aid_c.c_u.u_addr.ua_nodecnt == 0 ) { 180 /* if we've exausted all addresses, fail */ 181 if ( aid->aid_c.c_u.u_addr.ua_netcnt == 0 ) { 182 ioc_error_ack( aid->aid_c.c_u.u_addr.ua_q, 183 aid->aid_c.c_u.u_addr.ua_m, EADDRINUSE ); 184 aid->aid_c.c_type = 0; 185 aid->aid_c.c_u.u_addr.ua_q = NULL; 186 aid->aid_c.c_u.u_addr.ua_m = NULL; 187 aid->aid_c.c_u.u_addr.ua_probecnt = 0; 188 aid->aid_c.c_u.u_addr.ua_netcnt = 0; 189 aid->aid_c.c_u.u_addr.ua_nodecnt = 0; 190 } else { 191 aid->aid_c.c_u.u_addr.ua_nodecnt = 256; 192 aid->aid_c.c_u.u_addr.ua_netcnt--; 193 if ( ntohs(aid->aid_sat.sat_addr.s_net) > 194 ntohs(aid->aid_nr.nr_lastnet) ) { 195 aid->aid_sat.sat_addr.s_net = aid->aid_nr.nr_firstnet; 196 } else 197 aid->aid_sat.sat_addr.s_net = 198 htons(ntohs(aid->aid_sat.sat_addr.s_net) + 1); 199 } 200 } else { 201 aid->aid_sat.sat_addr.s_node++; 202 aid->aid_c.c_u.u_addr.ua_nodecnt--; 203 if ( aid->aid_sat.sat_addr.s_node == 0 || 204 aid->aid_sat.sat_addr.s_node == 255 || 205 aid->aid_sat.sat_addr.s_node == 254 ) { 206 continue; 207 } 208 break; 209 } 210 } 211 } 212 if ( aid->aid_c.c_u.u_addr.ua_probecnt-- <= 0 ) { 213 aid->aid_flags &= ~AIDF_PROBING; 214 /* worked, send ioctl reponse */ 215 ioc_ok_ack( aid->aid_c.c_u.u_addr.ua_q, aid->aid_c.c_u.u_addr.ua_m, 0 ); 216 aid->aid_c.c_type = 0; 217 aid->aid_c.c_u.u_addr.ua_q = NULL; 218 aid->aid_c.c_u.u_addr.ua_m = NULL; 219 aid->aid_c.c_u.u_addr.ua_probecnt = 0; 220 aid->aid_c.c_u.u_addr.ua_netcnt = 0; 221 aid->aid_c.c_u.u_addr.ua_nodecnt = 0; 222 return; 223 } 224 225 aarp_send( aid, AARPOP_PROBE, NULL, 226 aid->aid_sat.sat_addr.s_net, aid->aid_sat.sat_addr.s_node ); 227 qtimeout( aid->aid_q, if_pickaddr, (caddr_t)aid, hz / 5 ); 228} 229 230 int 231if_setaddr( queue_t *q, mblk_t *m, char *name, struct sockaddr_at *sat ) 232{ 233 struct atif_data *aid; 234 struct netrange nr; 235 ulong time; 236 237 for ( aid = interfaces; aid != NULL; aid = aid->aid_next ) { 238 if ( strcmp( name, aid->aid_name ) == 0 ) { 239 break; 240 } 241 } 242 if ( aid == NULL ) { 243 return( EADDRNOTAVAIL ); 244 } 245 246 if ( aid->aid_c.c_type != 0 ) { 247 cmn_err( CE_NOTE, "if_setaddr context %x\n", aid->aid_c.c_type ); 248 return( EINVAL ); 249 } 250 251 bcopy( sat->sat_zero, &nr, sizeof( struct netrange )); 252 253 if ( aid->aid_flags & AIDF_LOOPBACK ) { 254 aid->aid_sat = *sat; 255 aid->aid_nr = nr; 256 257 /* routes? */ 258 259 ioc_ok_ack( q, m, 0 ); 260 return( 0 ); 261 } 262 263 drv_getparm( TIME, &time ); 264 if ( sat->sat_addr.s_net == ATADDR_ANYNET ) { 265 if ( nr.nr_lastnet == nr.nr_firstnet ) { 266 sat->sat_addr.s_net = nr.nr_firstnet; 267 } else { 268 sat->sat_addr.s_net = htons(ntohs(nr.nr_firstnet) + time % 269 (ntohs(nr.nr_lastnet) - ntohs(nr.nr_firstnet))); 270 } 271 } else { 272 if ( ntohs( sat->sat_addr.s_net ) < ntohs( nr.nr_firstnet ) || 273 ntohs( sat->sat_addr.s_net ) > ntohs( nr.nr_lastnet )) { 274 return( EINVAL ); 275 } 276 } 277 278 if ( sat->sat_addr.s_node == ATADDR_ANYNODE ) { 279 sat->sat_addr.s_node = time; 280 } 281 282 aid->aid_flags |= AIDF_PROBING; 283 aid->aid_sat = *sat; 284 aid->aid_nr = nr; 285 286 aid->aid_c.c_type = SIOCSIFADDR; 287 aid->aid_c.c_u.u_addr.ua_q = q; 288 aid->aid_c.c_u.u_addr.ua_m = m; 289 aid->aid_c.c_u.u_addr.ua_probecnt = 10; 290 aid->aid_c.c_u.u_addr.ua_netcnt = ntohs(nr.nr_lastnet) - 291 ntohs(nr.nr_firstnet); 292 aid->aid_c.c_u.u_addr.ua_nodecnt = 256; 293 qtimeout( aid->aid_q, if_pickaddr, (caddr_t)aid, 0 ); 294 return( 0 ); 295} 296 297/* 298 * These three routines are all a big mess... 299 */ 300 struct atif_data * 301if_dest( struct atif_data *aid, struct sockaddr_at *sat ) 302{ 303 struct atif_data *dest; 304 305 for ( dest = interfaces; dest != NULL; dest = dest->aid_next ) { 306 if ((( sat->sat_addr.s_net == 0 && aid == dest ) || 307 ( ntohs(sat->sat_addr.s_net) >= 308 ntohs(dest->aid_nr.nr_firstnet) && 309 ntohs(sat->sat_addr.s_net) <= 310 ntohs(dest->aid_nr.nr_lastnet) )) && 311 ( sat->sat_addr.s_node == dest->aid_sat.sat_addr.s_node || 312 sat->sat_addr.s_node == ATADDR_BCAST )) { 313 break; 314 } 315 } 316 if ( dest == NULL ) { 317 return( NULL ); 318 } 319 return( dest ); 320} 321 322 struct atif_data * 323if_withaddr( struct sockaddr_at *sat ) 324{ 325 struct atif_data *dest; 326 327 for ( dest = interfaces; dest != NULL; dest = dest->aid_next ) { 328 if ( sat->sat_addr.s_net == dest->aid_sat.sat_addr.s_net && 329 sat->sat_addr.s_node == dest->aid_sat.sat_addr.s_node ) { 330 break; 331 } 332 } 333 return( dest ); 334} 335 336 struct atif_data * 337if_withnet( struct sockaddr_at *sat ) 338{ 339 struct atif_data *dest; 340 341 for ( dest = interfaces; dest != NULL; dest = dest->aid_next ) { 342 if ( ntohs(sat->sat_addr.s_net) >= ntohs(dest->aid_nr.nr_firstnet) && 343 ntohs(sat->sat_addr.s_net) <= ntohs(dest->aid_nr.nr_lastnet)) { 344 break; 345 } 346 } 347 return( dest ); 348} 349 350 int 351if_route( struct atif_data *aid, mblk_t *m, struct sockaddr_at *sat ) 352{ 353 struct sockaddr_at gate; 354 355 if ( sat->sat_addr.s_net == 0 ) { 356 if ( sat->sat_addr.s_node == 0 ) { 357 aid = if_withaddr( sat ); 358 } 359 if ( aid == NULL ) { 360 freemsg( m ); 361 return( ENETUNREACH ); 362 } 363 gate = *sat; 364 } else { 365 if ( rt_gate( sat, &gate ) < 0 ) { /* no route */ 366 gate = *sat; 367 } 368 if (( aid = if_withaddr( &gate )) == NULL ) { 369 if (( aid = if_withnet( &gate )) == NULL ) { 370 freemsg( m ); 371 return( ENETUNREACH ); 372 } 373 } 374 } 375 376 if ( aid->aid_flags & AIDF_LOOPBACK ) { 377 return( ddp_rput( aid, m )); 378 } else { 379 /* the aarp layer is expected to send broadcast packets appropriately */ 380 return( aarp_resolve( aid, m, &gate )); 381 } 382} 383