]> arthur.barton.de Git - netatalk.git/blob - sys/solaris/if.c
More Solaris cleanups for 64bit compatibility.
[netatalk.git] / sys / solaris / if.c
1 /* $Id: if.c,v 1.2 2002-01-17 07:11:13 srittau 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
35 static struct atif_data *interfaces = NULL;
36
37     struct atif_data *
38 if_primary()
39 {
40     return( interfaces );
41 }
42
43     struct atif_data *
44 if_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
64 if_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
93 if_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
121 if_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
139 if_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
166 if_pickaddr( struct atif_data *aid )
167 {
168     if ( aid->aid_c.c_type != SIOCSIFADDR ) {
169         cmn_err( CE_NOTE, "if_pickaddr context %x\n", aid->aid_c.c_type );
170         return;
171     }
172
173     if ( aid->aid_flags & AIDF_PROBEFAILED ) {
174         aid->aid_flags &= ~AIDF_PROBEFAILED;
175         /* choose new address */
176         for (;;) {
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;
188                 } else {
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;
194                     } else
195                       aid->aid_sat.sat_addr.s_net = 
196                         htons(ntohs(aid->aid_sat.sat_addr.s_net) + 1);
197                 }
198             } else {
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 ) {
204                     continue;
205                 }
206                 break;
207             }
208         }
209     }
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;
220         return;
221     }
222
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 );
226 }
227
228     int
229 if_setaddr( queue_t *q, mblk_t *m, char *name, struct sockaddr_at *sat )
230 {
231     struct atif_data    *aid;
232     struct netrange     nr;
233     ulong               time;
234
235     for ( aid = interfaces; aid != NULL; aid = aid->aid_next ) {
236         if ( strcmp( name, aid->aid_name ) == 0 ) {
237             break;
238         }
239     }
240     if ( aid == NULL ) {
241         return( EADDRNOTAVAIL );
242     }
243
244     if ( aid->aid_c.c_type != 0 ) {
245         cmn_err( CE_NOTE, "if_setaddr context %x\n", aid->aid_c.c_type );
246         return( EINVAL );
247     }
248
249     bcopy( sat->sat_zero, &nr, sizeof( struct netrange ));
250
251     if ( aid->aid_flags & AIDF_LOOPBACK ) {
252         aid->aid_sat = *sat;
253         aid->aid_nr = nr;
254
255         /* routes? */
256
257         ioc_ok_ack( q, m, 0 );
258         return( 0 );
259     }
260
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;
265         } else {
266             sat->sat_addr.s_net = htons(ntohs(nr.nr_firstnet) + time %
267                     (ntohs(nr.nr_lastnet) - ntohs(nr.nr_firstnet)));
268         }
269     } else {
270         if ( ntohs( sat->sat_addr.s_net ) < ntohs( nr.nr_firstnet ) ||
271                 ntohs( sat->sat_addr.s_net ) > ntohs( nr.nr_lastnet )) {
272             return( EINVAL );
273         }
274     }
275
276     if ( sat->sat_addr.s_node == ATADDR_ANYNODE ) {
277         sat->sat_addr.s_node = time;
278     }
279
280     aid->aid_flags |= AIDF_PROBING;
281     aid->aid_sat = *sat;
282     aid->aid_nr = nr;
283
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 );
292     return( 0 );
293 }
294
295 /*
296  * These three routines are all a big mess...
297  */
298     struct atif_data *
299 if_dest( struct atif_data *aid, struct sockaddr_at *sat )
300 {
301     struct atif_data    *dest;
302
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 )) {
311             break;
312         }
313     }
314     if ( dest == NULL ) {
315         return( NULL );
316     }
317     return( dest );
318 }
319
320     struct atif_data *
321 if_withaddr( struct sockaddr_at *sat )
322 {
323     struct atif_data    *dest;
324
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 ) {
328             break;
329         }
330     }
331     return( dest );
332 }
333
334     struct atif_data *
335 if_withnet( struct sockaddr_at *sat )
336 {
337     struct atif_data    *dest;
338
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)) {
342             break;
343         }
344     }
345     return( dest );
346 }
347
348     int
349 if_route( struct atif_data *aid, mblk_t *m, struct sockaddr_at *sat )
350 {
351     struct sockaddr_at  gate;
352
353     if ( sat->sat_addr.s_net == 0 ) {
354         if ( sat->sat_addr.s_node == 0 ) {
355             aid = if_withaddr( sat );
356         }
357         if ( aid == NULL ) {
358             freemsg( m );
359             return( ENETUNREACH );
360         }
361         gate = *sat;
362     } else {
363         if ( rt_gate( sat, &gate ) < 0 ) {      /* no route */
364             gate = *sat;
365         }
366         if (( aid = if_withaddr( &gate )) == NULL ) {
367             if (( aid = if_withnet( &gate )) == NULL ) {
368                 freemsg( m );
369                 return( ENETUNREACH );
370             }
371         }
372     }
373
374     if ( aid->aid_flags & AIDF_LOOPBACK ) {
375         return( ddp_rput( aid, m ));
376     } else {
377         /* the aarp layer is expected to send broadcast packets appropriately */
378         return( aarp_resolve( aid, m, &gate ));
379     }
380 }