1/*
2 * Copyright (c) 1990,1991 Regents of The University of Michigan.
3 * All Rights Reserved.
4 *
5 * Permission to use, copy, modify, and distribute this software and
6 * its documentation for any purpose and without fee is hereby granted,
7 * provided that the above copyright notice appears in all copies and
8 * that both that copyright notice and this permission notice appear
9 * in supporting documentation, and that the name of The University
10 * of Michigan not be used in advertising or publicity pertaining to
11 * distribution of the software without specific, written prior
12 * permission. This software is supplied as is without expressed or
13 * implied warranties of any kind.
14 *
15 *	Research Systems Unix Group
16 *	The University of Michigan
17 *	c/o Mike Clark
18 *	535 W. William Street
19 *	Ann Arbor, Michigan
20 *	+1-313-763-0525
21 *	netatalk@itd.umich.edu
22 */
23
24#include <sys/types.h>
25#include <sys/mbuf.h>
26#include <sys/socket.h>
27#include <sys/protosw.h>
28#include <sys/ioctl.h>
29#include <sys/errno.h>
30#include <net/if.h>
31#include <net/if_llc.h>
32#include <net/if_to_proto.h>
33#include <net/netisr.h>
34#include <netinet/in.h>
35#undef s_net
36#include <netinet/if_ether.h>
37
38#include "at.h"
39#include "at_var.h"
40
41extern u_char	at_org_code[ 3 ];
42extern u_char	aarp_org_code[ 3 ];
43
44/*
45 * This is the magic input routine, for all AppleTalk related packets.
46 * It will pick up *all* packets received, on all interfaces, apparently.
47 * If it turns out that receiving all packets in this fashion causes
48 * DLI to not receive packets what it should, we may need to call DLI
49 * directly from within the AppleTalk input routines.  Ick.
50 */
51struct mbuf *
52ddp_ifinput( m, ifp, inq, eh )
53    struct mbuf		*m;
54    struct ifnet	*ifp;
55    struct ifqueue	**inq;
56    struct ether_header	*eh;
57{
58    struct llc		llc;
59    struct if_family	*ifam;
60
61    switch ( eh->ether_type ) {
62    case ETHERTYPE_AT :
63	*inq = &atintrq1;
64	smp_lock( &(*inq)->lk_ifqueue, LK_RETRY );
65	schednetisr( NETISR_AT );
66	return( m );
67
68    case ETHERTYPE_AARP :
69	aarpinput( ifp, m );
70	return( 0 );
71
72    default :
73	if ( eh->ether_type <= ETHERMTU ) {		/* ieee802 */
74	    if ( m->m_len < sizeof( struct llc )) {
75		break;
76	    }
77
78	    bcopy( mtod( m, caddr_t ), &llc, sizeof( struct llc ));
79	    if ( llc.llc_dsap != LLC_SNAP_LSAP ||
80		    llc.llc_ssap != LLC_SNAP_LSAP ||
81		    llc.llc_control != LLC_UI ) {
82		break;
83	    }
84
85	    if ( bcmp( llc.llc_org_code, at_org_code,
86		    sizeof( at_org_code )) == 0 &&
87		    ntohs( llc.llc_ether_type ) == ETHERTYPE_AT ) {
88		m_adj( m, sizeof( struct llc ));
89		*inq = &atintrq2;
90		smp_lock( &(*inq)->lk_ifqueue, LK_RETRY );
91		schednetisr( NETISR_AT );
92		return( m );
93	    }
94
95	    if ( bcmp( llc.llc_org_code, aarp_org_code,
96		    sizeof( aarp_org_code )) == 0 &&
97		    ntohs( llc.llc_ether_type ) == ETHERTYPE_AARP ) {
98		m_adj( m, sizeof( struct llc ));
99		aarpinput( ifp, m );
100		return( 0 );
101	    }
102	}
103    }
104
105    /*
106     * Check is anyone else wants this packet.
107     */
108    for ( ifam = if_family; ifam->domain != -1; ifam++ ) {
109	if (( eh->ether_type == ifam->if_type || ifam->if_type == -1 ) &&
110		ifam->prswitch &&
111		ifam->prswitch->pr_ifinput != (int (*)())ddp_ifinput ) {
112	    break;
113	}
114    }
115    if ( ifam->domain != -1 && ifam->prswitch->pr_ifinput ) {
116	return( (struct mbuf *)(*ifam->prswitch->pr_ifinput)( m, ifp,
117		inq, eh ));
118    }
119
120    m_freem( m );
121    return( 0 );
122}
123
124/*
125 * Fill in type and odst. odst is the media output address, i.e.
126 * the MAC layer address. Type is the MAC type. Should be 0 to
127 * indicate IEEE addressing.
128 *
129 * Stupidly enough, there's no way to say "can't send this now."
130 * So, we just let the first packet go into the air. Not much
131 * else to be done, except maybe bitch at DEC. Note: we're not
132 * passing the mbuf to aarpresolve() -- that way it doesn't get
133 * mfree-ed twice.
134 */
135ddp_ifoutput( ifp, m, dst, type, odst )
136    struct ifnet	*ifp;
137    struct mbuf		*m;
138    struct sockaddr_at	*dst;
139    short		*type;
140    char		*odst;
141{
142    struct at_ifaddr	*aa;
143    struct llc		*llc;
144    struct mbuf		*m0;
145
146    if ( !aarpresolve( ifp, 0, dst, odst )) {
147	*type = 0xffff;
148	return( 0 );
149    }
150
151    if (( aa = (struct at_ifaddr *)at_ifawithnet( dst, ifp->if_addrlist ))
152	    == 0 ) {
153	*type = 0xffff;
154	return( 0 );
155    }
156
157    if ( aa->aa_flags & AFA_PHASE2 ) {
158	/*
159	 * This code needs to be modeled after the similar code in
160	 * at_sun.c -- you can't just MGET() and bcopy(), since we might be
161	 * dealing with mbufs which are really pages.
162	 */
163	MGET( m0, M_WAIT, MT_HEADER );
164	if ( m0 == 0 ) {
165	    *type = 0xffff;
166	    return( 0 );
167	}
168	m0->m_next = m->m_next;
169	m0->m_off = m->m_off;
170	m0->m_len = m->m_len;
171	bcopy( mtod( m, caddr_t ), mtod( m0, caddr_t ), m->m_len );
172	m->m_next = m0;
173	m->m_off = MMINOFF;
174	m->m_len = sizeof( struct llc );
175
176	llc = mtod( m, struct llc *);
177	llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
178	llc->llc_control = LLC_UI;
179	bcopy( at_org_code, llc->llc_org_code, sizeof( at_org_code ));
180	llc->llc_ether_type = htons( ETHERTYPE_AT );
181
182	/*
183	 * Set the type to be the length of the packet, instead of 0.
184	 * Ultrix used to put the length in the packet when we set type
185	 * to 0, however, now we do it ourselves.
186	 */
187	for ( *type = 0; m; m = m->m_next ) {
188	    *type += m->m_len;
189	}
190    } else {
191	*type = ETHERTYPE_AT;
192    }
193
194    return( 1 );
195}
196
197ddp_ifioctl( ifp, cmd, data )
198    struct ifnet	*ifp;
199    int			cmd;
200    caddr_t		data;
201{
202    switch( cmd ) {
203    case SIOCSIFADDR :
204	aarpwhohas((struct arpcom *)ifp,
205		&AA_SAT((struct ifaddr *)data)->sat_addr );
206	break;
207    default :
208	return( EINVAL );
209    }
210    return( 0 );
211}
212