~ubuntu-branches/ubuntu/precise/netatalk/precise

« back to all changes in this revision

Viewing changes to sys/sunos/at_sun.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Rittau
  • Date: 2004-01-19 12:43:49 UTC
  • Revision ID: james.westby@ubuntu.com-20040119124349-es563jbp0hk0ae51
Tags: upstream-1.6.4
ImportĀ upstreamĀ versionĀ 1.6.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: at_sun.c,v 1.2 2001/08/06 13:39:30 rufustfirefly Exp $
 
3
 */
 
4
 
 
5
#include <sys/param.h>
 
6
#include <sys/types.h>
 
7
#include <sys/socket.h>
 
8
#include <sys/mbuf.h>
 
9
#include <sys/protosw.h>
 
10
#include <sys/domain.h>
 
11
#include <sys/errno.h>
 
12
 
 
13
#include <net/if_arp.h>
 
14
#include <net/if.h>
 
15
#include <net/route.h>
 
16
#include <net/af.h>
 
17
#include <net/netisr.h>
 
18
 
 
19
#include <sun/vddrv.h>
 
20
 
 
21
#include <netinet/in.h>
 
22
#undef s_net
 
23
#include <netinet/if_ether.h>
 
24
 
 
25
#include <netatalk/at.h>
 
26
#include <netatalk/at_var.h>
 
27
#include <netatalk/ddp_var.h>
 
28
#include <netatalk/phase2.h>
 
29
 
 
30
struct vdlat {
 
31
    int         vda_magic;
 
32
    char        *vda_name;
 
33
}       atvdl = {
 
34
    VDMAGIC_USER, "netatalk"
 
35
};
 
36
 
 
37
struct ifqueue  *atef_input();
 
38
int             atef_output();
 
39
extern int      atintr();
 
40
 
 
41
extern u_char   aarp_org_code[ 3 ];
 
42
extern u_char   at_org_code[ 3 ];
 
43
 
 
44
/*
 
45
 * Entries in this table are inserted into the ether_families linked
 
46
 * list at the beginnning. As such, they will be searched by the input
 
47
 * and output routines opposite to the order here.
 
48
 *
 
49
 * In order to do both phase 1 and phase 2 during output, we have a
 
50
 * special entry (the AF_APPLETALK entry) whose ethertype field is
 
51
 * changed by the output function, to reflect the actual link layer
 
52
 * to be used. This ether_family entry is never seen during Ethernet
 
53
 * input, since the earlier entry captures all packets (it is seen
 
54
 * during loopback input, in that the input function is called directly
 
55
 * on loopback output).
 
56
 */
 
57
struct ether_family     ether_atalk[] = {
 
58
    {
 
59
        AF_APPLETALK,   0,      /* Changed by atef_output() */
 
60
        atef_input,     atef_output,    atintr,
 
61
    },
 
62
    {
 
63
        0,              ETHERTYPE_AARP,
 
64
        atef_input,     0,              0,
 
65
    },
 
66
    {
 
67
        0,              ETHERTYPE_AT,
 
68
        atef_input,     0,              atintr,
 
69
    },
 
70
    {
 
71
        0,              EF_8023_TYPE,
 
72
        atef_input,     0,              atintr,
 
73
    },
 
74
};
 
75
int     ether_atalkN = sizeof( ether_atalk ) / sizeof( ether_atalk[ 0 ] );
 
76
 
 
77
extern struct ether_family      *ether_families;
 
78
 
 
79
extern int                      atalk_hash(), atalk_netmatch();
 
80
extern int                      null_hash(), null_netmatch();
 
81
 
 
82
xxxinit( cmd, vdd, vdi, vds )
 
83
    unsigned int        cmd;
 
84
    struct vddrv        *vdd;
 
85
    addr_t              vdi;
 
86
    struct vdstat       *vds;
 
87
{
 
88
    struct ether_family *ef;
 
89
    struct domain       *dom;
 
90
    struct protosw      *pr;
 
91
    int                 i;
 
92
 
 
93
    switch( cmd ) {
 
94
        case VDLOAD :
 
95
            vdd->vdd_vdtab = (struct vdlinkage *)&atvdl;
 
96
 
 
97
            /*
 
98
             * Register with the network-interface layer (ethernet).
 
99
             */
 
100
            for ( i = 0; i < ether_atalkN; i++ ) {
 
101
                ether_register( &ether_atalk[ i ] );
 
102
            }
 
103
 
 
104
            /*
 
105
             * Register with the socket layer.
 
106
             */
 
107
            atalkdomain.dom_next = domains;
 
108
            domains = &atalkdomain;
 
109
            if ( atalkdomain.dom_init ) {
 
110
                (*atalkdomain.dom_init)();
 
111
            }
 
112
            for ( pr = atalkdomain.dom_protosw;
 
113
                    pr < atalkdomain.dom_protoswNPROTOSW; pr++ ) {
 
114
                if ( pr->pr_init ) {
 
115
                    (*pr->pr_init)();
 
116
                }
 
117
            }
 
118
 
 
119
            /*
 
120
             * Cobble ourselves into the routing table.
 
121
             */
 
122
            afswitch[ AF_APPLETALK ].af_hash = atalk_hash;
 
123
            afswitch[ AF_APPLETALK ].af_netmatch = atalk_netmatch;
 
124
            return( 0 );
 
125
 
 
126
        case VDUNLOAD :
 
127
            /*
 
128
             * Make sure that there are no open appletalk sockets.
 
129
             */
 
130
            if ( ddpcb != NULL ) {
 
131
                return( EMFILE );
 
132
            }
 
133
 
 
134
            /*
 
135
             * There is no ether_unregister(), so we'll have to do it
 
136
             * our selves...
 
137
             */
 
138
            for ( i = 0; i < ether_atalkN; i++ ) {
 
139
                if ( ether_families == &ether_atalk[ i ] ) {
 
140
                    ether_families = ether_families->ef_next;
 
141
                    continue;
 
142
                } else {
 
143
                    for ( ef = ether_families; ef->ef_next; ef = ef->ef_next ) {
 
144
                        if ( ef->ef_next == &ether_atalk[ i ] ) {
 
145
                            ef->ef_next = ef->ef_next->ef_next;
 
146
                            break;
 
147
                        }
 
148
                    }
 
149
                }
 
150
            }
 
151
 
 
152
            /*
 
153
             * Remove aarp timers and held packets.
 
154
             */
 
155
            aarp_clean();
 
156
 
 
157
            /*
 
158
             * Remove AppleTalk interface addresses.
 
159
             */
 
160
            aa_clean();
 
161
 
 
162
            /*
 
163
             * Remove our routines from the routing table.
 
164
             */
 
165
            afswitch[ AF_APPLETALK ].af_hash = null_hash;
 
166
            afswitch[ AF_APPLETALK ].af_netmatch = null_netmatch;
 
167
 
 
168
            /*
 
169
             * Remove atalkdomain from the domains list.
 
170
             * Unlikely, but someone may have registered after us.
 
171
             */
 
172
            if ( domains == &atalkdomain ) {
 
173
                domains = domains->dom_next;
 
174
            } else {
 
175
                for ( dom = domains; dom->dom_next; dom = dom->dom_next ) {
 
176
                    if ( dom->dom_next == &atalkdomain ) {
 
177
                        dom->dom_next = dom->dom_next->dom_next;
 
178
                        break;
 
179
                    }
 
180
                }
 
181
            }
 
182
            return( 0 );
 
183
 
 
184
        case VDSTAT :
 
185
            return( 0 );
 
186
        default :
 
187
            return( EIO );
 
188
    }
 
189
}
 
190
 
 
191
/*
 
192
 * Input routine for netatalk on suns.  There are five possible
 
193
 * packets.  First, packets received on the loopback interface
 
194
 * are immediately sent to the phase 1 interrupt queue (this will
 
195
 * have to change if we ever do a phase 2 only version).  Second,
 
196
 * IEEE802 packet are sent to either the aarpinput() routine or
 
197
 * the phase 2 interrupt queue.  Finally, DIX packets are sent
 
198
 * to either aarpinput() or the phase 1 interrupt queue.
 
199
 */
 
200
    struct ifqueue *
 
201
atef_input( ifp, m, header )
 
202
    struct ifnet        *ifp;
 
203
    struct mbuf         *m;
 
204
    struct ether_header *header;
 
205
{
 
206
    struct llc          llc;
 
207
    struct mbuf         *n = 0;
 
208
 
 
209
    /*
 
210
     * Check first for LOOPBACK flag, since loopback code passes NULL for
 
211
     * the header.
 
212
     */
 
213
    if ( ifp->if_flags & IFF_LOOPBACK ) {
 
214
        return( &atintrq2 );
 
215
    }
 
216
 
 
217
    /*
 
218
     * Before SunOS 4.1, the ether_type was passed as is from the
 
219
     * packet.  After SunOS 4.1, the ether_type is swapped in
 
220
     * do_protocol(), before the ether_family routines are called.
 
221
     */
 
222
#if defined( sun ) && defined( i386 )
 
223
    header->ether_type = ntohs( header->ether_type );
 
224
#endif /* sun i386 */
 
225
 
 
226
    if ( header->ether_type <= ETHERMTU ) {     /* IEEE802 */
 
227
        /*
 
228
         * We need to remove the interface pointer from the beginning of this
 
229
         * packet.  We can't always use IF_ADJ(), since it can (and will,
 
230
         * very often) MFREE() the first mbuf in our chain.  If IF_ADJ()
 
231
         * would free the first mbuf, we just advance our pointer to the
 
232
         * next mbuf.  Since our calling routine passes m by value, we're
 
233
         * not actually losing m.  Later, we don't need to put the interface
 
234
         * pointer back on, since the caller still has it in its copy of m.
 
235
         */
 
236
        if ( m->m_len == sizeof( struct ifnet * )) {
 
237
            n = m;
 
238
            m = m->m_next;
 
239
        } else {
 
240
            IF_ADJ( m );
 
241
        }
 
242
 
 
243
        /*
 
244
         * We can't call m_pullup(), since we need to preserve
 
245
         * the value of m.
 
246
         */
 
247
        if ( m->m_len < sizeof( struct llc )) {
 
248
printf( "atef_input size llc\n" );
 
249
            ( n ) ? m_freem( n ) : m_freem( m );
 
250
            return( 0 );
 
251
        }
 
252
        bcopy( mtod( m, caddr_t ), &llc, sizeof( struct llc ));
 
253
        if ( llc.llc_dsap != LLC_SNAP_LSAP || llc.llc_ssap != LLC_SNAP_LSAP ||
 
254
                llc.llc_control != LLC_UI ) {
 
255
            ( n ) ? m_freem( n ) : m_freem( m );
 
256
            return( 0 );
 
257
        }
 
258
 
 
259
        /*
 
260
         * See IF_ADJ() above.  Here we prepend ifp to the mbuf chain.  If we
 
261
         * didn't remove it earlier, we don't replace it here.
 
262
         */
 
263
        if ( n ) {
 
264
            m_adj( m, sizeof( struct llc ));
 
265
        } else {
 
266
            m_adj( m, sizeof( struct llc ) - sizeof( struct ifnet *));
 
267
            if ( m->m_len < sizeof( struct ifnet * )) {
 
268
printf( "atef_input too small!\n" );
 
269
                m_freem( m );
 
270
                return( 0 );
 
271
            }
 
272
            *mtod( m, struct ifnet ** ) = ifp;
 
273
        }
 
274
 
 
275
        if ( ntohs( llc.llc_ether_type ) == ETHERTYPE_AT &&
 
276
                bcmp( llc.llc_org_code, at_org_code,
 
277
                sizeof( at_org_code )) == 0 ) {
 
278
            return( &atintrq2 );
 
279
        }
 
280
 
 
281
        /* do we really want to pass m, here?  what happened to n? XXX */
 
282
        if ( ntohs( llc.llc_ether_type ) == ETHERTYPE_AARP &&
 
283
                bcmp( llc.llc_org_code, aarp_org_code,
 
284
                sizeof( aarp_org_code )) == 0 ) {
 
285
            aarpinput( ifp, n ? n : m );
 
286
            return( 0 );
 
287
        }
 
288
 
 
289
    } else {                                    /* DIX */
 
290
        switch ( header->ether_type ) {
 
291
        case ETHERTYPE_AT :
 
292
            return( &atintrq1 );
 
293
 
 
294
        case ETHERTYPE_AARP :
 
295
            aarpinput( ifp, m );
 
296
            return( 0 );
 
297
        }
 
298
    }
 
299
 
 
300
    ( n ) ? m_freem( n ) : m_freem( m );
 
301
    return( 0 );
 
302
}
 
303
 
 
304
/*
 
305
 * If the destination is on a 802.3 wire, do phase 2 encapsulation,
 
306
 * adding the 802.2 and SNAP headers.  Always fill in the edst with the
 
307
 * ethernet address of the destination.
 
308
 */
 
309
atef_output( dst, m, ifp, edst )
 
310
    struct sockaddr_at  *dst;
 
311
    struct mbuf         *m;
 
312
    struct ifnet        *ifp;
 
313
    struct ether_addr   *edst;
 
314
{
 
315
    struct at_ifaddr    *aa;
 
316
    struct mbuf         *m0;
 
317
    struct llc          llc;
 
318
    int                 s;
 
319
 
 
320
    s = splimp();
 
321
    if ( !aarpresolve( ifp, m, dst, edst )) {
 
322
        (void) splx( s );
 
323
        return( 1 );
 
324
    }
 
325
    (void) splx( s );
 
326
 
 
327
    /*
 
328
     * ifaddr is the first thing in at_ifaddr
 
329
     */
 
330
    if (( aa = (struct at_ifaddr *)at_ifawithnet( dst, ifp->if_addrlist ))
 
331
            == 0 ) {
 
332
        m_freem( m );
 
333
        return( 1 );
 
334
    }
 
335
 
 
336
    /*
 
337
     * In the phase 2 case, we need to prepend an mbuf for the llc header.
 
338
     * Since we must preserve the value of m, which is passed to us by
 
339
     * value, we m_copy() the first mbuf, and use it for our llc header.
 
340
     *
 
341
     * We could worry about leaving space for the ether header, but
 
342
     * since we'll have to go through all sorts of hoops, including a
 
343
     * possibly large copy, there's really no sense.
 
344
     */
 
345
    if ( aa->aa_flags & AFA_PHASE2 ) {
 
346
        if ( M_HASCL( m ) || m->m_off - MMINOFF < sizeof( struct llc )) {
 
347
            if (( m0 = m_copy( m, 0, m->m_len )) == 0 ) {
 
348
                m_freem( m );
 
349
                return( 1 );
 
350
            }
 
351
            if ( M_HASCL( m )) {        /* m is a cluster */
 
352
                int s = splimp();
 
353
 
 
354
                mclput( m );
 
355
                splx( s );
 
356
            }
 
357
 
 
358
            m0->m_next = m->m_next;
 
359
            m->m_next = m0;
 
360
            m->m_off = MMAXOFF - sizeof( struct llc );
 
361
            m->m_len = sizeof( struct llc );
 
362
        } else {
 
363
            m->m_off -= sizeof( struct llc );
 
364
            m->m_len += sizeof( struct llc );
 
365
        }
 
366
 
 
367
        llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP;
 
368
        llc.llc_control = LLC_UI;
 
369
        bcopy( at_org_code, llc.llc_org_code, sizeof( at_org_code ));
 
370
        llc.llc_ether_type = htons( ETHERTYPE_AT );
 
371
        bcopy( &llc, mtod( m, caddr_t ), sizeof( struct llc ));
 
372
        ether_atalk[ 0 ].ef_ethertype = EF_8023_TYPE;
 
373
        return( 0 );
 
374
    } else {
 
375
        ether_atalk[ 0 ].ef_ethertype = ETHERTYPE_AT;
 
376
        return( 0 );
 
377
    }
 
378
}