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