1/*
2 * Copyright (c) 2000-2012 Apple, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * Copyright 1994 Apple Computer, Inc.
30 * All Rights Reserved.
31 *
32 * Tuyen A. Nguyen. (December 5, 1994)
33 *   Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
34 */
35
36#include <sys/errno.h>
37#include <sys/types.h>
38#include <sys/param.h>
39#include <machine/spl.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/proc.h>
43#include <sys/filedesc.h>
44#include <sys/fcntl.h>
45#include <sys/mbuf.h>
46#include <sys/ioctl.h>
47#include <sys/malloc.h>
48#include <sys/socket.h>
49#include <sys/socketvar.h>
50#include <sys/sockio.h>
51
52#include <net/if.h>
53#include <net/if_types.h>
54#include <net/if_dl.h>
55#include <net/dlil.h>
56#include <net/ethernet.h>
57#include <net/kpi_protocol.h>
58
59#include <netat/sysglue.h>
60#include <netat/appletalk.h>
61#include <netat/at_pcb.h>
62#include <netat/at_var.h>
63#include <netat/ddp.h>
64#include <netat/at_aarp.h>
65#include <netat/at_pat.h>
66#include <netat/atp.h>
67#include <netat/debug.h>
68
69#define DSAP_SNAP 0xaa
70
71extern int adspInited;
72
73static llc_header_t	snap_hdr_at = SNAP_HDR_AT;
74static llc_header_t	snap_hdr_aarp = SNAP_HDR_AARP;
75static unsigned char snap_proto_ddp[5] = SNAP_PROTO_AT;
76static unsigned char snap_proto_aarp[5] = SNAP_PROTO_AARP;
77
78static void at_input_packet(protocol_family_t protocol, mbuf_t m);
79
80struct ifqueue atalkintrq; 	/* appletalk and aarp packet input queue */
81
82short appletalk_inited = 0;
83
84void atalk_load(void);
85void atalk_unload(void);
86
87extern int pktsIn, pktsOut;
88
89
90void atalk_load()
91{
92	atp_init();
93	atp_link();
94	adspInited = 0;
95
96/*	adsp_init();
97		for 2225395
98		this happens in adsp_open and is undone on ADSP_UNLINK
99*/
100	domain_proto_mtx_unlock(TRUE);
101	proto_register_input(PF_APPLETALK, at_input_packet, NULL, 0);
102	domain_proto_mtx_lock();
103} /* atalk_load */
104
105/* Undo everything atalk_load() did. */
106void atalk_unload()  /* not currently used */
107{
108	atp_unlink();
109
110#ifdef NOT_YET
111	{
112		extern gbuf_t *scb_resource_m;
113		extern gbuf_t *atp_resource_m;
114		if (scb_resource_m) {
115			gbuf_freem(scb_resource_m);
116			scb_resource_m = 0;
117			scb_free_list = 0;
118		}
119		/* allocated in atp_trans_alloc() */
120		if (atp_resource_m) {
121			gbuf_freem(atp_resource_m);
122			atp_resource_m = 0;
123			atp_trans_free_list = 0;
124		}
125	}
126#endif
127
128	appletalk_inited = 0;
129} /* atalk_unload */
130
131void appletalk_hack_start(void)
132{
133	if (!appletalk_inited) {
134		atalk_load();
135		atalkintrq.ifq_maxlen = IFQ_MAXLEN;
136		appletalk_inited = 1;
137	}
138} /* appletalk_hack_start */
139
140int pat_output(patp, mlist, dst_addr, type)
141	at_ifaddr_t *patp;
142	struct mbuf *mlist;			/* packet chain */
143	unsigned char *dst_addr;	/* for atalk addr - net # must be in network byte order */
144	int 	type;
145{
146	struct mbuf *m, *m1;
147	llc_header_t *llc_header;
148	struct sockaddr dst;
149
150	if (! patp->aa_ifp) {
151		for (m = mlist; m; m = mlist) {
152			mlist = m->m_nextpkt;
153			m->m_nextpkt = 0;
154			m_freem(m);
155		}
156		return ENOTREADY;
157	}
158
159	/* this is for ether_output */
160	dst.sa_family = AF_APPLETALK;
161	dst.sa_len = 2 + sizeof(struct etalk_addr);
162	bcopy (dst_addr, &dst.sa_data[0], sizeof(struct etalk_addr));
163
164	/* packet chains are used on output and can be tested using aufs */
165	for (m = mlist; m; m = mlist) {
166		mlist = m->m_nextpkt;
167		m->m_nextpkt = 0;
168
169		M_PREPEND(m, sizeof(llc_header_t), M_DONTWAIT);
170		if (m == 0) {
171			continue;
172		}
173
174		llc_header = mtod(m, llc_header_t *);
175		*llc_header =
176		  (type == AARP_AT_TYPE) ? snap_hdr_aarp : snap_hdr_at;
177
178		for (m->m_pkthdr.len = 0, m1 = m; m1; m1 = m1->m_next)
179			m->m_pkthdr.len += m1->m_len;
180		m->m_pkthdr.rcvif = 0;
181
182		/* *** Note: AT is sending out mbufs of type MSG_DATA,
183		   not MT_DATA.  *** */
184#ifdef APPLETALK_DEBUG
185		if (m->m_next &&
186		    !((m->m_next)->m_flags & M_EXT))
187			kprintf("po: mlen= %d, m2len= %d\n", m->m_len,
188				(m->m_next)->m_len);
189#endif
190		atalk_unlock();
191		dlil_output(patp->aa_ifp, PF_APPLETALK, m, NULL, &dst, 0, NULL);
192		atalk_lock();
193
194		pktsOut++;
195	}
196
197	return 0;
198} /* pat_output */
199
200static void
201at_input_packet(
202	__unused protocol_family_t	protocol,
203	mbuf_t						m)
204{
205	struct mbuf *m1;
206	struct ifnet *ifp;
207	llc_header_t *llc_header;
208	at_ifaddr_t *ifID;
209	char src[6];
210	enet_header_t *enet_header;
211
212	if (!appletalk_inited) {
213		m_freem(m);
214		return;
215	}
216
217	if ((m->m_flags & M_PKTHDR) == 0) {
218#ifdef APPLETALK_DEBUG
219		kprintf("atalkintr: no HDR on packet received");
220#endif
221		m_freem(m);
222		return;
223	}
224
225	  /* make sure the interface this packet was received on is configured
226	     for AppleTalk */
227	  ifp = m->m_pkthdr.rcvif;
228	  TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) {
229		if (ifID->aa_ifp && (ifID->aa_ifp == ifp))
230			break;
231	  }
232	  /* if we didn't find a matching interface */
233	  if (!ifID) {
234		m_freem(m);
235		return; /* was EAFNOSUPPORT */
236	  }
237
238	  /* make sure the entire packet header is in the current mbuf */
239	  if (m->m_len < ENET_LLC_SIZE &&
240	      (m = m_pullup(m, ENET_LLC_SIZE)) == 0) {
241#ifdef APPLETALK_DEBUG
242		kprintf("atalkintr: packet too small\n");
243#endif
244		m_freem(m);
245		return;
246	  }
247	  enet_header = mtod(m, enet_header_t *);
248
249	  /* Ignore multicast packets from local station */
250	  /* *** Note: code for IFTYPE_TOKENTALK may be needed here. *** */
251	  if (ifID->aa_ifp->if_type == IFT_ETHER ||
252		ifID->aa_ifp->if_type == IFT_L2VLAN ||
253		ifID->aa_ifp->if_type == IFT_IEEE8023ADLAG) {
254		bcopy((char *)enet_header->src, src, sizeof(src));
255
256#ifdef COMMENT  /* In order to receive packets from the Blue Box, we cannot
257		   reject packets whose source address matches our local address.
258		*/
259		if ((enet_header->dst[0] & 1) &&
260		    (bcmp(src, ifID->xaddr, sizeof(src)) == 0)) {
261		  /* Packet rejected: think it's a local mcast. */
262		  m_freem(m);
263		  return; /* was EAFNOSUPPORT */
264		}
265#endif /* COMMENT */
266
267		llc_header = (llc_header_t *)(enet_header+1);
268
269		/* advance the mbuf pointers past the ethernet header */
270		m->m_data += ENET_LLC_SIZE;
271		m->m_len -= ENET_LLC_SIZE;
272
273		pktsIn++;
274
275		if (LLC_PROTO_EQUAL(llc_header->protocol,snap_proto_aarp)) {
276	       		(void)aarp_rcv_pkt(mtod(m, aarp_pkt_t *), ifID);
277			m_freem(m);
278		}
279		else if (LLC_PROTO_EQUAL(llc_header->protocol, snap_proto_ddp)) {
280			/* if we're a router take all pkts */
281			if (!ROUTING_MODE) {
282			  if (aarp_chk_addr(mtod(m, at_ddp_t  *), ifID)
283			      == AARP_ERR_NOT_OURS) {
284#ifdef APPLETALK_DEBUG
285			    kprintf("pat_input: Packet Rejected: not for us? dest=%x.%x.%x.%x.%x.%x LLC_PROTO= %02x%02x\n",
286				    enet_header->dst[0], enet_header->dst[1],
287				    enet_header->dst[2], enet_header->dst[3],
288				    enet_header->dst[4], enet_header->dst[5],
289				    llc_header->protocol[3],
290				    llc_header->protocol[4]);
291#endif
292			    m_freem(m);
293			    return; /* was EAFNOSUPPORT */
294			  }
295			}
296			MCHTYPE(m, MSG_DATA); /* set the mbuf type */
297
298			ifID->stats.rcv_packets++;
299			for (m1 = m; m1; m1 = m1->m_next)
300				ifID->stats.rcv_bytes += m1->m_len;
301
302			if (!MULTIPORT_MODE)
303				ddp_glean(m, ifID, (struct etalk_addr *)src);
304
305			ddp_input(m, ifID);
306		} else {
307#ifdef APPLETALK_DEBUG
308		  	kprintf("pat_input: Packet Rejected: wrong LLC_PROTO = %02x%02x\n",
309				llc_header->protocol[3],
310				llc_header->protocol[4]);
311#endif
312			m_freem(m);
313		}
314	}
315}
316