1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23#ifndef INET
24#define INET 1
25#endif
26
27extern "C"{
28#include <sys/param.h>
29#include <sys/kernel.h>
30#include <sys/malloc.h>
31#include <sys/mbuf.h>
32#include <sys/socket.h>
33#include <sys/sockio.h>
34#include <net/dlil.h>
35#include <sys/sysctl.h>
36#include <sys/systm.h>
37#include <sys/syslog.h>
38
39#include <net/if.h>
40#include <net/route.h>
41#include <net/if_llc.h>
42#include <net/if_dl.h>
43#include <net/if_types.h>
44#include <sys/kpi_mbuf.h>	/* For MBUF_LOOP */
45
46#include <sys/socketvar.h>
47
48#include <net/dlil.h>
49
50#include "firewire.h"
51#include <if_firewire.h>
52}
53#include "IOFireWireIP.h"
54
55struct fw_desc {
56	u_int16_t	type;			/* Type of protocol stored in data */
57	u_long 		protocol_family;	/* Protocol family */
58	u_long		data[2];		/* Protocol data */
59};
60
61#define FIREWIRE_DESC_BLK_SIZE (10)
62
63//
64// Statics for demux module
65//
66struct firewire_desc_blk_str {
67    u_long  n_max_used;
68    u_long	n_count;
69	u_long	n_used;
70    struct fw_desc  block_ptr[1];
71};
72/* Size of the above struct before the array of struct fw_desc */
73#define FIREWIRE_DESC_HEADER_SIZE	((size_t)&(((struct firewire_desc_blk_str*)0)->block_ptr[0]))
74
75static ifnet_t	loop_ifp;
76
77
78////////////////////////////////////////////////////////////////////////////////
79//
80// firewire_del_proto
81//
82// IN: ifnet_t ifp, u_long protocol_family
83//
84// Invoked by :
85//  dlil_detach_protocol calls this funcion
86//
87// Release all descriptor entries owned by this ifp/protocol_family (there may be several).
88// Setting the type to 0 releases the entry. Eventually we should compact-out
89// the unused entries.
90//
91////////////////////////////////////////////////////////////////////////////////
92__private_extern__
93int  firewire_del_proto(ifnet_t ifp, protocol_family_t protocol_family)
94{
95	IOFWInterface					*fwIf		= (IOFWInterface*)ifnet_softc(ifp);
96
97	if(fwIf == NULL)
98		return EINVAL;
99
100	struct firewire_desc_blk_str	*desc_blk	= (struct firewire_desc_blk_str *)fwIf->getFamilyCookie();
101
102	if (desc_blk == NULL)
103		return EINVAL;
104
105	int		found = 0;
106
107	for (u_long current = desc_blk->n_max_used; current > 0; current--)
108	{
109		if (desc_blk->block_ptr[current - 1].protocol_family == protocol_family)
110		{
111			found = 1;
112			desc_blk->block_ptr[current - 1].type = 0;
113			desc_blk->n_used--;
114		}
115	}
116
117	if (desc_blk->n_used == 0)
118	{
119		FREE(fwIf->getFamilyCookie(), M_IFADDR);
120		fwIf->setFamilyCookie(NULL);
121	}
122	else
123	{
124		/* Decrement n_max_used */
125		for (; desc_blk->n_max_used > 0 && desc_blk->block_ptr[desc_blk->n_max_used - 1].type == 0; desc_blk->n_max_used--)
126			;
127	}
128
129	return found;
130 }
131
132////////////////////////////////////////////////////////////////////////////////
133//
134// firewire_add_proto
135//
136// IN: ifnet_t ifp, u_long protocol_family, struct ddesc_head_str *desc_head
137//
138// Invoked by :
139//  dlil_attach_protocol calls this funcion
140//
141//
142////////////////////////////////////////////////////////////////////////////////
143__private_extern__ int
144firewire_add_proto_internal(ifnet_t ifp, u_long protocol_family, const struct ifnet_demux_desc	*demux)
145{
146	IOFWInterface					*fwIf		= (IOFWInterface*)ifnet_softc(ifp);
147
148	if(fwIf == NULL)
149		return EINVAL;
150
151	struct firewire_desc_blk_str	*desc_blk	= (struct firewire_desc_blk_str *)fwIf->getFamilyCookie();
152
153	struct fw_desc	*ed;
154	u_long		   i;
155
156	switch (demux->type)
157	{
158		case DLIL_DESC_ETYPE2:
159			if (demux->datalen != 2)
160				return EINVAL;
161			break;
162
163		default:
164			return EOPNOTSUPP;
165	}
166
167	// Check for case where all of the descriptor blocks are in use
168	if (desc_blk == NULL || desc_blk->n_used == desc_blk->n_count)
169	{
170		struct firewire_desc_blk_str *tmp;
171		u_long	new_count = FIREWIRE_DESC_BLK_SIZE;
172		u_long	new_size;
173		u_long	old_size = 0;
174
175		i = 0;
176		if (desc_blk)
177		{
178			new_count += desc_blk->n_count;
179			old_size = desc_blk->n_count * sizeof(struct fw_desc) + FIREWIRE_DESC_HEADER_SIZE;
180			i = desc_blk->n_used;
181		}
182
183		new_size = new_count * sizeof(struct fw_desc) + FIREWIRE_DESC_HEADER_SIZE;
184
185		tmp = (struct firewire_desc_blk_str*)_MALLOC(new_size, M_IFADDR, MBUF_WAITOK);
186		if (tmp  == 0)
187			return ENOMEM;
188
189		bzero(tmp + old_size, new_size - old_size);
190		if (desc_blk)
191		{
192			bcopy(desc_blk, tmp, old_size);
193			FREE(desc_blk, M_IFADDR);
194		}
195		desc_blk = tmp;
196		fwIf->setFamilyCookie(desc_blk);
197		desc_blk->n_count = new_count;
198	}
199	else
200	{
201		// Find a free entry
202		for (i = 0; i < desc_blk->n_count; i++)
203		{
204			if (desc_blk->block_ptr[i].type == 0)
205				break;
206		}
207	}
208
209	// Bump n_max_used if appropriate
210	if (i + 1 > desc_blk->n_max_used) {
211		desc_blk->n_max_used = i + 1;
212	}
213
214	ed = &desc_blk->block_ptr[i];
215	ed->protocol_family = protocol_family;
216	ed->data[0] = 0;
217	ed->data[1] = 0;
218
219	switch (demux->type) {
220		case DLIL_DESC_ETYPE2:
221			/* 2 byte ethernet raw protocol type is at native_type */
222			/* prtocol must be in network byte order */
223			ed->type = DLIL_DESC_ETYPE2;
224			ed->data[0] = *(u_int16_t*)demux->data;
225			break;
226	}
227
228	desc_blk->n_used++;
229
230    return 0;
231}
232
233int
234firewire_add_proto(ifnet_t   ifp, protocol_family_t protocol, const struct ifnet_demux_desc *demux_list, u_int32_t demux_count)
235{
236	int			error = 0;
237	u_int32_t	i;
238
239	for (i = 0; i < demux_count; i++)
240	{
241		error = firewire_add_proto_internal(ifp, protocol, &demux_list[i]);
242		if (error)
243		{
244			firewire_del_proto(ifp, protocol);
245			break;
246		}
247	}
248
249	return error;
250}
251
252////////////////////////////////////////////////////////////////////////////////
253//
254// firewire_demux
255//
256// IN: ifnet_t ifp,struct mbuf  *m,char *frame_header,
257//	   u_long *protocol_family
258//
259// Invoked by :
260//  dlil_input_packet()
261//
262////////////////////////////////////////////////////////////////////////////////
263__private_extern__ int firewire_demux(ifnet_t ifp, mbuf_t m, char *frame_header, protocol_family_t *protocol_family)
264{
265    register struct firewire_header *eh = (struct firewire_header *)frame_header;
266
267	IOFWInterface					*fwIf		= (IOFWInterface*)ifnet_softc(ifp);
268
269	if(fwIf == NULL)
270		return EINVAL;
271
272	struct firewire_desc_blk_str	*desc_blk	= (struct firewire_desc_blk_str *)fwIf->getFamilyCookie();
273
274	if (desc_blk == NULL)
275		return EINVAL;
276
277	u_short			fw_type = eh->fw_type;
278    u_int16_t		type = DLIL_DESC_ETYPE2;
279    u_long			maxd = desc_blk->n_max_used;
280    struct fw_desc	*ed = desc_blk->block_ptr;
281
282    /*
283     * Search through the connected protocols for a match.
284     */
285	for (u_long i = 0; i < maxd; i++)
286	{
287		if ((ed[i].type == type) && (ed[i].data[0] == fw_type))
288		{
289			*protocol_family = ed[i].protocol_family;
290			return 0;
291		}
292	}
293
294    return ENOENT;
295}
296
297////////////////////////////////////////////////////////////////////////////////
298//
299// firewire_frameout
300//
301// IN:	ifnet_t ifp,struct mbuf **m
302// IN:  struct sockaddr *ndest - contains the destination IP Address
303// IN:	char *edst - filled by firewire_arpresolve function in if_firewire.c
304// IN:  char *fw_type
305//
306// Invoked by :
307//  dlil.c for dlil_output, Its called after inet_firewire_pre_output
308//
309// Encapsulate a packet of type family for the local net.
310// Use trailer local net encapsulation if enough data in first
311// packet leaves a multiple of 512 bytes of data in remainder.
312//
313////////////////////////////////////////////////////////////////////////////////
314__private_extern__ int
315firewire_frameout(ifnet_t ifp, mbuf_t *m,
316					const struct sockaddr *ndest, const char *edst, const char *fw_type)
317{
318	register struct firewire_header *fwh;
319
320	/*
321	 * If a simplex interface, and the packet is being sent to our
322	 * Ethernet address or a broadcast address, loopback a copy.
323	 * XXX To make a simplex device behave exactly like a duplex
324	 * device, we should copy in the case of sending to our own
325	 * ethernet address (thus letting the original actually appear
326	 * on the wire). However, we don't do that here for security
327	 * reasons and compatibility with the original behavior.
328	 */
329
330	if ((ifnet_flags(ifp) & IFF_SIMPLEX) &&
331	    (mbuf_flags(*m) & MBUF_LOOP))
332	{
333		if (loop_ifp == NULL) {
334			ifnet_find_by_name("lo0", &loop_ifp);
335
336			/*
337			 * We make an assumption here that lo0 will never go away. This
338			 * means we don't have to worry about releasing the reference
339			 * later and we don't have to worry about leaking a reference
340			 * every time we are loaded.
341			 */
342			ifnet_release(loop_ifp);
343		}
344
345	    if (loop_ifp)
346		{
347            if (mbuf_flags(*m) & MBUF_BCAST)
348			{
349                mbuf_t n;
350
351                if (mbuf_copym(*m, 0, MBUF_COPYALL, MBUF_WAITOK, &n) == 0)
352                    ifnet_output(loop_ifp, PF_INET, n, 0, ndest);
353            }
354            else
355            {
356				if (bcmp(edst, ifnet_lladdr(ifp), FIREWIRE_ADDR_LEN) == 0)
357				{
358                    ifnet_output(loop_ifp, PF_INET, *m, 0, ndest);
359                    return EJUSTRETURN;
360                }
361            }
362	    }
363	}
364
365	//
366	// Add local net header.  If no space in first mbuf,
367	// allocate another.
368	//
369	if (mbuf_prepend(m, sizeof(struct firewire_header), MBUF_DONTWAIT) != 0)
370	    return (EJUSTRETURN);
371
372	//
373	// Lets put this intelligent here into the mbuf
374	// so we can demux on our output path
375	//
376	fwh = (struct firewire_header*)mbuf_data(*m);
377	(void)memcpy(&fwh->fw_type, fw_type,sizeof(fwh->fw_type));
378	memcpy(fwh->fw_dhost, edst, FIREWIRE_ADDR_LEN);
379	(void)memcpy(fwh->fw_shost, ifnet_lladdr(ifp), sizeof(fwh->fw_shost));
380
381	return 0;
382}
383
384////////////////////////////////////////////////////////////////////////////////
385//
386// firewire_add_if
387//
388// IN:	ifnet_t ifp
389//
390////////////////////////////////////////////////////////////////////////////////
391__private_extern__
392int  firewire_add_if(ifnet_t ifp)
393{
394    return 0;
395}
396
397////////////////////////////////////////////////////////////////////////////////
398//
399// firewire_del_if
400//
401// IN:	ifnet_t ifp
402//
403// Invoked by :
404//    firewire_free calls this function
405//
406////////////////////////////////////////////////////////////////////////////////
407__private_extern__
408int  firewire_del_if(IOFWInterface	*fwIf)
409{
410	if (fwIf->getFamilyCookie()) {
411		FREE(fwIf->getFamilyCookie(), M_IFADDR);
412		return 0;
413	}
414	else
415		return ENOENT;
416}
417
418////////////////////////////////////////////////////////////////////////////////
419//
420// firewire_ifmod_ioctl
421//
422// IN:	ifnet_t ifp
423//
424// Invoked by :
425//    dlil_ioctl calls this function, all ioctls are handled at
426//    firewire_inet_prmod_ioctl
427//
428////////////////////////////////////////////////////////////////////////////////
429__private_extern__ int
430firewire_ifmod_ioctl(ifnet_t ifp, unsigned long cmd, void  *data)
431{
432	int err = EOPNOTSUPP;
433	return err;
434}
435
436__private_extern__ int
437firewire_init_if(ifnet_t   ifp)
438{
439    return 0;
440}
441