/* * 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 #include /* For M_LOOP */ #include #include #include "firewire.h" #include } #include "IOFireWireIP.h" struct fw_desc { u_int16_t type; /* Type of protocol stored in data */ u_long protocol_family; /* Protocol family */ u_long data[2]; /* Protocol data */ }; #define FIREWIRE_DESC_BLK_SIZE (10) // // Statics for demux module // struct firewire_desc_blk_str { u_long n_max_used; u_long n_count; u_long n_used; struct fw_desc block_ptr[1]; }; /* Size of the above struct before the array of struct fw_desc */ #define FIREWIRE_DESC_HEADER_SIZE ((size_t)&(((struct firewire_desc_blk_str*)0)->block_ptr[0])) static ifnet_t loop_ifp; //////////////////////////////////////////////////////////////////////////////// // // firewire_del_proto // // IN: ifnet_t ifp, u_long protocol_family // // Invoked by : // dlil_detach_protocol calls this funcion // // Release all descriptor entries owned by this ifp/protocol_family (there may be several). // Setting the type to 0 releases the entry. Eventually we should compact-out // the unused entries. // //////////////////////////////////////////////////////////////////////////////// __private_extern__ int firewire_del_proto(ifnet_t ifp, protocol_family_t protocol_family) { IOFWInterface *fwIf = (IOFWInterface*)ifnet_softc(ifp); if(fwIf == NULL) return EINVAL; struct firewire_desc_blk_str *desc_blk = (struct firewire_desc_blk_str *)fwIf->getFamilyCookie(); if (desc_blk == NULL) return EINVAL; int found = 0; for (u_long current = desc_blk->n_max_used; current > 0; current--) { if (desc_blk->block_ptr[current - 1].protocol_family == protocol_family) { found = 1; desc_blk->block_ptr[current - 1].type = 0; desc_blk->n_used--; } } if (desc_blk->n_used == 0) { FREE(fwIf->getFamilyCookie(), M_IFADDR); fwIf->setFamilyCookie(NULL); } else { /* Decrement n_max_used */ for (; desc_blk->n_max_used > 0 && desc_blk->block_ptr[desc_blk->n_max_used - 1].type == 0; desc_blk->n_max_used--) ; } return found; } //////////////////////////////////////////////////////////////////////////////// // // firewire_add_proto // // IN: ifnet_t ifp, u_long protocol_family, struct ddesc_head_str *desc_head // // Invoked by : // dlil_attach_protocol calls this funcion // // //////////////////////////////////////////////////////////////////////////////// __private_extern__ int firewire_add_proto_internal(ifnet_t ifp, u_long protocol_family, const struct ifnet_demux_desc *demux) { IOFWInterface *fwIf = (IOFWInterface*)ifnet_softc(ifp); if(fwIf == NULL) return EINVAL; struct firewire_desc_blk_str *desc_blk = (struct firewire_desc_blk_str *)fwIf->getFamilyCookie(); struct fw_desc *ed; u_long i; switch (demux->type) { case DLIL_DESC_ETYPE2: if (demux->datalen != 2) return EINVAL; break; default: return EOPNOTSUPP; } // Check for case where all of the descriptor blocks are in use if (desc_blk == NULL || desc_blk->n_used == desc_blk->n_count) { struct firewire_desc_blk_str *tmp; u_long new_count = FIREWIRE_DESC_BLK_SIZE; u_long new_size; u_long old_size = 0; i = 0; if (desc_blk) { new_count += desc_blk->n_count; old_size = desc_blk->n_count * sizeof(struct fw_desc) + FIREWIRE_DESC_HEADER_SIZE; i = desc_blk->n_used; } new_size = new_count * sizeof(struct fw_desc) + FIREWIRE_DESC_HEADER_SIZE; tmp = (struct firewire_desc_blk_str*)_MALLOC(new_size, M_IFADDR, M_WAITOK); if (tmp == 0) return ENOMEM; bzero(tmp + old_size, new_size - old_size); if (desc_blk) { bcopy(desc_blk, tmp, old_size); FREE(desc_blk, M_IFADDR); } desc_blk = tmp; fwIf->setFamilyCookie(desc_blk); desc_blk->n_count = new_count; } else { // Find a free entry for (i = 0; i < desc_blk->n_count; i++) { if (desc_blk->block_ptr[i].type == 0) break; } } // Bump n_max_used if appropriate if (i + 1 > desc_blk->n_max_used) { desc_blk->n_max_used = i + 1; } ed = &desc_blk->block_ptr[i]; ed->protocol_family = protocol_family; ed->data[0] = 0; ed->data[1] = 0; switch (demux->type) { case DLIL_DESC_ETYPE2: /* 2 byte ethernet raw protocol type is at native_type */ /* prtocol must be in network byte order */ ed->type = DLIL_DESC_ETYPE2; ed->data[0] = *(u_int16_t*)demux->data; break; } desc_blk->n_used++; return 0; } int firewire_add_proto(ifnet_t ifp, protocol_family_t protocol, const struct ifnet_demux_desc *demux_list, u_int32_t demux_count) { int error = 0; u_int32_t i; for (i = 0; i < demux_count; i++) { error = firewire_add_proto_internal(ifp, protocol, &demux_list[i]); if (error) { firewire_del_proto(ifp, protocol); break; } } return error; } //////////////////////////////////////////////////////////////////////////////// // // firewire_demux // // IN: ifnet_t ifp,struct mbuf *m,char *frame_header, // u_long *protocol_family // // Invoked by : // dlil_input_packet() // //////////////////////////////////////////////////////////////////////////////// __private_extern__ int firewire_demux(ifnet_t ifp, mbuf_t m, char *frame_header, protocol_family_t *protocol_family) { register struct firewire_header *eh = (struct firewire_header *)frame_header; IOFWInterface *fwIf = (IOFWInterface*)ifnet_softc(ifp); if(fwIf == NULL) return EINVAL; struct firewire_desc_blk_str *desc_blk = (struct firewire_desc_blk_str *)fwIf->getFamilyCookie(); if (desc_blk == NULL) return EINVAL; u_short fw_type = eh->fw_type; u_int16_t type = DLIL_DESC_ETYPE2; u_long maxd = desc_blk->n_max_used; struct fw_desc *ed = desc_blk->block_ptr; /* * Search through the connected protocols for a match. */ for (u_long i = 0; i < maxd; i++) { if ((ed[i].type == type) && (ed[i].data[0] == fw_type)) { *protocol_family = ed[i].protocol_family; return 0; } } return ENOENT; } //////////////////////////////////////////////////////////////////////////////// // // firewire_frameout // // IN: ifnet_t ifp,struct mbuf **m // IN: struct sockaddr *ndest - contains the destination IP Address // IN: char *edst - filled by firewire_arpresolve function in if_firewire.c // IN: char *fw_type // // Invoked by : // dlil.c for dlil_output, Its called after inet_firewire_pre_output // // Encapsulate a packet of type family for the local net. // Use trailer local net encapsulation if enough data in first // packet leaves a multiple of 512 bytes of data in remainder. // //////////////////////////////////////////////////////////////////////////////// __private_extern__ int firewire_frameout(ifnet_t ifp, mbuf_t *m, const struct sockaddr *ndest, const char *edst, const char *fw_type) { register struct firewire_header *fwh; /* * If a simplex interface, and the packet is being sent to our * Ethernet address or a broadcast address, loopback a copy. * XXX To make a simplex device behave exactly like a duplex * device, we should copy in the case of sending to our own * ethernet address (thus letting the original actually appear * on the wire). However, we don't do that here for security * reasons and compatibility with the original behavior. */ if ((ifnet_flags(ifp) & IFF_SIMPLEX) && (mbuf_flags(*m) & M_LOOP)) { if (loop_ifp == NULL) { ifnet_find_by_name("lo0", &loop_ifp); /* * We make an assumption here that lo0 will never go away. This * means we don't have to worry about releasing the reference * later and we don't have to worry about leaking a reference * every time we are loaded. */ ifnet_release(loop_ifp); } if (loop_ifp) { if (mbuf_flags(*m) & M_BCAST) { mbuf_t n; if (mbuf_copym(*m, 0, MBUF_COPYALL, M_WAITOK, &n) == 0) ifnet_output(loop_ifp, PF_INET, n, 0, ndest); } else { if (bcmp(edst, ifnet_lladdr(ifp), FIREWIRE_ADDR_LEN) == 0) { ifnet_output(loop_ifp, PF_INET, *m, 0, ndest); return EJUSTRETURN; } } } } // // Add local net header. If no space in first mbuf, // allocate another. // if (mbuf_prepend(m, sizeof(struct firewire_header), M_DONTWAIT) != 0) return (EJUSTRETURN); // // Lets put this intelligent here into the mbuf // so we can demux on our output path // fwh = (struct firewire_header*)mbuf_data(*m); (void)memcpy(&fwh->fw_type, fw_type,sizeof(fwh->fw_type)); memcpy(fwh->fw_dhost, edst, FIREWIRE_ADDR_LEN); (void)memcpy(fwh->fw_shost, ifnet_lladdr(ifp), sizeof(fwh->fw_shost)); return 0; } //////////////////////////////////////////////////////////////////////////////// // // firewire_add_if // // IN: ifnet_t ifp // //////////////////////////////////////////////////////////////////////////////// __private_extern__ int firewire_add_if(ifnet_t ifp) { return 0; } //////////////////////////////////////////////////////////////////////////////// // // firewire_del_if // // IN: ifnet_t ifp // // Invoked by : // firewire_free calls this function // //////////////////////////////////////////////////////////////////////////////// __private_extern__ int firewire_del_if(IOFWInterface *fwIf) { if (fwIf->getFamilyCookie()) { FREE(fwIf->getFamilyCookie(), M_IFADDR); return 0; } else return ENOENT; } //////////////////////////////////////////////////////////////////////////////// // // firewire_ifmod_ioctl // // IN: ifnet_t ifp // // Invoked by : // dlil_ioctl calls this function, all ioctls are handled at // firewire_inet_prmod_ioctl // //////////////////////////////////////////////////////////////////////////////// __private_extern__ int firewire_ifmod_ioctl(ifnet_t ifp, u_long cmd, void *data) { int err = EOPNOTSUPP; return err; } __private_extern__ int firewire_init_if(ifnet_t ifp) { return 0; }