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