if_fwsubr.c revision 131177
1130407Sdfr/* 2130407Sdfr * Copyright (c) 2004 Doug Rabson 3130407Sdfr * Copyright (c) 1982, 1989, 1993 4130407Sdfr * The Regents of the University of California. All rights reserved. 5130407Sdfr * 6130407Sdfr * Redistribution and use in source and binary forms, with or without 7130407Sdfr * modification, are permitted provided that the following conditions 8130407Sdfr * are met: 9130407Sdfr * 1. Redistributions of source code must retain the above copyright 10130407Sdfr * notice, this list of conditions and the following disclaimer. 11130407Sdfr * 2. Redistributions in binary form must reproduce the above copyright 12130407Sdfr * notice, this list of conditions and the following disclaimer in the 13130407Sdfr * documentation and/or other materials provided with the distribution. 14130407Sdfr * 4. Neither the name of the University nor the names of its contributors 15130407Sdfr * may be used to endorse or promote products derived from this software 16130407Sdfr * without specific prior written permission. 17130407Sdfr * 18130407Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19130407Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20130407Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21130407Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22130407Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23130407Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24130407Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25130407Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26130407Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27130407Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28130407Sdfr * SUCH DAMAGE. 29130407Sdfr * 30130407Sdfr * $FreeBSD: head/sys/net/if_fwsubr.c 131177 2004-06-27 09:03:22Z pjd $ 31130407Sdfr */ 32130407Sdfr 33130407Sdfr#include "opt_inet.h" 34130407Sdfr#include "opt_inet6.h" 35131177Spjd#include "opt_mac.h" 36130407Sdfr 37130407Sdfr#include <sys/param.h> 38130407Sdfr#include <sys/systm.h> 39130407Sdfr#include <sys/kernel.h> 40131177Spjd#include <sys/mac.h> 41130407Sdfr#include <sys/malloc.h> 42130407Sdfr#include <sys/mbuf.h> 43130407Sdfr#include <sys/socket.h> 44130407Sdfr#include <sys/sockio.h> 45130407Sdfr 46130407Sdfr#include <net/if.h> 47130407Sdfr#include <net/netisr.h> 48130407Sdfr#include <net/route.h> 49130407Sdfr#include <net/if_llc.h> 50130407Sdfr#include <net/if_dl.h> 51130407Sdfr#include <net/if_types.h> 52130407Sdfr#include <net/bpf.h> 53130407Sdfr#include <net/firewire.h> 54130407Sdfr 55130407Sdfr#if defined(INET) || defined(INET6) 56130407Sdfr#include <netinet/in.h> 57130407Sdfr#include <netinet/in_var.h> 58130407Sdfr#include <netinet/if_ether.h> 59130407Sdfr#include <netinet/ip_fw.h> 60130407Sdfr#include <netinet/ip_dummynet.h> 61130407Sdfr#endif 62130407Sdfr#ifdef INET6 63130407Sdfr#include <netinet6/nd6.h> 64130407Sdfr#endif 65130407Sdfr 66130407Sdfr#define IFP2FC(IFP) ((struct fw_com *)IFP) 67130407Sdfr 68130407Sdfrstruct fw_hwaddr firewire_broadcastaddr = { 69130407Sdfr 0xffffffff, 70130407Sdfr 0xffffffff, 71130407Sdfr 0xff, 72130407Sdfr 0xff, 73130407Sdfr 0xffff, 74130407Sdfr 0xffffffff 75130407Sdfr}; 76130407Sdfr 77130407Sdfrstatic int 78130407Sdfrfirewire_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 79130407Sdfr struct rtentry *rt0) 80130407Sdfr{ 81130407Sdfr struct fw_com *fc = (struct fw_com *) ifp; 82130407Sdfr int error, type; 83130407Sdfr struct rtentry *rt; 84130407Sdfr struct m_tag *mtag; 85130407Sdfr union fw_encap *enc; 86130407Sdfr struct fw_hwaddr *destfw; 87130407Sdfr uint8_t speed; 88130407Sdfr uint16_t psize, fsize, dsize; 89130407Sdfr struct mbuf *mtail; 90130407Sdfr int unicast, dgl, foff; 91130407Sdfr static int next_dgl; 92130407Sdfr 93130407Sdfr GIANT_REQUIRED; 94130407Sdfr 95130429Sdfr#ifdef MAC 96130429Sdfr error = mac_check_ifnet_transmit(ifp, m); 97130429Sdfr if (error) 98130429Sdfr goto bad; 99130429Sdfr#endif 100130429Sdfr 101130407Sdfr if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 102130407Sdfr error = ENETDOWN; 103130407Sdfr goto bad; 104130407Sdfr } 105130407Sdfr 106130407Sdfr error = rt_check(&rt, &rt0, dst); 107130407Sdfr if (error) 108130407Sdfr goto bad; 109130407Sdfr 110130407Sdfr /* 111130407Sdfr * For unicast, we make a tag to store the lladdr of the 112130407Sdfr * destination. This might not be the first time we have seen 113130407Sdfr * the packet (for instance, the arp code might be trying to 114130407Sdfr * re-send it after receiving an arp reply) so we only 115130407Sdfr * allocate a tag if there isn't one there already. For 116130407Sdfr * multicast, we will eventually use a different tag to store 117130407Sdfr * the channel number. 118130407Sdfr */ 119130407Sdfr unicast = !(m->m_flags & (M_BCAST | M_MCAST)); 120130407Sdfr if (unicast) { 121130407Sdfr mtag = m_tag_locate(m, MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, NULL); 122130407Sdfr if (!mtag) { 123130407Sdfr mtag = m_tag_alloc(MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, 124130407Sdfr sizeof (struct fw_hwaddr), M_NOWAIT); 125130407Sdfr if (!mtag) { 126130407Sdfr error = ENOMEM; 127130407Sdfr goto bad; 128130407Sdfr } 129130407Sdfr m_tag_prepend(m, mtag); 130130407Sdfr } 131130407Sdfr destfw = (struct fw_hwaddr *)(mtag + 1); 132130407Sdfr } else { 133130407Sdfr destfw = 0; 134130407Sdfr } 135130407Sdfr 136130407Sdfr switch (dst->sa_family) { 137130407Sdfr#ifdef AF_INET 138130407Sdfr case AF_INET: 139130407Sdfr /* 140130407Sdfr * Only bother with arp for unicast. Allocation of 141130407Sdfr * channels etc. for firewire is quite different and 142130407Sdfr * doesn't fit into the arp model. 143130407Sdfr */ 144130407Sdfr if (unicast) { 145130407Sdfr error = arpresolve(ifp, rt, m, dst, (u_char *) destfw); 146130407Sdfr if (error) 147130407Sdfr return (error == EWOULDBLOCK ? 0 : error); 148130407Sdfr } 149130407Sdfr type = ETHERTYPE_IP; 150130407Sdfr break; 151130407Sdfr 152130407Sdfr case AF_ARP: 153130407Sdfr { 154130407Sdfr struct arphdr *ah; 155130407Sdfr ah = mtod(m, struct arphdr *); 156130407Sdfr ah->ar_hrd = htons(ARPHRD_IEEE1394); 157130407Sdfr type = ETHERTYPE_ARP; 158130407Sdfr if (unicast) 159130407Sdfr *destfw = *(struct fw_hwaddr *) ar_tha(ah); 160130407Sdfr 161130407Sdfr /* 162130407Sdfr * The standard arp code leaves a hole for the target 163130407Sdfr * hardware address which we need to close up. 164130407Sdfr */ 165130407Sdfr bcopy(ar_tpa(ah), ar_tha(ah), ah->ar_pln); 166130407Sdfr m_adj(m, -ah->ar_hln); 167130407Sdfr break; 168130407Sdfr } 169130407Sdfr#endif 170130407Sdfr 171130407Sdfr#ifdef INET6 172130407Sdfr case AF_INET6: 173130407Sdfr if (unicast) { 174130407Sdfr error = nd6_storelladdr(&fc->fc_if, rt, m, dst, 175130407Sdfr (u_char *) destfw); 176130407Sdfr if (error) 177130407Sdfr return (error); 178130407Sdfr } 179130407Sdfr type = ETHERTYPE_IPV6; 180130407Sdfr break; 181130407Sdfr#endif 182130407Sdfr 183130407Sdfr default: 184130407Sdfr if_printf(ifp, "can't handle af%d\n", dst->sa_family); 185130407Sdfr error = EAFNOSUPPORT; 186130407Sdfr goto bad; 187130407Sdfr } 188130407Sdfr 189130407Sdfr /* 190130407Sdfr * Let BPF tap off a copy before we encapsulate. 191130407Sdfr */ 192130407Sdfr if (ifp->if_bpf) { 193130407Sdfr struct fw_bpfhdr h; 194130407Sdfr if (unicast) 195130407Sdfr bcopy(destfw, h.firewire_dhost, 8); 196130407Sdfr else 197130407Sdfr bcopy(&firewire_broadcastaddr, h.firewire_dhost, 8); 198130407Sdfr bcopy(&fc->fc_hwaddr, h.firewire_shost, 8); 199130407Sdfr h.firewire_type = htons(type); 200130407Sdfr bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m); 201130407Sdfr } 202130407Sdfr 203130407Sdfr /* 204130407Sdfr * Punt on MCAP for now and send all multicast packets on the 205130407Sdfr * broadcast channel. 206130407Sdfr */ 207130407Sdfr if (m->m_flags & M_MCAST) 208130407Sdfr m->m_flags |= M_BCAST; 209130407Sdfr 210130407Sdfr /* 211130407Sdfr * Figure out what speed to use and what the largest supported 212130407Sdfr * packet size is. For unicast, this is the minimum of what we 213130407Sdfr * can speak and what they can hear. For broadcast, lets be 214130407Sdfr * conservative and use S100. We could possibly improve that 215130407Sdfr * by examining the bus manager's speed map or similar. We 216130407Sdfr * also reduce the packet size for broadcast to account for 217130407Sdfr * the GASP header. 218130407Sdfr */ 219130407Sdfr if (unicast) { 220130407Sdfr speed = min(fc->fc_speed, destfw->sspd); 221130407Sdfr psize = min(512 << speed, 2 << destfw->sender_max_rec); 222130407Sdfr } else { 223130407Sdfr speed = 0; 224130407Sdfr psize = 512 - 2*sizeof(uint32_t); 225130407Sdfr } 226130407Sdfr 227130407Sdfr /* 228130407Sdfr * Next, we encapsulate, possibly fragmenting the original 229130407Sdfr * datagram if it won't fit into a single packet. 230130407Sdfr */ 231130407Sdfr if (m->m_pkthdr.len <= psize - sizeof(uint32_t)) { 232130407Sdfr /* 233130407Sdfr * No fragmentation is necessary. 234130407Sdfr */ 235130407Sdfr M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT); 236130407Sdfr if (!m) { 237130407Sdfr error = ENOBUFS; 238130407Sdfr goto bad; 239130407Sdfr } 240130407Sdfr enc = mtod(m, union fw_encap *); 241130407Sdfr enc->unfrag.ether_type = type; 242130407Sdfr enc->unfrag.lf = FW_ENCAP_UNFRAG; 243130407Sdfr 244130407Sdfr /* 245130407Sdfr * Byte swap the encapsulation header manually. 246130407Sdfr */ 247130407Sdfr enc->ul[0] = htonl(enc->ul[0]); 248130407Sdfr 249130549Smlaier IFQ_HANDOFF(ifp, m, error); 250130549Smlaier return (error); 251130407Sdfr } else { 252130407Sdfr /* 253130407Sdfr * Fragment the datagram, making sure to leave enough 254130407Sdfr * space for the encapsulation header in each packet. 255130407Sdfr */ 256130407Sdfr fsize = psize - 2*sizeof(uint32_t); 257130407Sdfr dgl = next_dgl++; 258130407Sdfr dsize = m->m_pkthdr.len; 259130407Sdfr foff = 0; 260130407Sdfr while (m) { 261130407Sdfr if (m->m_pkthdr.len > fsize) { 262130407Sdfr /* 263130407Sdfr * Split off the tail segment from the 264130407Sdfr * datagram, copying our tags over. 265130407Sdfr */ 266130407Sdfr mtail = m_split(m, fsize, M_DONTWAIT); 267130407Sdfr m_tag_copy_chain(mtail, m, M_NOWAIT); 268130407Sdfr } else { 269130407Sdfr mtail = 0; 270130407Sdfr } 271130407Sdfr 272130407Sdfr /* 273130407Sdfr * Add our encapsulation header to this 274130407Sdfr * fragment and hand it off to the link. 275130407Sdfr */ 276130407Sdfr M_PREPEND(m, 2*sizeof(uint32_t), M_DONTWAIT); 277130407Sdfr if (!m) { 278130407Sdfr error = ENOBUFS; 279130407Sdfr goto bad; 280130407Sdfr } 281130407Sdfr enc = mtod(m, union fw_encap *); 282130407Sdfr if (foff == 0) { 283130407Sdfr enc->firstfrag.lf = FW_ENCAP_FIRST; 284130407Sdfr enc->firstfrag.datagram_size = dsize - 1; 285130407Sdfr enc->firstfrag.ether_type = type; 286130407Sdfr enc->firstfrag.dgl = dgl; 287130407Sdfr } else { 288130407Sdfr if (mtail) 289130407Sdfr enc->nextfrag.lf = FW_ENCAP_NEXT; 290130407Sdfr else 291130407Sdfr enc->nextfrag.lf = FW_ENCAP_LAST; 292130407Sdfr enc->nextfrag.datagram_size = dsize - 1; 293130407Sdfr enc->nextfrag.fragment_offset = foff; 294130407Sdfr enc->nextfrag.dgl = dgl; 295130407Sdfr } 296130407Sdfr foff += m->m_pkthdr.len - 2*sizeof(uint32_t); 297130407Sdfr 298130407Sdfr /* 299130407Sdfr * Byte swap the encapsulation header manually. 300130407Sdfr */ 301130407Sdfr enc->ul[0] = htonl(enc->ul[0]); 302130407Sdfr enc->ul[1] = htonl(enc->ul[1]); 303130407Sdfr 304130549Smlaier IFQ_HANDOFF(ifp, m, error); 305130549Smlaier if (error) { 306130407Sdfr if (mtail) 307130407Sdfr m_freem(mtail); 308130407Sdfr return (ENOBUFS); 309130407Sdfr } 310130407Sdfr 311130407Sdfr m = mtail; 312130407Sdfr } 313130407Sdfr 314130407Sdfr return (0); 315130407Sdfr } 316130407Sdfr 317130407Sdfrbad: 318130407Sdfr if (m) 319130407Sdfr m_freem(m); 320130407Sdfr return (error); 321130407Sdfr} 322130407Sdfr 323130407Sdfrstatic struct mbuf * 324130407Sdfrfirewire_input_fragment(struct fw_com *fc, struct mbuf *m, int src) 325130407Sdfr{ 326130407Sdfr union fw_encap *enc; 327130407Sdfr struct fw_reass *r; 328130407Sdfr struct mbuf *mf, *mprev; 329130407Sdfr int dsize; 330130407Sdfr int fstart, fend, start, end, islast; 331130407Sdfr uint32_t id; 332130407Sdfr 333130407Sdfr GIANT_REQUIRED; 334130407Sdfr 335130407Sdfr /* 336130407Sdfr * Find an existing reassembly buffer or create a new one. 337130407Sdfr */ 338130407Sdfr enc = mtod(m, union fw_encap *); 339130407Sdfr id = enc->firstfrag.dgl | (src << 16); 340130407Sdfr STAILQ_FOREACH(r, &fc->fc_frags, fr_link) 341130407Sdfr if (r->fr_id == id) 342130407Sdfr break; 343130407Sdfr if (!r) { 344130407Sdfr r = malloc(sizeof(struct fw_reass), M_TEMP, M_NOWAIT); 345130407Sdfr if (!r) { 346130407Sdfr m_freem(m); 347130407Sdfr return 0; 348130407Sdfr } 349130407Sdfr r->fr_id = id; 350130407Sdfr r->fr_frags = 0; 351130407Sdfr STAILQ_INSERT_HEAD(&fc->fc_frags, r, fr_link); 352130407Sdfr } 353130407Sdfr 354130407Sdfr /* 355130407Sdfr * If this fragment overlaps any other fragment, we must discard 356130407Sdfr * the partial reassembly and start again. 357130407Sdfr */ 358130407Sdfr if (enc->firstfrag.lf == FW_ENCAP_FIRST) 359130407Sdfr fstart = 0; 360130407Sdfr else 361130407Sdfr fstart = enc->nextfrag.fragment_offset; 362130407Sdfr fend = fstart + m->m_pkthdr.len - 2*sizeof(uint32_t); 363130407Sdfr dsize = enc->nextfrag.datagram_size; 364130407Sdfr islast = (enc->nextfrag.lf == FW_ENCAP_LAST); 365130407Sdfr 366130407Sdfr for (mf = r->fr_frags; mf; mf = mf->m_nextpkt) { 367130407Sdfr enc = mtod(mf, union fw_encap *); 368130407Sdfr if (enc->nextfrag.datagram_size != dsize) { 369130407Sdfr /* 370130407Sdfr * This fragment must be from a different 371130407Sdfr * packet. 372130407Sdfr */ 373130407Sdfr goto bad; 374130407Sdfr } 375130407Sdfr if (enc->firstfrag.lf == FW_ENCAP_FIRST) 376130407Sdfr start = 0; 377130407Sdfr else 378130407Sdfr start = enc->nextfrag.fragment_offset; 379130407Sdfr end = start + mf->m_pkthdr.len - 2*sizeof(uint32_t); 380130407Sdfr if ((fstart < end && fend > start) || 381130407Sdfr (islast && enc->nextfrag.lf == FW_ENCAP_LAST)) { 382130407Sdfr /* 383130407Sdfr * Overlap - discard reassembly buffer and start 384130407Sdfr * again with this fragment. 385130407Sdfr */ 386130407Sdfr goto bad; 387130407Sdfr } 388130407Sdfr } 389130407Sdfr 390130407Sdfr /* 391130407Sdfr * Find where to put this fragment in the list. 392130407Sdfr */ 393130407Sdfr for (mf = r->fr_frags, mprev = NULL; mf; 394130407Sdfr mprev = mf, mf = mf->m_nextpkt) { 395130407Sdfr enc = mtod(mf, union fw_encap *); 396130407Sdfr if (enc->firstfrag.lf == FW_ENCAP_FIRST) 397130407Sdfr start = 0; 398130407Sdfr else 399130407Sdfr start = enc->nextfrag.fragment_offset; 400130407Sdfr if (start >= fend) 401130407Sdfr break; 402130407Sdfr } 403130407Sdfr 404130407Sdfr /* 405130407Sdfr * If this is a last fragment and we are not adding at the end 406130407Sdfr * of the list, discard the buffer. 407130407Sdfr */ 408130407Sdfr if (islast && mprev && mprev->m_nextpkt) 409130407Sdfr goto bad; 410130407Sdfr 411130407Sdfr if (mprev) { 412130407Sdfr m->m_nextpkt = mprev->m_nextpkt; 413130407Sdfr mprev->m_nextpkt = m; 414130407Sdfr 415130407Sdfr /* 416130407Sdfr * Coalesce forwards and see if we can make a whole 417130407Sdfr * datagram. 418130407Sdfr */ 419130407Sdfr enc = mtod(mprev, union fw_encap *); 420130407Sdfr if (enc->firstfrag.lf == FW_ENCAP_FIRST) 421130407Sdfr start = 0; 422130407Sdfr else 423130407Sdfr start = enc->nextfrag.fragment_offset; 424130407Sdfr end = start + mprev->m_pkthdr.len - 2*sizeof(uint32_t); 425130407Sdfr while (end == fstart) { 426130407Sdfr /* 427130407Sdfr * Strip off the encap header from m and 428130407Sdfr * append it to mprev, freeing m. 429130407Sdfr */ 430130407Sdfr m_adj(m, 2*sizeof(uint32_t)); 431130407Sdfr mprev->m_nextpkt = m->m_nextpkt; 432130407Sdfr mprev->m_pkthdr.len += m->m_pkthdr.len; 433130407Sdfr m_cat(mprev, m); 434130407Sdfr 435130407Sdfr if (mprev->m_pkthdr.len == dsize + 1 + 2*sizeof(uint32_t)) { 436130407Sdfr /* 437130407Sdfr * We have assembled a complete packet 438130407Sdfr * we must be finished. Make sure we have 439130407Sdfr * merged the whole chain. 440130407Sdfr */ 441130407Sdfr STAILQ_REMOVE(&fc->fc_frags, r, fw_reass, fr_link); 442130407Sdfr free(r, M_TEMP); 443130407Sdfr m = mprev->m_nextpkt; 444130407Sdfr while (m) { 445130407Sdfr mf = m->m_nextpkt; 446130407Sdfr m_freem(m); 447130407Sdfr m = mf; 448130407Sdfr } 449130407Sdfr mprev->m_nextpkt = NULL; 450130407Sdfr 451130407Sdfr return (mprev); 452130407Sdfr } 453130407Sdfr 454130407Sdfr /* 455130407Sdfr * See if we can continue merging forwards. 456130407Sdfr */ 457130407Sdfr end = fend; 458130407Sdfr m = mprev->m_nextpkt; 459130407Sdfr if (m) { 460130407Sdfr enc = mtod(m, union fw_encap *); 461130407Sdfr if (enc->firstfrag.lf == FW_ENCAP_FIRST) 462130407Sdfr fstart = 0; 463130407Sdfr else 464130407Sdfr fstart = enc->nextfrag.fragment_offset; 465130407Sdfr fend = fstart + m->m_pkthdr.len 466130407Sdfr - 2*sizeof(uint32_t); 467130407Sdfr } else { 468130407Sdfr break; 469130407Sdfr } 470130407Sdfr } 471130407Sdfr } else { 472130407Sdfr m->m_nextpkt = 0; 473130407Sdfr r->fr_frags = m; 474130407Sdfr } 475130407Sdfr 476130407Sdfr return (0); 477130407Sdfr 478130407Sdfrbad: 479130407Sdfr while (r->fr_frags) { 480130407Sdfr mf = r->fr_frags; 481130407Sdfr r->fr_frags = mf->m_nextpkt; 482130407Sdfr m_freem(mf); 483130407Sdfr } 484130407Sdfr m->m_nextpkt = 0; 485130407Sdfr r->fr_frags = m; 486130407Sdfr 487130407Sdfr return (0); 488130407Sdfr} 489130407Sdfr 490130407Sdfrvoid 491130407Sdfrfirewire_input(struct ifnet *ifp, struct mbuf *m, uint16_t src) 492130407Sdfr{ 493130407Sdfr struct fw_com *fc = (struct fw_com *) ifp; 494130407Sdfr union fw_encap *enc; 495130407Sdfr int type, isr; 496130407Sdfr 497130407Sdfr GIANT_REQUIRED; 498130407Sdfr 499130407Sdfr /* 500130407Sdfr * The caller has already stripped off the packet header 501130407Sdfr * (stream or wreqb) and marked the mbuf's M_BCAST flag 502130407Sdfr * appropriately. We de-encapsulate the IP packet and pass it 503130407Sdfr * up the line after handling link-level fragmentation. 504130407Sdfr */ 505130407Sdfr if (m->m_pkthdr.len < sizeof(uint32_t)) { 506130407Sdfr if_printf(ifp, "discarding frame without " 507130407Sdfr "encapsulation header (len %u pkt len %u)\n", 508130407Sdfr m->m_len, m->m_pkthdr.len); 509130407Sdfr } 510130407Sdfr 511130407Sdfr m = m_pullup(m, sizeof(uint32_t)); 512130407Sdfr enc = mtod(m, union fw_encap *); 513130407Sdfr 514130407Sdfr /* 515130407Sdfr * Byte swap the encapsulation header manually. 516130407Sdfr */ 517130407Sdfr enc->ul[0] = htonl(enc->ul[0]); 518130407Sdfr 519130407Sdfr if (enc->unfrag.lf != 0) { 520130407Sdfr m = m_pullup(m, 2*sizeof(uint32_t)); 521130407Sdfr if (!m) 522130407Sdfr return; 523130407Sdfr enc = mtod(m, union fw_encap *); 524130407Sdfr enc->ul[1] = htonl(enc->ul[1]); 525130407Sdfr m = firewire_input_fragment(fc, m, src); 526130407Sdfr if (!m) 527130407Sdfr return; 528130407Sdfr enc = mtod(m, union fw_encap *); 529130407Sdfr type = enc->firstfrag.ether_type; 530130407Sdfr m_adj(m, 2*sizeof(uint32_t)); 531130407Sdfr } else { 532130407Sdfr type = enc->unfrag.ether_type; 533130407Sdfr m_adj(m, sizeof(uint32_t)); 534130407Sdfr } 535130407Sdfr 536130407Sdfr if (m->m_pkthdr.rcvif == NULL) { 537130407Sdfr if_printf(ifp, "discard frame w/o interface pointer\n"); 538130407Sdfr ifp->if_ierrors++; 539130407Sdfr m_freem(m); 540130407Sdfr return; 541130407Sdfr } 542130407Sdfr#ifdef DIAGNOSTIC 543130407Sdfr if (m->m_pkthdr.rcvif != ifp) { 544130407Sdfr if_printf(ifp, "Warning, frame marked as received on %s\n", 545130407Sdfr m->m_pkthdr.rcvif->if_xname); 546130407Sdfr } 547130407Sdfr#endif 548130407Sdfr 549130407Sdfr#ifdef MAC 550130407Sdfr /* 551130407Sdfr * Tag the mbuf with an appropriate MAC label before any other 552130407Sdfr * consumers can get to it. 553130407Sdfr */ 554130407Sdfr mac_create_mbuf_from_ifnet(ifp, m); 555130407Sdfr#endif 556130407Sdfr 557130407Sdfr /* 558130407Sdfr * Give bpf a chance at the packet. The link-level driver 559130407Sdfr * should have left us a tag with the EUID of the sender. 560130407Sdfr */ 561130407Sdfr if (ifp->if_bpf) { 562130407Sdfr struct fw_bpfhdr h; 563130407Sdfr struct m_tag *mtag; 564130407Sdfr 565130407Sdfr mtag = m_tag_locate(m, MTAG_FIREWIRE, MTAG_FIREWIRE_SENDER_EUID, 0); 566130407Sdfr if (mtag) 567130407Sdfr bcopy(mtag + 1, h.firewire_shost, 8); 568130407Sdfr else 569130407Sdfr bcopy(&firewire_broadcastaddr, h.firewire_dhost, 8); 570130407Sdfr bcopy(&fc->fc_hwaddr, h.firewire_dhost, 8); 571130407Sdfr h.firewire_type = htons(type); 572130407Sdfr bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m); 573130407Sdfr } 574130407Sdfr 575130407Sdfr if (ifp->if_flags & IFF_MONITOR) { 576130407Sdfr /* 577130407Sdfr * Interface marked for monitoring; discard packet. 578130407Sdfr */ 579130407Sdfr m_freem(m); 580130407Sdfr return; 581130407Sdfr } 582130407Sdfr 583130407Sdfr ifp->if_ibytes += m->m_pkthdr.len; 584130407Sdfr 585130407Sdfr /* Discard packet if interface is not up */ 586130407Sdfr if ((ifp->if_flags & IFF_UP) == 0) { 587130407Sdfr m_freem(m); 588130407Sdfr return; 589130407Sdfr } 590130407Sdfr 591130407Sdfr if (m->m_flags & (M_BCAST|M_MCAST)) 592130407Sdfr ifp->if_imcasts++; 593130407Sdfr 594130407Sdfr switch (type) { 595130407Sdfr#ifdef INET 596130407Sdfr case ETHERTYPE_IP: 597130407Sdfr if (ip_fastforward(m)) 598130407Sdfr return; 599130407Sdfr isr = NETISR_IP; 600130407Sdfr break; 601130407Sdfr 602130407Sdfr case ETHERTYPE_ARP: 603130407Sdfr { 604130407Sdfr struct arphdr *ah; 605130407Sdfr ah = mtod(m, struct arphdr *); 606130407Sdfr 607130407Sdfr /* 608130407Sdfr * Adjust the arp packet to insert an empty tha slot. 609130407Sdfr */ 610130407Sdfr m->m_len += ah->ar_hln; 611130407Sdfr m->m_pkthdr.len += ah->ar_hln; 612130407Sdfr bcopy(ar_tha(ah), ar_tpa(ah), ah->ar_pln); 613130407Sdfr isr = NETISR_ARP; 614130407Sdfr break; 615130407Sdfr } 616130407Sdfr#endif 617130407Sdfr 618130407Sdfr#ifdef INET6 619130407Sdfr case ETHERTYPE_IPV6: 620130407Sdfr isr = NETISR_IPV6; 621130407Sdfr break; 622130407Sdfr#endif 623130407Sdfr 624130407Sdfr default: 625130407Sdfr m_freem(m); 626130407Sdfr return; 627130407Sdfr } 628130407Sdfr 629130407Sdfr netisr_dispatch(isr, m); 630130407Sdfr} 631130407Sdfr 632130407Sdfrint 633130407Sdfrfirewire_ioctl(struct ifnet *ifp, int command, caddr_t data) 634130407Sdfr{ 635130407Sdfr struct ifaddr *ifa = (struct ifaddr *) data; 636130407Sdfr struct ifreq *ifr = (struct ifreq *) data; 637130407Sdfr int error = 0; 638130407Sdfr 639130407Sdfr switch (command) { 640130407Sdfr case SIOCSIFADDR: 641130407Sdfr ifp->if_flags |= IFF_UP; 642130407Sdfr 643130407Sdfr switch (ifa->ifa_addr->sa_family) { 644130407Sdfr#ifdef INET 645130407Sdfr case AF_INET: 646130407Sdfr ifp->if_init(ifp->if_softc); /* before arpwhohas */ 647130407Sdfr arp_ifinit(ifp, ifa); 648130407Sdfr break; 649130407Sdfr#endif 650130407Sdfr default: 651130407Sdfr ifp->if_init(ifp->if_softc); 652130407Sdfr break; 653130407Sdfr } 654130407Sdfr break; 655130407Sdfr 656130407Sdfr case SIOCGIFADDR: 657130407Sdfr { 658130407Sdfr struct sockaddr *sa; 659130407Sdfr 660130407Sdfr sa = (struct sockaddr *) & ifr->ifr_data; 661130407Sdfr bcopy(&IFP2FC(ifp)->fc_hwaddr, 662130407Sdfr (caddr_t) sa->sa_data, sizeof(struct fw_hwaddr)); 663130407Sdfr } 664130407Sdfr break; 665130407Sdfr 666130407Sdfr case SIOCSIFMTU: 667130407Sdfr /* 668130407Sdfr * Set the interface MTU. 669130407Sdfr */ 670130407Sdfr if (ifr->ifr_mtu > 1500) { 671130407Sdfr error = EINVAL; 672130407Sdfr } else { 673130407Sdfr ifp->if_mtu = ifr->ifr_mtu; 674130407Sdfr } 675130407Sdfr break; 676130407Sdfr default: 677130407Sdfr error = EINVAL; /* XXX netbsd has ENOTTY??? */ 678130407Sdfr break; 679130407Sdfr } 680130407Sdfr return (error); 681130407Sdfr} 682130407Sdfr 683130407Sdfrstatic int 684130407Sdfrfirewire_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, 685130407Sdfr struct sockaddr *sa) 686130407Sdfr{ 687130407Sdfr#ifdef INET 688130407Sdfr struct sockaddr_in *sin; 689130407Sdfr#endif 690130407Sdfr#ifdef INET6 691130407Sdfr struct sockaddr_in6 *sin6; 692130407Sdfr#endif 693130407Sdfr 694130407Sdfr switch(sa->sa_family) { 695130407Sdfr case AF_LINK: 696130407Sdfr /* 697130407Sdfr * No mapping needed. 698130407Sdfr */ 699130407Sdfr *llsa = 0; 700130407Sdfr return 0; 701130407Sdfr 702130407Sdfr#ifdef INET 703130407Sdfr case AF_INET: 704130407Sdfr sin = (struct sockaddr_in *)sa; 705130407Sdfr if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 706130407Sdfr return EADDRNOTAVAIL; 707130407Sdfr *llsa = 0; 708130407Sdfr return 0; 709130407Sdfr#endif 710130407Sdfr#ifdef INET6 711130407Sdfr case AF_INET6: 712130407Sdfr sin6 = (struct sockaddr_in6 *)sa; 713130407Sdfr if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 714130407Sdfr /* 715130407Sdfr * An IP6 address of 0 means listen to all 716130407Sdfr * of the Ethernet multicast address used for IP6. 717130407Sdfr * (This is used for multicast routers.) 718130407Sdfr */ 719130407Sdfr ifp->if_flags |= IFF_ALLMULTI; 720130407Sdfr *llsa = 0; 721130407Sdfr return 0; 722130407Sdfr } 723130407Sdfr if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 724130407Sdfr return EADDRNOTAVAIL; 725130407Sdfr *llsa = 0; 726130407Sdfr return 0; 727130407Sdfr#endif 728130407Sdfr 729130407Sdfr default: 730130407Sdfr /* 731130407Sdfr * Well, the text isn't quite right, but it's the name 732130407Sdfr * that counts... 733130407Sdfr */ 734130407Sdfr return EAFNOSUPPORT; 735130407Sdfr } 736130407Sdfr} 737130407Sdfr 738130407Sdfrvoid 739130407Sdfrfirewire_ifattach(struct ifnet *ifp, struct fw_hwaddr *llc) 740130407Sdfr{ 741130407Sdfr struct fw_com *fc = (struct fw_com *) ifp; 742130407Sdfr struct ifaddr *ifa; 743130407Sdfr struct sockaddr_dl *sdl; 744130407Sdfr static const char* speeds[] = { 745130407Sdfr "S100", "S200", "S400", "S800", 746130407Sdfr "S1600", "S3200" 747130407Sdfr }; 748130407Sdfr 749130407Sdfr fc->fc_speed = llc->sspd; 750130407Sdfr STAILQ_INIT(&fc->fc_frags); 751130407Sdfr 752130407Sdfr ifp->if_type = IFT_IEEE1394; 753130407Sdfr ifp->if_addrlen = sizeof(struct fw_hwaddr); 754130407Sdfr ifp->if_hdrlen = 0; 755130407Sdfr if_attach(ifp); 756130407Sdfr ifp->if_mtu = 1500; /* XXX */ 757130407Sdfr ifp->if_output = firewire_output; 758130407Sdfr ifp->if_resolvemulti = firewire_resolvemulti; 759130407Sdfr ifp->if_broadcastaddr = (u_char *) &firewire_broadcastaddr; 760130407Sdfr 761130407Sdfr ifa = ifaddr_byindex(ifp->if_index); 762130407Sdfr KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 763130407Sdfr sdl = (struct sockaddr_dl *)ifa->ifa_addr; 764130407Sdfr sdl->sdl_type = IFT_IEEE1394; 765130407Sdfr sdl->sdl_alen = ifp->if_addrlen; 766130407Sdfr bcopy(llc, LLADDR(sdl), ifp->if_addrlen); 767130407Sdfr 768130407Sdfr bpfattach(ifp, DLT_APPLE_IP_OVER_IEEE1394, 769130407Sdfr sizeof(struct fw_hwaddr)); 770130407Sdfr 771130407Sdfr if_printf(ifp, "Firewire address: %8D @ 0x%04x%08x, %s, maxrec %d\n", 772130407Sdfr (uint8_t *) &llc->sender_unique_ID_hi, ":", 773130407Sdfr ntohs(llc->sender_unicast_FIFO_hi), 774130407Sdfr ntohl(llc->sender_unicast_FIFO_lo), 775130407Sdfr speeds[llc->sspd], 776130407Sdfr (2 << llc->sender_max_rec)); 777130407Sdfr} 778130407Sdfr 779130407Sdfrvoid 780130407Sdfrfirewire_ifdetach(struct ifnet *ifp) 781130407Sdfr{ 782130407Sdfr bpfdetach(ifp); 783130407Sdfr if_detach(ifp); 784130407Sdfr} 785130407Sdfr 786130407Sdfrvoid 787130407Sdfrfirewire_busreset(struct ifnet *ifp) 788130407Sdfr{ 789130407Sdfr struct fw_com *fc = (struct fw_com *) ifp; 790130407Sdfr struct fw_reass *r; 791130407Sdfr struct mbuf *m; 792130407Sdfr 793130407Sdfr /* 794130407Sdfr * Discard any partial datagrams since the host ids may have changed. 795130407Sdfr */ 796130407Sdfr while ((r = STAILQ_FIRST(&fc->fc_frags))) { 797130407Sdfr STAILQ_REMOVE_HEAD(&fc->fc_frags, fr_link); 798130407Sdfr while (r->fr_frags) { 799130407Sdfr m = r->fr_frags; 800130407Sdfr r->fr_frags = m->m_nextpkt; 801130407Sdfr m_freem(m); 802130407Sdfr } 803130407Sdfr free(r, M_TEMP); 804130407Sdfr } 805130407Sdfr} 806