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
30struct vdlat {
31    int		vda_magic;
32    char	*vda_name;
33}	atvdl = {
34    VDMAGIC_USER, "netatalk"
35};
36
37struct ifqueue	*atef_input();
38int		atef_output();
39extern int	atintr();
40
41extern u_char	aarp_org_code[ 3 ];
42extern 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 */
57struct 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};
75int	ether_atalkN = sizeof( ether_atalk ) / sizeof( ether_atalk[ 0 ] );
76
77extern struct ether_family	*ether_families;
78
79extern int			atalk_hash(), atalk_netmatch();
80extern int			null_hash(), null_netmatch();
81
82xxxinit( 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 *
201atef_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 )) {
248printf( "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 * )) {
268printf( "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 */
309atef_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}
379