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
24#ifndef INET
25#define INET 1
26#endif
27
28extern "C"{
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/kernel.h>
32#include <sys/malloc.h>
33#include <sys/mbuf.h>
34#include <sys/socket.h>
35#include <sys/sockio.h>
36#include <sys/sysctl.h>
37
38#include <net/dlil.h>
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 <net/kpi_protocol.h>
45
46#include <netinet/in.h>
47#include <netinet/in_var.h>
48#include <netinet/in_systm.h>
49#include <netinet/ip.h>
50#include <netinet/in_arp.h>
51#include <sys/socketvar.h>
52
53#include "firewire.h"
54#include "if_firewire.h"
55}
56#include "IOFireWireIP.h"
57
58extern void firewire_arpintr __P((mbuf_t	m));
59
60extern errno_t firewire_inet_arp __P((ifnet_t ifp,
61						u_short arpop,
62						const struct sockaddr_dl	*sender_hw,
63						const struct sockaddr		*sender_proto,
64						const struct sockaddr_dl	*target_hw,
65						const struct sockaddr		*target_proto));
66
67extern void firewire_inet_event __P((ifnet_t			ifp,
68							__unused protocol_family_t	protocol,
69							const struct kev_msg		*event));
70
71////////////////////////////////////////////////////////////////////////////////
72//
73// inet_firewire_input
74//
75// IN: struct mbuf  *m, char *frame_header, ifnet_t ifp,
76// IN: u_long dl_tag, int sync_ok
77//
78// Invoked by :
79//  It will be called from the context of dlil_input_thread queue from
80//  dlil_input_packet
81//
82// Process a received firewire ARP/IP packet, the packet is in the mbuf
83// chain m
84//
85////////////////////////////////////////////////////////////////////////////////
86static errno_t
87inet_firewire_input(
88	__unused ifnet_t			ifp,
89	__unused protocol_family_t	protocol_family,
90	mbuf_t						m,
91	char     					*frame_header)
92{
93    struct firewire_header *eh = (struct firewire_header *)frame_header;
94    u_short fw_type;
95
96	ifnet_touch_lastchange(ifp);
97
98    fw_type = ntohs(eh->fw_type);
99
100    switch (fw_type)
101	{
102        case FWTYPE_IP:
103			{
104				mbuf_pullup(&m, sizeof(struct ip));
105				if (m == NULL)
106					return EJUSTRETURN;
107
108				errno_t ret = proto_input(PF_INET, m);
109
110				if( ret )
111					mbuf_freem(m);
112
113				return ret;
114			}
115
116        case FWTYPE_ARP:
117            firewire_arpintr(m);
118			break;
119
120        default:
121            return ENOENT;
122    }
123
124    return 0;
125}
126
127////////////////////////////////////////////////////////////////////////////////
128//
129//  inet_firewire_pre_output
130//
131//   IN:	ifnet_t ifp
132//   IN:	struct mbuf **m0
133//   IN:	struct sockaddr dst_netaddr
134//   IN:	caddr_t	route
135//   OUT:	char *type
136//	 OUT:	char *edst
137//	 IN:	u_long dl_tag
138//
139// Invoked by :
140//  Invoked by dlil.c for dlil_output=>(*proto)->dl_pre_output=>
141//  inet_firewire_pre_output=>
142//
143// Process a received firewire ARP/IP packet, the packet is in the mbuf
144// chain m
145//
146////////////////////////////////////////////////////////////////////////////////
147int
148inet_firewire_pre_output(
149	ifnet_t						interface,
150	__unused protocol_family_t	protocol_family,
151	mbuf_t						*m0,
152	const struct sockaddr		*dst_netaddr,
153	void*						route,
154	char						*type,
155	char						*edst)
156{
157    mbuf_t m = *m0;
158    errno_t	result = 0;
159
160    if ((ifnet_flags(interface) & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
161		return ENETDOWN;
162
163	// Tell firewire_frameout it's ok to loop packet unless negated below.
164    mbuf_setflags(m, mbuf_flags(m) | MBUF_LOOP);
165
166    switch (dst_netaddr->sa_family)
167	{
168    	case AF_INET:
169		{
170			struct sockaddr_dl	ll_dest;
171			result = inet_arp_lookup(interface, (const struct sockaddr_in*)dst_netaddr,
172								   &ll_dest, sizeof(ll_dest), (route_t)route, *m0);
173			if (result == 0)
174			{
175				bcopy(LLADDR(&ll_dest), edst, FIREWIRE_ADDR_LEN);
176				*(u_int16_t*)type = htons(FWTYPE_IP);
177			}
178		}
179		break;
180
181        case AF_UNSPEC:
182		{
183            mbuf_setflags(m, mbuf_flags(m) & ~MBUF_LOOP);
184            register struct firewire_header *fwh = (struct firewire_header *)dst_netaddr->sa_data;
185			(void)memcpy(edst, fwh->fw_dhost, FIREWIRE_ADDR_LEN);
186            *(u_short *)type = fwh->fw_type;
187		}
188		break;
189
190        default:
191            return EAFNOSUPPORT;
192    }
193
194	return result;
195}
196
197////////////////////////////////////////////////////////////////////////////////
198//
199//  firewire_inet_prmod_ioctl
200//
201//   IN:	ifnet_t ifp
202//   IN:	unsigned long	command
203//   IN:	caddr_t			data
204//
205// Invoked by :
206//  Invoked by dlil.c for dlil_output=>(*proto)->dl_pre_output=>
207//  inet_firewire_pre_output=>
208//
209// Process an ioctl from dlil_ioctl in the context of ip, i guess !!
210//
211////////////////////////////////////////////////////////////////////////////////
212static errno_t
213firewire_inet_prmod_ioctl(
214    __unused ifnet_t			ifp,
215    __unused protocol_family_t	protocol_family,
216    __unused unsigned long		command,
217    __unused void*				data)
218{
219    return EOPNOTSUPP;
220}
221
222static errno_t
223firewire_inet_resolve_multi(
224	ifnet_t					ifp,
225	const struct sockaddr	*proto_addr,
226	struct sockaddr_dl		*out_ll,
227	size_t					ll_len)
228{
229	static const size_t minsize = offsetof(struct sockaddr_dl, sdl_data[0]) + FIREWIRE_ADDR_LEN;
230	const struct sockaddr_in	*sin = (const struct sockaddr_in*)proto_addr;
231
232	if (proto_addr->sa_family != AF_INET)
233		return EAFNOSUPPORT;
234
235	if (proto_addr->sa_len < sizeof(struct sockaddr_in))
236		return EINVAL;
237
238	if (ll_len < minsize)
239		return EMSGSIZE;
240
241	bzero(out_ll, minsize);
242	out_ll->sdl_len = minsize;
243	out_ll->sdl_family = AF_LINK;
244	out_ll->sdl_index = ifnet_index(ifp);
245	out_ll->sdl_type = IFT_IEEE1394;
246	out_ll->sdl_nlen = 0;
247	out_ll->sdl_alen = FIREWIRE_ADDR_LEN;
248	out_ll->sdl_slen = 0;
249	FIREWIRE_MAP_IP_MULTICAST(&sin->sin_addr, LLADDR(out_ll));
250
251	return 0;
252}
253
254////////////////////////////////////////////////////////////////////////////////
255//
256// firewire_attach_inet
257//
258//   IN:	ifnet_t ifp
259//
260// Invoked by:
261//  firewire_attach_inet will be invoked from IOFWInterface::attachToDataLinkLayer
262//
263////////////////////////////////////////////////////////////////////////////////
264int
265firewire_attach_inet(ifnet_t ifp, protocol_family_t protocol_family)
266{
267	struct ifnet_attach_proto_param	proto;
268	struct ifnet_demux_desc demux[2];
269    u_short en_native=htons(FWTYPE_IP);
270    u_short arp_native=htons(FWTYPE_ARP);
271	errno_t	error;
272
273	bzero(&demux[0], sizeof(demux));
274	demux[0].type	= DLIL_DESC_ETYPE2;
275	demux[0].data	= &en_native;
276	demux[0].datalen = sizeof(en_native);
277	demux[1].type	= DLIL_DESC_ETYPE2;
278	demux[1].data	= &arp_native;
279	demux[1].datalen = sizeof(arp_native);
280
281	bzero(&proto, sizeof(proto));
282	proto.demux_list	= demux;
283	proto.demux_count	= sizeof(demux) / sizeof(demux[0]);
284	proto.input			= inet_firewire_input;
285	proto.pre_output	= inet_firewire_pre_output;
286	proto.ioctl			= firewire_inet_prmod_ioctl;
287	proto.event			= firewire_inet_event;
288	proto.resolve		= firewire_inet_resolve_multi;
289	proto.send_arp		= firewire_inet_arp;
290
291	error = ifnet_attach_protocol(ifp, protocol_family, &proto);
292	if (error && error != EEXIST)
293	{
294		printf("WARNING: firewire_attach_inet can't attach ip to %s%d\n",
295			   ifnet_name(ifp), ifnet_unit(ifp));
296	}
297
298	return error;
299}