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/queue.h>
31#include <sys/sysctl.h>
32#include <sys/systm.h>
33#include <sys/mbuf.h>
34#include <sys/malloc.h>
35#include <sys/socket.h>
36#include <sys/syslog.h>
37
38#include <net/if.h>
39#include <net/if_dl.h>
40#include <net/if_types.h>
41#include <net/route.h>
42#include <net/dlil.h>
43#include <net/if_llc.h>
44#if BRIDGE
45#include <net/ethernet.h>
46#include <net/bridge.h>
47#endif
48
49#include <netinet/in.h>
50#include <netinet/in_var.h>
51#include <netinet/in_arp.h>
52}
53
54extern "C"
55{
56#include "firewire.h"
57#include "if_firewire.h"
58}
59#include "IOFireWireIP.h"
60
61void		firewire_arpintr __P((mbuf_t m));
62u_char		*firewire_sprintf __P((register u_char *p, register u_char *ap));
63static void inet_firewire_arp_input __P((mbuf_t m));
64
65////////////////////////////////////////////////////////////////////////////////
66//
67// firewire_arpintr
68//
69// IN: register mbuf_t m
70//
71// Invoked by :
72// inet_firewire_input in firewire_inet_pr_module.c and it will be called from
73// the context of dlil_input_thread queue
74//
75// Common length and type checks are done here, then the protocol-specific
76// routine is called.
77//
78////////////////////////////////////////////////////////////////////////////////
79void
80firewire_arpintr(register mbuf_t m)
81{
82    if (m == 0 || (mbuf_flags(m) & MBUF_PKTHDR) == 0)
83        panic("arpintr");
84
85    inet_firewire_arp_input(m);
86}
87
88#if INET
89errno_t
90firewire_inet_arp(
91	ifnet_t								ifp,
92	u_short								arpop,
93	const struct sockaddr_dl*			sender_hw,
94	const struct sockaddr*				sender_proto,
95	const struct sockaddr_dl*			target_hw,
96	const struct sockaddr*				target_proto)
97{
98	mbuf_t	m;
99	errno_t	result;
100	register struct firewire_header *fwh;
101	register IP1394_ARP *fwa;
102	const struct sockaddr_in* sender_ip = (const struct sockaddr_in*)sender_proto;
103	const struct sockaddr_in* target_ip = (const struct sockaddr_in*)target_proto;
104	char *datap;
105
106	IOFWInterface *fwIf	   = (IOFWInterface*)ifnet_softc(ifp);
107
108	if(fwIf == NULL)
109		return EINVAL;
110
111	IOFireWireIP  *fwIpObj = (IOFireWireIP*)fwIf->getController();
112
113	if(fwIpObj == NULL)
114		return EINVAL;
115
116	LCB	*lcb = fwIpObj->getLcb();
117
118	if (target_ip == NULL)
119		return EINVAL;
120
121	if ((sender_ip && sender_ip->sin_family != AF_INET) ||
122		(target_ip && target_ip->sin_family != AF_INET))
123		return EAFNOSUPPORT;
124
125	result = mbuf_gethdr(MBUF_DONTWAIT, MBUF_TYPE_DATA, &m);
126	if (result != 0)
127		return result;
128
129	mbuf_setlen(m, sizeof(*fwa));
130	mbuf_pkthdr_setlen(m, sizeof(*fwa));
131
132	/* Move the data pointer in the mbuf to the end, aligned to 4 bytes */
133	datap = (char*)mbuf_datastart(m);
134	datap += mbuf_trailingspace(m);
135	datap -= (((u_long)datap) & 0x3);
136	mbuf_setdata(m, datap, sizeof(*fwa));
137	fwa = (IP1394_ARP*)mbuf_data(m);
138	bzero((caddr_t)fwa, sizeof(*fwa));
139
140	/* Prepend the ethernet header, we will send the raw frame */
141	result = mbuf_prepend(&m, sizeof(*fwh), MBUF_DONTWAIT);
142	if(result != 0)
143		return result;
144
145	fwh = (struct firewire_header*)mbuf_data(m);
146    fwh->fw_type = htons(FWTYPE_ARP);
147
148	/* Fill out the arp packet */
149    fwa->hardwareType = htons(ARP_HDW_TYPE);
150    fwa->protocolType = htons(FWTYPE_IP);
151    fwa->hwAddrLen = sizeof(IP1394_HDW_ADDR);
152    fwa->ipAddrLen = IPV4_ADDR_SIZE;
153    fwa->opcode = htons(arpop);
154    fwa->senderMaxRec = lcb->ownHardwareAddress.maxRec;
155    fwa->sspd = lcb->ownHardwareAddress.spd;
156    fwa->senderUnicastFifoHi = htons(lcb->ownHardwareAddress.unicastFifoHi);
157    fwa->senderUnicastFifoLo = htonl(lcb->ownHardwareAddress.unicastFifoLo);
158
159	/* Sender Hardware */
160	if (sender_hw != NULL)
161		bcopy(CONST_LLADDR(sender_hw), &fwa->senderUniqueID, sizeof(fwa->senderUniqueID));
162	else
163		ifnet_lladdr_copy_bytes(ifp, &fwa->senderUniqueID, FIREWIRE_ADDR_LEN);
164
165	ifnet_lladdr_copy_bytes(ifp, fwh->fw_shost, sizeof(fwh->fw_shost));
166
167	/* Sender IP */
168	if (sender_ip != NULL)
169		fwa->senderIpAddress = sender_ip->sin_addr.s_addr;
170	else
171	{
172		ifaddr_t	*addresses;
173		struct sockaddr sa;
174
175		if (ifnet_get_address_list_family(ifp, &addresses, AF_INET) == 0)
176		{
177			ifaddr_address( addresses[0], &sa, 16 );
178			fwa->senderIpAddress  = ((UInt32)(sa.sa_data[5] & 0xFF)) << 24;
179			fwa->senderIpAddress |= ((UInt32)(sa.sa_data[4] & 0xFF)) << 16;
180			fwa->senderIpAddress |= ((UInt32)(sa.sa_data[3] & 0xFF)) << 8;
181			fwa->senderIpAddress |= ((UInt32)(sa.sa_data[2] & 0xFF));
182
183			ifnet_free_address_list(addresses);
184		}
185		else
186		{
187			mbuf_free(m);
188			return ENXIO;
189		}
190	}
191
192	/* Target Hardware */
193	if (target_hw == 0)
194		bcopy(fwbroadcastaddr, fwh->fw_dhost, sizeof(fwh->fw_dhost));
195	else
196		bcopy(CONST_LLADDR(target_hw), fwh->fw_dhost, sizeof(fwh->fw_dhost));
197
198	/* Target IP */
199	fwa->targetIpAddress = target_ip->sin_addr.s_addr;
200
201	ifnet_output_raw(ifp, PF_INET, m);
202
203	return 0;
204}
205
206////////////////////////////////////////////////////////////////////////////////
207//
208// in_firewire_arp_input
209//
210// IN: register struct mbuf *m
211//
212// Invoked by :
213// firewire_arpintr calls it from the context of dlil_input_thread queue
214//
215// ARP for Internet protocols on 10 Mb/s Ethernet.
216// Algorithm is that given in RFC 826.
217// In addition, a sanity check is performed on the sender
218// protocol address, to catch impersonators.
219// We no longer handle negotiations for use of trailer protocol:
220// Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent
221// along with IP replies if we wanted trailers sent to us,
222// and also sent them in response to IP replies.
223// This allowed either end to announce the desire to receive trailer packets.
224// We no longer reply to requests for ETHERTYPE_TRAIL protocol either,
225// but formerly didn't normally send requests.
226//
227////////////////////////////////////////////////////////////////////////////////
228static void
229inet_firewire_arp_input(
230	mbuf_t m)
231{
232	IP1394_ARP *fwa;
233	struct sockaddr_dl	sender_hw;
234	struct sockaddr_in	sender_ip;
235	struct sockaddr_in	target_ip;
236
237	ifnet_t		  ifp		= mbuf_pkthdr_rcvif((mbuf_t)m);
238
239	IOFWInterface *fwIf		= (IOFWInterface*)ifnet_softc(ifp);
240
241	if(fwIf == NULL)
242		return;
243
244	IOFireWireIP  *fwIpObj	= (IOFireWireIP*)fwIf->getController();
245
246	if(fwIpObj == NULL)
247		return;
248
249    if (mbuf_len(m) < (int)sizeof(IP1394_ARP) &&
250	    mbuf_pullup(&m, sizeof(IP1394_ARP)) != 0)
251		return;
252
253	fwa = (IP1394_ARP*)mbuf_data(m);
254
255	// Verify this is an firewire/ip arp and address lengths are correct
256    if (fwa->hardwareType != htons(ARP_HDW_TYPE) || fwa->protocolType != htons(FWTYPE_IP)
257        || fwa->hwAddrLen != sizeof(IP1394_HDW_ADDR) || fwa->ipAddrLen != IPV4_ADDR_SIZE)
258	{
259        mbuf_free(m);
260        return;
261    }
262
263	bzero(&sender_ip, sizeof(sender_ip));
264	sender_ip.sin_len = sizeof(sender_ip);
265	sender_ip.sin_family = AF_INET;
266	sender_ip.sin_addr.s_addr = fwa->senderIpAddress;
267	target_ip = sender_ip;
268	target_ip.sin_addr.s_addr = fwa->targetIpAddress;
269
270	bzero(&sender_hw, sizeof(sender_hw));
271	sender_hw.sdl_len = sizeof(sender_hw);
272	sender_hw.sdl_family = AF_LINK;
273	sender_hw.sdl_type = IFT_IEEE1394;
274	sender_hw.sdl_alen = FIREWIRE_ADDR_LEN;
275	bcopy(&fwa->senderUniqueID, LLADDR(&sender_hw), FIREWIRE_ADDR_LEN);
276
277	if(fwIpObj->arpCacheHandler(fwa))
278		inet_arp_handle_input(ifp, ntohs(fwa->opcode), &sender_hw, &sender_ip, &target_ip);
279
280	mbuf_free((mbuf_t)m);
281}
282
283void
284firewire_inet_event(
285	ifnet_t						ifp,
286	__unused protocol_family_t	protocol,
287	const struct kev_msg		*event)
288{
289	ifaddr_t	*addresses;
290
291	if (event->vendor_code !=  KEV_VENDOR_APPLE ||
292		event->kev_class != KEV_NETWORK_CLASS ||
293		event->kev_subclass != KEV_DL_SUBCLASS ||
294		event->event_code != KEV_DL_LINK_ADDRESS_CHANGED)
295	return;
296
297	if (ifnet_get_address_list_family(ifp, &addresses, AF_INET) == 0)
298	{
299		int i;
300
301		for (i = 0; addresses[i] != NULL; i++)
302			inet_arp_init_ifaddr(ifp, addresses[i]);
303
304		ifnet_free_address_list(addresses);
305	}
306}
307#endif
308
309/*
310 * Convert Ethernet address to printable (loggable) representation.
311 */
312static u_char digits[] = "0123456789abcdef";
313u_char *
314firewire_sprintf(register u_char *p, register u_char *ap)
315{
316    register u_char *cp;
317    register int i;
318
319        for (cp = p, i = 0; i < 8; i++) {
320                *cp++ = digits[*ap >> 4];
321                *cp++ = digits[*ap++ & 0xf];
322                *cp++ = ':';
323        }
324        *--cp = 0;
325        return (p);
326}
327