/* * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * The contents of this file constitute Original Code as defined in and * are subject to the Apple Public Source License Version 1.1 (the * "License"). You may not use this file except in compliance with the * License. Please obtain a copy of the License at * http://www.apple.com/publicsource and read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License. * * @APPLE_LICENSE_HEADER_END@ */ #ifndef INET #define INET 1 #endif extern "C"{ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if BRIDGE #include #include #endif #include #include #include } extern "C" { #include "firewire.h" #include "if_firewire.h" } #include "IOFireWireIP.h" void firewire_arpintr __P((mbuf_t m)); u_char *firewire_sprintf __P((register u_char *p, register u_char *ap)); static void inet_firewire_arp_input __P((mbuf_t m)); //////////////////////////////////////////////////////////////////////////////// // // firewire_arpintr // // IN: register mbuf_t m // // Invoked by : // inet_firewire_input in firewire_inet_pr_module.c and it will be called from // the context of dlil_input_thread queue // // Common length and type checks are done here, then the protocol-specific // routine is called. // //////////////////////////////////////////////////////////////////////////////// void firewire_arpintr(register mbuf_t m) { if (m == 0 || (mbuf_flags(m) & M_PKTHDR) == 0) panic("arpintr"); inet_firewire_arp_input(m); } #if INET errno_t firewire_inet_arp( ifnet_t ifp, u_short arpop, const struct sockaddr_dl* sender_hw, const struct sockaddr* sender_proto, const struct sockaddr_dl* target_hw, const struct sockaddr* target_proto) { mbuf_t m; errno_t result; register struct firewire_header *fwh; register IP1394_ARP *fwa; const struct sockaddr_in* sender_ip = (const struct sockaddr_in*)sender_proto; const struct sockaddr_in* target_ip = (const struct sockaddr_in*)target_proto; char *datap; IOFWInterface *fwIf = (IOFWInterface*)ifnet_softc(ifp); if(fwIf == NULL) return EINVAL; IOFireWireIP *fwIpObj = (IOFireWireIP*)fwIf->getController(); if(fwIpObj == NULL) return EINVAL; LCB *lcb = fwIpObj->getLcb(); if (target_ip == NULL) return EINVAL; if ((sender_ip && sender_ip->sin_family != AF_INET) || (target_ip && target_ip->sin_family != AF_INET)) return EAFNOSUPPORT; result = mbuf_gethdr(M_DONTWAIT, MBUF_TYPE_DATA, &m); if (result != 0) return result; mbuf_setlen(m, sizeof(*fwa)); mbuf_pkthdr_setlen(m, sizeof(*fwa)); /* Move the data pointer in the mbuf to the end, aligned to 4 bytes */ datap = (char*)mbuf_datastart(m); datap += mbuf_trailingspace(m); datap -= (((u_long)datap) & 0x3); mbuf_setdata(m, datap, sizeof(*fwa)); fwa = (IP1394_ARP*)mbuf_data(m); bzero((caddr_t)fwa, sizeof(*fwa)); /* Prepend the ethernet header, we will send the raw frame */ result = mbuf_prepend(&m, sizeof(*fwh), M_DONTWAIT); if(result != 0) return result; fwh = (struct firewire_header*)mbuf_data(m); fwh->fw_type = htons(FWTYPE_ARP); /* Fill out the arp packet */ fwa->hardwareType = htons(ARP_HDW_TYPE); fwa->protocolType = htons(FWTYPE_IP); fwa->hwAddrLen = sizeof(IP1394_HDW_ADDR); fwa->ipAddrLen = IPV4_ADDR_SIZE; fwa->opcode = htons(arpop); fwa->senderMaxRec = lcb->ownHardwareAddress.maxRec; fwa->sspd = lcb->ownHardwareAddress.spd; fwa->senderUnicastFifoHi = htons(lcb->ownHardwareAddress.unicastFifoHi); fwa->senderUnicastFifoLo = htonl(lcb->ownHardwareAddress.unicastFifoLo); /* Sender Hardware */ if (sender_hw != NULL) bcopy(CONST_LLADDR(sender_hw), &fwa->senderUniqueID, sizeof(fwa->senderUniqueID)); else ifnet_lladdr_copy_bytes(ifp, &fwa->senderUniqueID, FIREWIRE_ADDR_LEN); ifnet_lladdr_copy_bytes(ifp, fwh->fw_shost, sizeof(fwh->fw_shost)); /* Sender IP */ if (sender_ip != NULL) fwa->senderIpAddress = sender_ip->sin_addr.s_addr; else { ifaddr_t *addresses; if (ifnet_get_address_list_family(ifp, &addresses, AF_INET) == 0) { fwa->senderIpAddress = ((sockaddr_in*)((ifaddr*)addresses[0])->ifa_addr)->sin_addr.s_addr;// ((ifaddr*)addresses[0])->ifa_addr.s_addr; ifnet_free_address_list(addresses); } else { mbuf_free(m); return ENXIO; } } /* Target Hardware */ if (target_hw == 0) bcopy(fwbroadcastaddr, fwh->fw_dhost, sizeof(fwh->fw_dhost)); else bcopy(CONST_LLADDR(target_hw), fwh->fw_dhost, sizeof(fwh->fw_dhost)); /* Target IP */ fwa->targetIpAddress = target_ip->sin_addr.s_addr; ifnet_output_raw(ifp, PF_INET, m); return 0; } //////////////////////////////////////////////////////////////////////////////// // // in_firewire_arp_input // // IN: register struct mbuf *m // // Invoked by : // firewire_arpintr calls it from the context of dlil_input_thread queue // // ARP for Internet protocols on 10 Mb/s Ethernet. // Algorithm is that given in RFC 826. // In addition, a sanity check is performed on the sender // protocol address, to catch impersonators. // We no longer handle negotiations for use of trailer protocol: // Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent // along with IP replies if we wanted trailers sent to us, // and also sent them in response to IP replies. // This allowed either end to announce the desire to receive trailer packets. // We no longer reply to requests for ETHERTYPE_TRAIL protocol either, // but formerly didn't normally send requests. // //////////////////////////////////////////////////////////////////////////////// static void inet_firewire_arp_input( mbuf_t m) { IP1394_ARP *fwa; struct sockaddr_dl sender_hw; struct sockaddr_in sender_ip; struct sockaddr_in target_ip; ifnet_t ifp = mbuf_pkthdr_rcvif((mbuf_t)m); IOFWInterface *fwIf = (IOFWInterface*)ifnet_softc(ifp); if(fwIf == NULL) return; IOFireWireIP *fwIpObj = (IOFireWireIP*)fwIf->getController(); if(fwIpObj == NULL) return; if (mbuf_len(m) < (int)sizeof(IP1394_ARP) && mbuf_pullup(&m, sizeof(IP1394_ARP)) != 0) return; fwa = (IP1394_ARP*)mbuf_data(m); // Verify this is an firewire/ip arp and address lengths are correct if (fwa->hardwareType != htons(ARP_HDW_TYPE) || fwa->protocolType != htons(FWTYPE_IP) || fwa->hwAddrLen != sizeof(IP1394_HDW_ADDR) || fwa->ipAddrLen != IPV4_ADDR_SIZE) { mbuf_free(m); return; } bzero(&sender_ip, sizeof(sender_ip)); sender_ip.sin_len = sizeof(sender_ip); sender_ip.sin_family = AF_INET; sender_ip.sin_addr.s_addr = fwa->senderIpAddress; target_ip = sender_ip; target_ip.sin_addr.s_addr = fwa->targetIpAddress; bzero(&sender_hw, sizeof(sender_hw)); sender_hw.sdl_len = sizeof(sender_hw); sender_hw.sdl_family = AF_LINK; sender_hw.sdl_type = IFT_IEEE1394; sender_hw.sdl_alen = FIREWIRE_ADDR_LEN; bcopy(&fwa->senderUniqueID, LLADDR(&sender_hw), FIREWIRE_ADDR_LEN); if(fwIpObj->arpCacheHandler(fwa)) inet_arp_handle_input(ifp, ntohs(fwa->opcode), &sender_hw, &sender_ip, &target_ip); mbuf_free((mbuf_t)m); } void firewire_inet_event( ifnet_t ifp, __unused protocol_family_t protocol, const struct kev_msg *event) { ifaddr_t *addresses; if (event->vendor_code != KEV_VENDOR_APPLE || event->kev_class != KEV_NETWORK_CLASS || event->kev_subclass != KEV_DL_SUBCLASS || event->event_code != KEV_DL_LINK_ADDRESS_CHANGED) return; if (ifnet_get_address_list_family(ifp, &addresses, AF_INET) == 0) { int i; for (i = 0; addresses[i] != NULL; i++) inet_arp_init_ifaddr(ifp, addresses[i]); ifnet_free_address_list(addresses); } } #endif /* * Convert Ethernet address to printable (loggable) representation. */ static u_char digits[] = "0123456789abcdef"; u_char * firewire_sprintf(register u_char *p, register u_char *ap) { register u_char *cp; register int i; for (cp = p, i = 0; i < 8; i++) { *cp++ = digits[*ap >> 4]; *cp++ = digits[*ap++ & 0xf]; *cp++ = ':'; } *--cp = 0; return (p); }