1 /* $Id: if.c,v 1.3 2005-04-28 20:50:07 bfernhomberg Exp $
6 #endif /* HAVE_CONFIG_H */
9 #include <sys/socket.h>
10 #include <sys/sockio.h>
11 #include <sys/stream.h>
14 #include <sys/cmn_err.h>
15 #include <sys/errno.h>
16 #include <sys/byteorder.h>
17 #include <sys/ethernet.h>
20 #include <netinet/arp.h>
28 #include <netatalk/at.h>
29 #include <netatalk/aarp.h>
35 static struct atif_data *interfaces = NULL;
44 if_alloc( queue_t *q )
46 struct atif_data *aid;
48 if (( aid = kmem_zalloc( sizeof( struct atif_data ), KM_SLEEP )) == NULL ) {
52 aid->aid_state = DL_UNATTACHED;
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.
64 if_name( struct atif_data *aid, char *name, ulong ppa )
66 sprintf( aid->aid_name, "%s%ld", name, ppa );
68 if ( interfaces == NULL ) { /* create fake loopback */
69 if (( interfaces = if_alloc( NULL )) == NULL ) {
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;
78 aid->aid_next = interfaces;
79 aid->aid_next->aid_prev = aid;
82 aid->aid_next = interfaces->aid_next;
83 aid->aid_prev = interfaces;
84 aid->aid_next->aid_prev = aid;
85 interfaces->aid_next = aid;
93 if_free( struct atif_data *aid )
95 if ( aid->aid_c.c_type != 0 ) {
96 cmn_err( CE_NOTE, "if_free context %x\n", aid->aid_c.c_type );
102 if ( aid->aid_next != NULL ) {
103 aid->aid_next->aid_prev = aid->aid_prev;
105 if ( aid->aid_prev != NULL ) {
106 aid->aid_prev->aid_next = aid->aid_next;
108 if ( aid == interfaces ) {
109 interfaces = aid->aid_next;
111 kmem_free( aid, sizeof( struct atif_data ));
113 if ( interfaces != NULL && interfaces->aid_next == NULL ) {
114 kmem_free( interfaces, sizeof( struct atif_data ));
121 if_getaddr( char *name, struct sockaddr_at *sat )
123 struct atif_data *aid;
125 for ( aid = interfaces; aid != NULL; aid = aid->aid_next ) {
126 if ( strcmp( name, aid->aid_name ) == 0 ) {
131 return( EADDRNOTAVAIL );
134 bcopy( &aid->aid_sat, sat, sizeof( struct sockaddr_at ));
139 if_addmulti( queue_t *q, mblk_t *m, char *name, struct sockaddr *sa )
141 struct atif_data *aid;
143 for ( aid = interfaces; aid != NULL; aid = aid->aid_next ) {
144 if ( strcmp( name, aid->aid_name ) == 0 ) {
149 return( EADDRNOTAVAIL );
152 if ( aid->aid_c.c_type != 0 ) {
153 cmn_err( CE_NOTE, "if_addmulti context %x\n", aid->aid_c.c_type );
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 );
166 if_pickaddr( void *ptr )
168 struct atif_data *aid = (struct atif_data*) ptr;
170 if ( aid->aid_c.c_type != SIOCSIFADDR ) {
171 cmn_err( CE_NOTE, "if_pickaddr context %x\n", aid->aid_c.c_type );
175 if ( aid->aid_flags & AIDF_PROBEFAILED ) {
176 aid->aid_flags &= ~AIDF_PROBEFAILED;
177 /* choose new address */
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;
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;
197 aid->aid_sat.sat_addr.s_net =
198 htons(ntohs(aid->aid_sat.sat_addr.s_net) + 1);
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 ) {
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;
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 );
231 if_setaddr( queue_t *q, mblk_t *m, char *name, struct sockaddr_at *sat )
233 struct atif_data *aid;
237 for ( aid = interfaces; aid != NULL; aid = aid->aid_next ) {
238 if ( strcmp( name, aid->aid_name ) == 0 ) {
243 return( EADDRNOTAVAIL );
246 if ( aid->aid_c.c_type != 0 ) {
247 cmn_err( CE_NOTE, "if_setaddr context %x\n", aid->aid_c.c_type );
251 bcopy( sat->sat_zero, &nr, sizeof( struct netrange ));
253 if ( aid->aid_flags & AIDF_LOOPBACK ) {
259 ioc_ok_ack( q, m, 0 );
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;
268 sat->sat_addr.s_net = htons(ntohs(nr.nr_firstnet) + time %
269 (ntohs(nr.nr_lastnet) - ntohs(nr.nr_firstnet)));
272 if ( ntohs( sat->sat_addr.s_net ) < ntohs( nr.nr_firstnet ) ||
273 ntohs( sat->sat_addr.s_net ) > ntohs( nr.nr_lastnet )) {
278 if ( sat->sat_addr.s_node == ATADDR_ANYNODE ) {
279 sat->sat_addr.s_node = time;
282 aid->aid_flags |= AIDF_PROBING;
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 );
298 * These three routines are all a big mess...
301 if_dest( struct atif_data *aid, struct sockaddr_at *sat )
303 struct atif_data *dest;
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 )) {
316 if ( dest == NULL ) {
323 if_withaddr( struct sockaddr_at *sat )
325 struct atif_data *dest;
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 ) {
337 if_withnet( struct sockaddr_at *sat )
339 struct atif_data *dest;
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)) {
351 if_route( struct atif_data *aid, mblk_t *m, struct sockaddr_at *sat )
353 struct sockaddr_at gate;
355 if ( sat->sat_addr.s_net == 0 ) {
356 if ( sat->sat_addr.s_node == 0 ) {
357 aid = if_withaddr( sat );
361 return( ENETUNREACH );
365 if ( rt_gate( sat, &gate ) < 0 ) { /* no route */
368 if (( aid = if_withaddr( &gate )) == NULL ) {
369 if (( aid = if_withnet( &gate )) == NULL ) {
371 return( ENETUNREACH );
376 if ( aid->aid_flags & AIDF_LOOPBACK ) {
377 return( ddp_rput( aid, m ));
379 /* the aarp layer is expected to send broadcast packets appropriately */
380 return( aarp_resolve( aid, m, &gate ));