1 /* $Id: if.c,v 1.2 2002-01-17 07:11:13 srittau 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( struct atif_data *aid )
168 if ( aid->aid_c.c_type != SIOCSIFADDR ) {
169 cmn_err( CE_NOTE, "if_pickaddr context %x\n", aid->aid_c.c_type );
173 if ( aid->aid_flags & AIDF_PROBEFAILED ) {
174 aid->aid_flags &= ~AIDF_PROBEFAILED;
175 /* choose new address */
177 if ( aid->aid_c.c_u.u_addr.ua_nodecnt == 0 ) {
178 /* if we've exausted all addresses, fail */
179 if ( aid->aid_c.c_u.u_addr.ua_netcnt == 0 ) {
180 ioc_error_ack( aid->aid_c.c_u.u_addr.ua_q,
181 aid->aid_c.c_u.u_addr.ua_m, EADDRINUSE );
182 aid->aid_c.c_type = 0;
183 aid->aid_c.c_u.u_addr.ua_q = NULL;
184 aid->aid_c.c_u.u_addr.ua_m = NULL;
185 aid->aid_c.c_u.u_addr.ua_probecnt = 0;
186 aid->aid_c.c_u.u_addr.ua_netcnt = 0;
187 aid->aid_c.c_u.u_addr.ua_nodecnt = 0;
189 aid->aid_c.c_u.u_addr.ua_nodecnt = 256;
190 aid->aid_c.c_u.u_addr.ua_netcnt--;
191 if ( ntohs(aid->aid_sat.sat_addr.s_net) >
192 ntohs(aid->aid_nr.nr_lastnet) ) {
193 aid->aid_sat.sat_addr.s_net = aid->aid_nr.nr_firstnet;
195 aid->aid_sat.sat_addr.s_net =
196 htons(ntohs(aid->aid_sat.sat_addr.s_net) + 1);
199 aid->aid_sat.sat_addr.s_node++;
200 aid->aid_c.c_u.u_addr.ua_nodecnt--;
201 if ( aid->aid_sat.sat_addr.s_node == 0 ||
202 aid->aid_sat.sat_addr.s_node == 255 ||
203 aid->aid_sat.sat_addr.s_node == 254 ) {
210 if ( aid->aid_c.c_u.u_addr.ua_probecnt-- <= 0 ) {
211 aid->aid_flags &= ~AIDF_PROBING;
212 /* worked, send ioctl reponse */
213 ioc_ok_ack( aid->aid_c.c_u.u_addr.ua_q, aid->aid_c.c_u.u_addr.ua_m, 0 );
214 aid->aid_c.c_type = 0;
215 aid->aid_c.c_u.u_addr.ua_q = NULL;
216 aid->aid_c.c_u.u_addr.ua_m = NULL;
217 aid->aid_c.c_u.u_addr.ua_probecnt = 0;
218 aid->aid_c.c_u.u_addr.ua_netcnt = 0;
219 aid->aid_c.c_u.u_addr.ua_nodecnt = 0;
223 aarp_send( aid, AARPOP_PROBE, NULL,
224 aid->aid_sat.sat_addr.s_net, aid->aid_sat.sat_addr.s_node );
225 qtimeout( aid->aid_q, if_pickaddr, (caddr_t)aid, hz / 5 );
229 if_setaddr( queue_t *q, mblk_t *m, char *name, struct sockaddr_at *sat )
231 struct atif_data *aid;
235 for ( aid = interfaces; aid != NULL; aid = aid->aid_next ) {
236 if ( strcmp( name, aid->aid_name ) == 0 ) {
241 return( EADDRNOTAVAIL );
244 if ( aid->aid_c.c_type != 0 ) {
245 cmn_err( CE_NOTE, "if_setaddr context %x\n", aid->aid_c.c_type );
249 bcopy( sat->sat_zero, &nr, sizeof( struct netrange ));
251 if ( aid->aid_flags & AIDF_LOOPBACK ) {
257 ioc_ok_ack( q, m, 0 );
261 drv_getparm( TIME, &time );
262 if ( sat->sat_addr.s_net == ATADDR_ANYNET ) {
263 if ( nr.nr_lastnet == nr.nr_firstnet ) {
264 sat->sat_addr.s_net = nr.nr_firstnet;
266 sat->sat_addr.s_net = htons(ntohs(nr.nr_firstnet) + time %
267 (ntohs(nr.nr_lastnet) - ntohs(nr.nr_firstnet)));
270 if ( ntohs( sat->sat_addr.s_net ) < ntohs( nr.nr_firstnet ) ||
271 ntohs( sat->sat_addr.s_net ) > ntohs( nr.nr_lastnet )) {
276 if ( sat->sat_addr.s_node == ATADDR_ANYNODE ) {
277 sat->sat_addr.s_node = time;
280 aid->aid_flags |= AIDF_PROBING;
284 aid->aid_c.c_type = SIOCSIFADDR;
285 aid->aid_c.c_u.u_addr.ua_q = q;
286 aid->aid_c.c_u.u_addr.ua_m = m;
287 aid->aid_c.c_u.u_addr.ua_probecnt = 10;
288 aid->aid_c.c_u.u_addr.ua_netcnt = ntohs(nr.nr_lastnet) -
289 ntohs(nr.nr_firstnet);
290 aid->aid_c.c_u.u_addr.ua_nodecnt = 256;
291 qtimeout( aid->aid_q, if_pickaddr, (caddr_t)aid, 0 );
296 * These three routines are all a big mess...
299 if_dest( struct atif_data *aid, struct sockaddr_at *sat )
301 struct atif_data *dest;
303 for ( dest = interfaces; dest != NULL; dest = dest->aid_next ) {
304 if ((( sat->sat_addr.s_net == 0 && aid == dest ) ||
305 ( ntohs(sat->sat_addr.s_net) >=
306 ntohs(dest->aid_nr.nr_firstnet) &&
307 ntohs(sat->sat_addr.s_net) <=
308 ntohs(dest->aid_nr.nr_lastnet) )) &&
309 ( sat->sat_addr.s_node == dest->aid_sat.sat_addr.s_node ||
310 sat->sat_addr.s_node == ATADDR_BCAST )) {
314 if ( dest == NULL ) {
321 if_withaddr( struct sockaddr_at *sat )
323 struct atif_data *dest;
325 for ( dest = interfaces; dest != NULL; dest = dest->aid_next ) {
326 if ( sat->sat_addr.s_net == dest->aid_sat.sat_addr.s_net &&
327 sat->sat_addr.s_node == dest->aid_sat.sat_addr.s_node ) {
335 if_withnet( struct sockaddr_at *sat )
337 struct atif_data *dest;
339 for ( dest = interfaces; dest != NULL; dest = dest->aid_next ) {
340 if ( ntohs(sat->sat_addr.s_net) >= ntohs(dest->aid_nr.nr_firstnet) &&
341 ntohs(sat->sat_addr.s_net) <= ntohs(dest->aid_nr.nr_lastnet)) {
349 if_route( struct atif_data *aid, mblk_t *m, struct sockaddr_at *sat )
351 struct sockaddr_at gate;
353 if ( sat->sat_addr.s_net == 0 ) {
354 if ( sat->sat_addr.s_node == 0 ) {
355 aid = if_withaddr( sat );
359 return( ENETUNREACH );
363 if ( rt_gate( sat, &gate ) < 0 ) { /* no route */
366 if (( aid = if_withaddr( &gate )) == NULL ) {
367 if (( aid = if_withnet( &gate )) == NULL ) {
369 return( ENETUNREACH );
374 if ( aid->aid_flags & AIDF_LOOPBACK ) {
375 return( ddp_rput( aid, m ));
377 /* the aarp layer is expected to send broadcast packets appropriately */
378 return( aarp_resolve( aid, m, &gate ));