if_fwsubr.c revision 287861
1139823Simp/*- 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 287861 2015-09-16 14:26:28Z melifaro $ 31130407Sdfr */ 32130407Sdfr 33130407Sdfr#include "opt_inet.h" 34130407Sdfr#include "opt_inet6.h" 35130407Sdfr 36130407Sdfr#include <sys/param.h> 37130407Sdfr#include <sys/systm.h> 38130407Sdfr#include <sys/kernel.h> 39130407Sdfr#include <sys/malloc.h> 40130407Sdfr#include <sys/mbuf.h> 41147256Sbrooks#include <sys/module.h> 42130407Sdfr#include <sys/socket.h> 43130407Sdfr#include <sys/sockio.h> 44130407Sdfr 45130407Sdfr#include <net/if.h> 46257176Sglebius#include <net/if_var.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> 54186119Sqingli#include <net/if_llatbl.h> 55130407Sdfr 56130407Sdfr#if defined(INET) || defined(INET6) 57130407Sdfr#include <netinet/in.h> 58130407Sdfr#include <netinet/in_var.h> 59130407Sdfr#include <netinet/if_ether.h> 60130407Sdfr#endif 61130407Sdfr#ifdef INET6 62130407Sdfr#include <netinet6/nd6.h> 63130407Sdfr#endif 64130407Sdfr 65163606Srwatson#include <security/mac/mac_framework.h> 66163606Srwatson 67227293Sedstatic MALLOC_DEFINE(M_FWCOM, "fw_com", "firewire interface internals"); 68147256Sbrooks 69130407Sdfrstruct fw_hwaddr firewire_broadcastaddr = { 70130407Sdfr 0xffffffff, 71130407Sdfr 0xffffffff, 72130407Sdfr 0xff, 73130407Sdfr 0xff, 74130407Sdfr 0xffff, 75130407Sdfr 0xffffffff 76130407Sdfr}; 77130407Sdfr 78130407Sdfrstatic int 79249925Sglebiusfirewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 80191148Skmacy struct route *ro) 81130407Sdfr{ 82154209Sbrooks struct fw_com *fc = IFP2FWC(ifp); 83130407Sdfr int error, type; 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; 92287861Smelifaro#if defined(INET) || defined(INET6) 93287861Smelifaro int is_gw = 0; 94275211Sbz#endif 95130407Sdfr 96130429Sdfr#ifdef MAC 97172930Srwatson error = mac_ifnet_check_transmit(ifp, m); 98130429Sdfr if (error) 99130429Sdfr goto bad; 100130429Sdfr#endif 101130429Sdfr 102148887Srwatson if (!((ifp->if_flags & IFF_UP) && 103148887Srwatson (ifp->if_drv_flags & IFF_DRV_RUNNING))) { 104130407Sdfr error = ENETDOWN; 105130407Sdfr goto bad; 106130407Sdfr } 107130407Sdfr 108287861Smelifaro#if defined(INET) || defined(INET6) 109287861Smelifaro if (ro != NULL && ro->ro_rt != NULL && 110287861Smelifaro (ro->ro_rt->rt_flags & RTF_GATEWAY) != 0) 111287861Smelifaro is_gw = 1; 112287861Smelifaro#endif 113130407Sdfr /* 114130407Sdfr * For unicast, we make a tag to store the lladdr of the 115130407Sdfr * destination. This might not be the first time we have seen 116130407Sdfr * the packet (for instance, the arp code might be trying to 117130407Sdfr * re-send it after receiving an arp reply) so we only 118130407Sdfr * allocate a tag if there isn't one there already. For 119130407Sdfr * multicast, we will eventually use a different tag to store 120130407Sdfr * the channel number. 121130407Sdfr */ 122130407Sdfr unicast = !(m->m_flags & (M_BCAST | M_MCAST)); 123130407Sdfr if (unicast) { 124130407Sdfr mtag = m_tag_locate(m, MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, NULL); 125130407Sdfr if (!mtag) { 126130407Sdfr mtag = m_tag_alloc(MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, 127130407Sdfr sizeof (struct fw_hwaddr), M_NOWAIT); 128130407Sdfr if (!mtag) { 129130407Sdfr error = ENOMEM; 130130407Sdfr goto bad; 131130407Sdfr } 132130407Sdfr m_tag_prepend(m, mtag); 133130407Sdfr } 134130407Sdfr destfw = (struct fw_hwaddr *)(mtag + 1); 135130407Sdfr } else { 136130407Sdfr destfw = 0; 137130407Sdfr } 138130407Sdfr 139130407Sdfr switch (dst->sa_family) { 140184711Sbz#ifdef INET 141130407Sdfr case AF_INET: 142130407Sdfr /* 143130407Sdfr * Only bother with arp for unicast. Allocation of 144130407Sdfr * channels etc. for firewire is quite different and 145130407Sdfr * doesn't fit into the arp model. 146130407Sdfr */ 147130407Sdfr if (unicast) { 148275196Smelifaro is_gw = 0; 149275196Smelifaro if (ro != NULL && ro->ro_rt != NULL && 150275196Smelifaro (ro->ro_rt->rt_flags & RTF_GATEWAY) != 0) 151275196Smelifaro is_gw = 1; 152275196Smelifaro error = arpresolve(ifp, is_gw, m, dst, (u_char *) destfw, NULL); 153130407Sdfr if (error) 154130407Sdfr return (error == EWOULDBLOCK ? 0 : error); 155130407Sdfr } 156130407Sdfr type = ETHERTYPE_IP; 157130407Sdfr break; 158130407Sdfr 159130407Sdfr case AF_ARP: 160130407Sdfr { 161130407Sdfr struct arphdr *ah; 162130407Sdfr ah = mtod(m, struct arphdr *); 163130407Sdfr ah->ar_hrd = htons(ARPHRD_IEEE1394); 164130407Sdfr type = ETHERTYPE_ARP; 165130407Sdfr if (unicast) 166130407Sdfr *destfw = *(struct fw_hwaddr *) ar_tha(ah); 167130407Sdfr 168130407Sdfr /* 169130407Sdfr * The standard arp code leaves a hole for the target 170130407Sdfr * hardware address which we need to close up. 171130407Sdfr */ 172130407Sdfr bcopy(ar_tpa(ah), ar_tha(ah), ah->ar_pln); 173130407Sdfr m_adj(m, -ah->ar_hln); 174130407Sdfr break; 175130407Sdfr } 176130407Sdfr#endif 177130407Sdfr 178130407Sdfr#ifdef INET6 179130407Sdfr case AF_INET6: 180130407Sdfr if (unicast) { 181287861Smelifaro error = nd6_resolve(fc->fc_ifp, is_gw, m, dst, 182275196Smelifaro (u_char *) destfw, NULL); 183130407Sdfr if (error) 184287861Smelifaro return (error == EWOULDBLOCK ? 0 : error); 185130407Sdfr } 186130407Sdfr type = ETHERTYPE_IPV6; 187130407Sdfr break; 188130407Sdfr#endif 189130407Sdfr 190130407Sdfr default: 191130407Sdfr if_printf(ifp, "can't handle af%d\n", dst->sa_family); 192130407Sdfr error = EAFNOSUPPORT; 193130407Sdfr goto bad; 194130407Sdfr } 195130407Sdfr 196130407Sdfr /* 197130407Sdfr * Let BPF tap off a copy before we encapsulate. 198130407Sdfr */ 199159183Ssam if (bpf_peers_present(ifp->if_bpf)) { 200130407Sdfr struct fw_bpfhdr h; 201130407Sdfr if (unicast) 202130407Sdfr bcopy(destfw, h.firewire_dhost, 8); 203130407Sdfr else 204130407Sdfr bcopy(&firewire_broadcastaddr, h.firewire_dhost, 8); 205130407Sdfr bcopy(&fc->fc_hwaddr, h.firewire_shost, 8); 206130407Sdfr h.firewire_type = htons(type); 207130407Sdfr bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m); 208130407Sdfr } 209130407Sdfr 210130407Sdfr /* 211130407Sdfr * Punt on MCAP for now and send all multicast packets on the 212130407Sdfr * broadcast channel. 213130407Sdfr */ 214130407Sdfr if (m->m_flags & M_MCAST) 215130407Sdfr m->m_flags |= M_BCAST; 216130407Sdfr 217130407Sdfr /* 218130407Sdfr * Figure out what speed to use and what the largest supported 219130407Sdfr * packet size is. For unicast, this is the minimum of what we 220130407Sdfr * can speak and what they can hear. For broadcast, lets be 221130407Sdfr * conservative and use S100. We could possibly improve that 222130407Sdfr * by examining the bus manager's speed map or similar. We 223130407Sdfr * also reduce the packet size for broadcast to account for 224130407Sdfr * the GASP header. 225130407Sdfr */ 226130407Sdfr if (unicast) { 227130407Sdfr speed = min(fc->fc_speed, destfw->sspd); 228130407Sdfr psize = min(512 << speed, 2 << destfw->sender_max_rec); 229130407Sdfr } else { 230130407Sdfr speed = 0; 231130407Sdfr psize = 512 - 2*sizeof(uint32_t); 232130407Sdfr } 233130407Sdfr 234130407Sdfr /* 235130407Sdfr * Next, we encapsulate, possibly fragmenting the original 236130407Sdfr * datagram if it won't fit into a single packet. 237130407Sdfr */ 238130407Sdfr if (m->m_pkthdr.len <= psize - sizeof(uint32_t)) { 239130407Sdfr /* 240130407Sdfr * No fragmentation is necessary. 241130407Sdfr */ 242243882Sglebius M_PREPEND(m, sizeof(uint32_t), M_NOWAIT); 243130407Sdfr if (!m) { 244130407Sdfr error = ENOBUFS; 245130407Sdfr goto bad; 246130407Sdfr } 247130407Sdfr enc = mtod(m, union fw_encap *); 248130407Sdfr enc->unfrag.ether_type = type; 249130407Sdfr enc->unfrag.lf = FW_ENCAP_UNFRAG; 250144114Sgallatin enc->unfrag.reserved = 0; 251130407Sdfr 252130407Sdfr /* 253130407Sdfr * Byte swap the encapsulation header manually. 254130407Sdfr */ 255130407Sdfr enc->ul[0] = htonl(enc->ul[0]); 256130407Sdfr 257185164Skmacy error = (ifp->if_transmit)(ifp, m); 258130549Smlaier return (error); 259130407Sdfr } else { 260130407Sdfr /* 261130407Sdfr * Fragment the datagram, making sure to leave enough 262130407Sdfr * space for the encapsulation header in each packet. 263130407Sdfr */ 264130407Sdfr fsize = psize - 2*sizeof(uint32_t); 265130407Sdfr dgl = next_dgl++; 266130407Sdfr dsize = m->m_pkthdr.len; 267130407Sdfr foff = 0; 268130407Sdfr while (m) { 269130407Sdfr if (m->m_pkthdr.len > fsize) { 270130407Sdfr /* 271130407Sdfr * Split off the tail segment from the 272130407Sdfr * datagram, copying our tags over. 273130407Sdfr */ 274243882Sglebius mtail = m_split(m, fsize, M_NOWAIT); 275130407Sdfr m_tag_copy_chain(mtail, m, M_NOWAIT); 276130407Sdfr } else { 277130407Sdfr mtail = 0; 278130407Sdfr } 279130407Sdfr 280130407Sdfr /* 281130407Sdfr * Add our encapsulation header to this 282130407Sdfr * fragment and hand it off to the link. 283130407Sdfr */ 284243882Sglebius M_PREPEND(m, 2*sizeof(uint32_t), M_NOWAIT); 285130407Sdfr if (!m) { 286130407Sdfr error = ENOBUFS; 287130407Sdfr goto bad; 288130407Sdfr } 289130407Sdfr enc = mtod(m, union fw_encap *); 290130407Sdfr if (foff == 0) { 291130407Sdfr enc->firstfrag.lf = FW_ENCAP_FIRST; 292144114Sgallatin enc->firstfrag.reserved1 = 0; 293144114Sgallatin enc->firstfrag.reserved2 = 0; 294130407Sdfr enc->firstfrag.datagram_size = dsize - 1; 295130407Sdfr enc->firstfrag.ether_type = type; 296130407Sdfr enc->firstfrag.dgl = dgl; 297130407Sdfr } else { 298130407Sdfr if (mtail) 299130407Sdfr enc->nextfrag.lf = FW_ENCAP_NEXT; 300130407Sdfr else 301130407Sdfr enc->nextfrag.lf = FW_ENCAP_LAST; 302144114Sgallatin enc->nextfrag.reserved1 = 0; 303144114Sgallatin enc->nextfrag.reserved2 = 0; 304144114Sgallatin enc->nextfrag.reserved3 = 0; 305130407Sdfr enc->nextfrag.datagram_size = dsize - 1; 306130407Sdfr enc->nextfrag.fragment_offset = foff; 307130407Sdfr enc->nextfrag.dgl = dgl; 308130407Sdfr } 309130407Sdfr foff += m->m_pkthdr.len - 2*sizeof(uint32_t); 310130407Sdfr 311130407Sdfr /* 312130407Sdfr * Byte swap the encapsulation header manually. 313130407Sdfr */ 314130407Sdfr enc->ul[0] = htonl(enc->ul[0]); 315130407Sdfr enc->ul[1] = htonl(enc->ul[1]); 316130407Sdfr 317185164Skmacy error = (ifp->if_transmit)(ifp, m); 318130549Smlaier if (error) { 319130407Sdfr if (mtail) 320130407Sdfr m_freem(mtail); 321130407Sdfr return (ENOBUFS); 322130407Sdfr } 323130407Sdfr 324130407Sdfr m = mtail; 325130407Sdfr } 326130407Sdfr 327130407Sdfr return (0); 328130407Sdfr } 329130407Sdfr 330130407Sdfrbad: 331130407Sdfr if (m) 332130407Sdfr m_freem(m); 333130407Sdfr return (error); 334130407Sdfr} 335130407Sdfr 336130407Sdfrstatic struct mbuf * 337130407Sdfrfirewire_input_fragment(struct fw_com *fc, struct mbuf *m, int src) 338130407Sdfr{ 339130407Sdfr union fw_encap *enc; 340130407Sdfr struct fw_reass *r; 341130407Sdfr struct mbuf *mf, *mprev; 342130407Sdfr int dsize; 343130407Sdfr int fstart, fend, start, end, islast; 344130407Sdfr uint32_t id; 345130407Sdfr 346130407Sdfr /* 347130407Sdfr * Find an existing reassembly buffer or create a new one. 348130407Sdfr */ 349130407Sdfr enc = mtod(m, union fw_encap *); 350130407Sdfr id = enc->firstfrag.dgl | (src << 16); 351130407Sdfr STAILQ_FOREACH(r, &fc->fc_frags, fr_link) 352130407Sdfr if (r->fr_id == id) 353130407Sdfr break; 354130407Sdfr if (!r) { 355130407Sdfr r = malloc(sizeof(struct fw_reass), M_TEMP, M_NOWAIT); 356130407Sdfr if (!r) { 357130407Sdfr m_freem(m); 358130407Sdfr return 0; 359130407Sdfr } 360130407Sdfr r->fr_id = id; 361130407Sdfr r->fr_frags = 0; 362130407Sdfr STAILQ_INSERT_HEAD(&fc->fc_frags, r, fr_link); 363130407Sdfr } 364130407Sdfr 365130407Sdfr /* 366130407Sdfr * If this fragment overlaps any other fragment, we must discard 367130407Sdfr * the partial reassembly and start again. 368130407Sdfr */ 369130407Sdfr if (enc->firstfrag.lf == FW_ENCAP_FIRST) 370130407Sdfr fstart = 0; 371130407Sdfr else 372130407Sdfr fstart = enc->nextfrag.fragment_offset; 373130407Sdfr fend = fstart + m->m_pkthdr.len - 2*sizeof(uint32_t); 374130407Sdfr dsize = enc->nextfrag.datagram_size; 375130407Sdfr islast = (enc->nextfrag.lf == FW_ENCAP_LAST); 376130407Sdfr 377130407Sdfr for (mf = r->fr_frags; mf; mf = mf->m_nextpkt) { 378130407Sdfr enc = mtod(mf, union fw_encap *); 379130407Sdfr if (enc->nextfrag.datagram_size != dsize) { 380130407Sdfr /* 381130407Sdfr * This fragment must be from a different 382130407Sdfr * packet. 383130407Sdfr */ 384130407Sdfr goto bad; 385130407Sdfr } 386130407Sdfr if (enc->firstfrag.lf == FW_ENCAP_FIRST) 387130407Sdfr start = 0; 388130407Sdfr else 389130407Sdfr start = enc->nextfrag.fragment_offset; 390130407Sdfr end = start + mf->m_pkthdr.len - 2*sizeof(uint32_t); 391130407Sdfr if ((fstart < end && fend > start) || 392130407Sdfr (islast && enc->nextfrag.lf == FW_ENCAP_LAST)) { 393130407Sdfr /* 394130407Sdfr * Overlap - discard reassembly buffer and start 395130407Sdfr * again with this fragment. 396130407Sdfr */ 397130407Sdfr goto bad; 398130407Sdfr } 399130407Sdfr } 400130407Sdfr 401130407Sdfr /* 402130407Sdfr * Find where to put this fragment in the list. 403130407Sdfr */ 404130407Sdfr for (mf = r->fr_frags, mprev = NULL; mf; 405130407Sdfr mprev = mf, mf = mf->m_nextpkt) { 406130407Sdfr enc = mtod(mf, union fw_encap *); 407130407Sdfr if (enc->firstfrag.lf == FW_ENCAP_FIRST) 408130407Sdfr start = 0; 409130407Sdfr else 410130407Sdfr start = enc->nextfrag.fragment_offset; 411130407Sdfr if (start >= fend) 412130407Sdfr break; 413130407Sdfr } 414130407Sdfr 415130407Sdfr /* 416130407Sdfr * If this is a last fragment and we are not adding at the end 417130407Sdfr * of the list, discard the buffer. 418130407Sdfr */ 419130407Sdfr if (islast && mprev && mprev->m_nextpkt) 420130407Sdfr goto bad; 421130407Sdfr 422130407Sdfr if (mprev) { 423130407Sdfr m->m_nextpkt = mprev->m_nextpkt; 424130407Sdfr mprev->m_nextpkt = m; 425130407Sdfr 426130407Sdfr /* 427130407Sdfr * Coalesce forwards and see if we can make a whole 428130407Sdfr * datagram. 429130407Sdfr */ 430130407Sdfr enc = mtod(mprev, union fw_encap *); 431130407Sdfr if (enc->firstfrag.lf == FW_ENCAP_FIRST) 432130407Sdfr start = 0; 433130407Sdfr else 434130407Sdfr start = enc->nextfrag.fragment_offset; 435130407Sdfr end = start + mprev->m_pkthdr.len - 2*sizeof(uint32_t); 436130407Sdfr while (end == fstart) { 437130407Sdfr /* 438130407Sdfr * Strip off the encap header from m and 439130407Sdfr * append it to mprev, freeing m. 440130407Sdfr */ 441130407Sdfr m_adj(m, 2*sizeof(uint32_t)); 442130407Sdfr mprev->m_nextpkt = m->m_nextpkt; 443130407Sdfr mprev->m_pkthdr.len += m->m_pkthdr.len; 444130407Sdfr m_cat(mprev, m); 445130407Sdfr 446130407Sdfr if (mprev->m_pkthdr.len == dsize + 1 + 2*sizeof(uint32_t)) { 447130407Sdfr /* 448130407Sdfr * We have assembled a complete packet 449130407Sdfr * we must be finished. Make sure we have 450130407Sdfr * merged the whole chain. 451130407Sdfr */ 452130407Sdfr STAILQ_REMOVE(&fc->fc_frags, r, fw_reass, fr_link); 453130407Sdfr free(r, M_TEMP); 454130407Sdfr m = mprev->m_nextpkt; 455130407Sdfr while (m) { 456130407Sdfr mf = m->m_nextpkt; 457130407Sdfr m_freem(m); 458130407Sdfr m = mf; 459130407Sdfr } 460130407Sdfr mprev->m_nextpkt = NULL; 461130407Sdfr 462130407Sdfr return (mprev); 463130407Sdfr } 464130407Sdfr 465130407Sdfr /* 466130407Sdfr * See if we can continue merging forwards. 467130407Sdfr */ 468130407Sdfr end = fend; 469130407Sdfr m = mprev->m_nextpkt; 470130407Sdfr if (m) { 471130407Sdfr enc = mtod(m, union fw_encap *); 472130407Sdfr if (enc->firstfrag.lf == FW_ENCAP_FIRST) 473130407Sdfr fstart = 0; 474130407Sdfr else 475130407Sdfr fstart = enc->nextfrag.fragment_offset; 476130407Sdfr fend = fstart + m->m_pkthdr.len 477130407Sdfr - 2*sizeof(uint32_t); 478130407Sdfr } else { 479130407Sdfr break; 480130407Sdfr } 481130407Sdfr } 482130407Sdfr } else { 483130407Sdfr m->m_nextpkt = 0; 484130407Sdfr r->fr_frags = m; 485130407Sdfr } 486130407Sdfr 487130407Sdfr return (0); 488130407Sdfr 489130407Sdfrbad: 490130407Sdfr while (r->fr_frags) { 491130407Sdfr mf = r->fr_frags; 492130407Sdfr r->fr_frags = mf->m_nextpkt; 493130407Sdfr m_freem(mf); 494130407Sdfr } 495130407Sdfr m->m_nextpkt = 0; 496130407Sdfr r->fr_frags = m; 497130407Sdfr 498130407Sdfr return (0); 499130407Sdfr} 500130407Sdfr 501130407Sdfrvoid 502130407Sdfrfirewire_input(struct ifnet *ifp, struct mbuf *m, uint16_t src) 503130407Sdfr{ 504154209Sbrooks struct fw_com *fc = IFP2FWC(ifp); 505130407Sdfr union fw_encap *enc; 506130407Sdfr int type, isr; 507130407Sdfr 508130407Sdfr /* 509130407Sdfr * The caller has already stripped off the packet header 510130407Sdfr * (stream or wreqb) and marked the mbuf's M_BCAST flag 511130407Sdfr * appropriately. We de-encapsulate the IP packet and pass it 512130407Sdfr * up the line after handling link-level fragmentation. 513130407Sdfr */ 514130407Sdfr if (m->m_pkthdr.len < sizeof(uint32_t)) { 515130407Sdfr if_printf(ifp, "discarding frame without " 516130407Sdfr "encapsulation header (len %u pkt len %u)\n", 517130407Sdfr m->m_len, m->m_pkthdr.len); 518130407Sdfr } 519130407Sdfr 520130407Sdfr m = m_pullup(m, sizeof(uint32_t)); 521169735Srwatson if (m == NULL) 522169735Srwatson return; 523130407Sdfr enc = mtod(m, union fw_encap *); 524130407Sdfr 525130407Sdfr /* 526130407Sdfr * Byte swap the encapsulation header manually. 527130407Sdfr */ 528151265Simp enc->ul[0] = ntohl(enc->ul[0]); 529130407Sdfr 530130407Sdfr if (enc->unfrag.lf != 0) { 531130407Sdfr m = m_pullup(m, 2*sizeof(uint32_t)); 532130407Sdfr if (!m) 533130407Sdfr return; 534130407Sdfr enc = mtod(m, union fw_encap *); 535151265Simp enc->ul[1] = ntohl(enc->ul[1]); 536130407Sdfr m = firewire_input_fragment(fc, m, src); 537130407Sdfr if (!m) 538130407Sdfr return; 539130407Sdfr enc = mtod(m, union fw_encap *); 540130407Sdfr type = enc->firstfrag.ether_type; 541130407Sdfr m_adj(m, 2*sizeof(uint32_t)); 542130407Sdfr } else { 543130407Sdfr type = enc->unfrag.ether_type; 544130407Sdfr m_adj(m, sizeof(uint32_t)); 545130407Sdfr } 546130407Sdfr 547130407Sdfr if (m->m_pkthdr.rcvif == NULL) { 548130407Sdfr if_printf(ifp, "discard frame w/o interface pointer\n"); 549271867Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 550130407Sdfr m_freem(m); 551130407Sdfr return; 552130407Sdfr } 553130407Sdfr#ifdef DIAGNOSTIC 554130407Sdfr if (m->m_pkthdr.rcvif != ifp) { 555130407Sdfr if_printf(ifp, "Warning, frame marked as received on %s\n", 556130407Sdfr m->m_pkthdr.rcvif->if_xname); 557130407Sdfr } 558130407Sdfr#endif 559130407Sdfr 560130407Sdfr#ifdef MAC 561130407Sdfr /* 562130407Sdfr * Tag the mbuf with an appropriate MAC label before any other 563130407Sdfr * consumers can get to it. 564130407Sdfr */ 565172930Srwatson mac_ifnet_create_mbuf(ifp, m); 566130407Sdfr#endif 567130407Sdfr 568130407Sdfr /* 569130407Sdfr * Give bpf a chance at the packet. The link-level driver 570130407Sdfr * should have left us a tag with the EUID of the sender. 571130407Sdfr */ 572159183Ssam if (bpf_peers_present(ifp->if_bpf)) { 573130407Sdfr struct fw_bpfhdr h; 574130407Sdfr struct m_tag *mtag; 575130407Sdfr 576130407Sdfr mtag = m_tag_locate(m, MTAG_FIREWIRE, MTAG_FIREWIRE_SENDER_EUID, 0); 577130407Sdfr if (mtag) 578130407Sdfr bcopy(mtag + 1, h.firewire_shost, 8); 579130407Sdfr else 580130407Sdfr bcopy(&firewire_broadcastaddr, h.firewire_dhost, 8); 581130407Sdfr bcopy(&fc->fc_hwaddr, h.firewire_dhost, 8); 582130407Sdfr h.firewire_type = htons(type); 583130407Sdfr bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m); 584130407Sdfr } 585130407Sdfr 586130407Sdfr if (ifp->if_flags & IFF_MONITOR) { 587130407Sdfr /* 588130407Sdfr * Interface marked for monitoring; discard packet. 589130407Sdfr */ 590130407Sdfr m_freem(m); 591130407Sdfr return; 592130407Sdfr } 593130407Sdfr 594271867Sglebius if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); 595130407Sdfr 596130407Sdfr /* Discard packet if interface is not up */ 597130407Sdfr if ((ifp->if_flags & IFF_UP) == 0) { 598130407Sdfr m_freem(m); 599130407Sdfr return; 600130407Sdfr } 601130407Sdfr 602130407Sdfr if (m->m_flags & (M_BCAST|M_MCAST)) 603271867Sglebius if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1); 604130407Sdfr 605130407Sdfr switch (type) { 606130407Sdfr#ifdef INET 607130407Sdfr case ETHERTYPE_IP: 608154518Sandre if ((m = ip_fastforward(m)) == NULL) 609130407Sdfr return; 610130407Sdfr isr = NETISR_IP; 611130407Sdfr break; 612130407Sdfr 613130407Sdfr case ETHERTYPE_ARP: 614130407Sdfr { 615130407Sdfr struct arphdr *ah; 616130407Sdfr ah = mtod(m, struct arphdr *); 617130407Sdfr 618130407Sdfr /* 619130407Sdfr * Adjust the arp packet to insert an empty tha slot. 620130407Sdfr */ 621130407Sdfr m->m_len += ah->ar_hln; 622130407Sdfr m->m_pkthdr.len += ah->ar_hln; 623130407Sdfr bcopy(ar_tha(ah), ar_tpa(ah), ah->ar_pln); 624130407Sdfr isr = NETISR_ARP; 625130407Sdfr break; 626130407Sdfr } 627130407Sdfr#endif 628130407Sdfr 629130407Sdfr#ifdef INET6 630130407Sdfr case ETHERTYPE_IPV6: 631130407Sdfr isr = NETISR_IPV6; 632130407Sdfr break; 633130407Sdfr#endif 634130407Sdfr 635130407Sdfr default: 636130407Sdfr m_freem(m); 637130407Sdfr return; 638130407Sdfr } 639130407Sdfr 640223741Sbz M_SETFIB(m, ifp->if_fib); 641130407Sdfr netisr_dispatch(isr, m); 642130407Sdfr} 643130407Sdfr 644130407Sdfrint 645194581Srdivackyfirewire_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 646130407Sdfr{ 647130407Sdfr struct ifaddr *ifa = (struct ifaddr *) data; 648130407Sdfr struct ifreq *ifr = (struct ifreq *) data; 649130407Sdfr int error = 0; 650130407Sdfr 651130407Sdfr switch (command) { 652130407Sdfr case SIOCSIFADDR: 653130407Sdfr ifp->if_flags |= IFF_UP; 654130407Sdfr 655130407Sdfr switch (ifa->ifa_addr->sa_family) { 656130407Sdfr#ifdef INET 657130407Sdfr case AF_INET: 658130407Sdfr ifp->if_init(ifp->if_softc); /* before arpwhohas */ 659130407Sdfr arp_ifinit(ifp, ifa); 660130407Sdfr break; 661130407Sdfr#endif 662130407Sdfr default: 663130407Sdfr ifp->if_init(ifp->if_softc); 664130407Sdfr break; 665130407Sdfr } 666130407Sdfr break; 667130407Sdfr 668130407Sdfr case SIOCGIFADDR: 669130407Sdfr { 670130407Sdfr struct sockaddr *sa; 671130407Sdfr 672130407Sdfr sa = (struct sockaddr *) & ifr->ifr_data; 673154209Sbrooks bcopy(&IFP2FWC(ifp)->fc_hwaddr, 674130407Sdfr (caddr_t) sa->sa_data, sizeof(struct fw_hwaddr)); 675130407Sdfr } 676130407Sdfr break; 677130407Sdfr 678130407Sdfr case SIOCSIFMTU: 679130407Sdfr /* 680130407Sdfr * Set the interface MTU. 681130407Sdfr */ 682130407Sdfr if (ifr->ifr_mtu > 1500) { 683130407Sdfr error = EINVAL; 684130407Sdfr } else { 685130407Sdfr ifp->if_mtu = ifr->ifr_mtu; 686130407Sdfr } 687130407Sdfr break; 688130407Sdfr default: 689130407Sdfr error = EINVAL; /* XXX netbsd has ENOTTY??? */ 690130407Sdfr break; 691130407Sdfr } 692130407Sdfr return (error); 693130407Sdfr} 694130407Sdfr 695130407Sdfrstatic int 696130407Sdfrfirewire_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, 697130407Sdfr struct sockaddr *sa) 698130407Sdfr{ 699130407Sdfr#ifdef INET 700130407Sdfr struct sockaddr_in *sin; 701130407Sdfr#endif 702130407Sdfr#ifdef INET6 703130407Sdfr struct sockaddr_in6 *sin6; 704130407Sdfr#endif 705130407Sdfr 706130407Sdfr switch(sa->sa_family) { 707130407Sdfr case AF_LINK: 708130407Sdfr /* 709130407Sdfr * No mapping needed. 710130407Sdfr */ 711130407Sdfr *llsa = 0; 712130407Sdfr return 0; 713130407Sdfr 714130407Sdfr#ifdef INET 715130407Sdfr case AF_INET: 716130407Sdfr sin = (struct sockaddr_in *)sa; 717130407Sdfr if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 718130407Sdfr return EADDRNOTAVAIL; 719130407Sdfr *llsa = 0; 720130407Sdfr return 0; 721130407Sdfr#endif 722130407Sdfr#ifdef INET6 723130407Sdfr case AF_INET6: 724130407Sdfr sin6 = (struct sockaddr_in6 *)sa; 725130407Sdfr if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 726130407Sdfr /* 727130407Sdfr * An IP6 address of 0 means listen to all 728130407Sdfr * of the Ethernet multicast address used for IP6. 729130407Sdfr * (This is used for multicast routers.) 730130407Sdfr */ 731130407Sdfr ifp->if_flags |= IFF_ALLMULTI; 732130407Sdfr *llsa = 0; 733130407Sdfr return 0; 734130407Sdfr } 735130407Sdfr if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 736130407Sdfr return EADDRNOTAVAIL; 737130407Sdfr *llsa = 0; 738130407Sdfr return 0; 739130407Sdfr#endif 740130407Sdfr 741130407Sdfr default: 742130407Sdfr /* 743130407Sdfr * Well, the text isn't quite right, but it's the name 744130407Sdfr * that counts... 745130407Sdfr */ 746130407Sdfr return EAFNOSUPPORT; 747130407Sdfr } 748130407Sdfr} 749130407Sdfr 750130407Sdfrvoid 751130407Sdfrfirewire_ifattach(struct ifnet *ifp, struct fw_hwaddr *llc) 752130407Sdfr{ 753154209Sbrooks struct fw_com *fc = IFP2FWC(ifp); 754130407Sdfr struct ifaddr *ifa; 755130407Sdfr struct sockaddr_dl *sdl; 756130407Sdfr static const char* speeds[] = { 757130407Sdfr "S100", "S200", "S400", "S800", 758130407Sdfr "S1600", "S3200" 759130407Sdfr }; 760130407Sdfr 761130407Sdfr fc->fc_speed = llc->sspd; 762130407Sdfr STAILQ_INIT(&fc->fc_frags); 763130407Sdfr 764130407Sdfr ifp->if_addrlen = sizeof(struct fw_hwaddr); 765130407Sdfr ifp->if_hdrlen = 0; 766130407Sdfr if_attach(ifp); 767130407Sdfr ifp->if_mtu = 1500; /* XXX */ 768130407Sdfr ifp->if_output = firewire_output; 769130407Sdfr ifp->if_resolvemulti = firewire_resolvemulti; 770130407Sdfr ifp->if_broadcastaddr = (u_char *) &firewire_broadcastaddr; 771130407Sdfr 772152315Sru ifa = ifp->if_addr; 773130407Sdfr KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 774130407Sdfr sdl = (struct sockaddr_dl *)ifa->ifa_addr; 775130407Sdfr sdl->sdl_type = IFT_IEEE1394; 776130407Sdfr sdl->sdl_alen = ifp->if_addrlen; 777130407Sdfr bcopy(llc, LLADDR(sdl), ifp->if_addrlen); 778130407Sdfr 779130407Sdfr bpfattach(ifp, DLT_APPLE_IP_OVER_IEEE1394, 780130407Sdfr sizeof(struct fw_hwaddr)); 781130407Sdfr 782130407Sdfr if_printf(ifp, "Firewire address: %8D @ 0x%04x%08x, %s, maxrec %d\n", 783130407Sdfr (uint8_t *) &llc->sender_unique_ID_hi, ":", 784130407Sdfr ntohs(llc->sender_unicast_FIFO_hi), 785130407Sdfr ntohl(llc->sender_unicast_FIFO_lo), 786130407Sdfr speeds[llc->sspd], 787130407Sdfr (2 << llc->sender_max_rec)); 788130407Sdfr} 789130407Sdfr 790130407Sdfrvoid 791130407Sdfrfirewire_ifdetach(struct ifnet *ifp) 792130407Sdfr{ 793130407Sdfr bpfdetach(ifp); 794130407Sdfr if_detach(ifp); 795130407Sdfr} 796130407Sdfr 797130407Sdfrvoid 798130407Sdfrfirewire_busreset(struct ifnet *ifp) 799130407Sdfr{ 800154209Sbrooks struct fw_com *fc = IFP2FWC(ifp); 801130407Sdfr struct fw_reass *r; 802130407Sdfr struct mbuf *m; 803130407Sdfr 804130407Sdfr /* 805130407Sdfr * Discard any partial datagrams since the host ids may have changed. 806130407Sdfr */ 807130407Sdfr while ((r = STAILQ_FIRST(&fc->fc_frags))) { 808130407Sdfr STAILQ_REMOVE_HEAD(&fc->fc_frags, fr_link); 809130407Sdfr while (r->fr_frags) { 810130407Sdfr m = r->fr_frags; 811130407Sdfr r->fr_frags = m->m_nextpkt; 812130407Sdfr m_freem(m); 813130407Sdfr } 814130407Sdfr free(r, M_TEMP); 815130407Sdfr } 816130407Sdfr} 817147256Sbrooks 818147256Sbrooksstatic void * 819147256Sbrooksfirewire_alloc(u_char type, struct ifnet *ifp) 820147256Sbrooks{ 821147256Sbrooks struct fw_com *fc; 822147256Sbrooks 823147256Sbrooks fc = malloc(sizeof(struct fw_com), M_FWCOM, M_WAITOK | M_ZERO); 824147256Sbrooks fc->fc_ifp = ifp; 825147256Sbrooks 826147256Sbrooks return (fc); 827147256Sbrooks} 828147256Sbrooks 829147256Sbrooksstatic void 830147256Sbrooksfirewire_free(void *com, u_char type) 831147256Sbrooks{ 832147256Sbrooks 833147256Sbrooks free(com, M_FWCOM); 834147256Sbrooks} 835147256Sbrooks 836147256Sbrooksstatic int 837147256Sbrooksfirewire_modevent(module_t mod, int type, void *data) 838147256Sbrooks{ 839147256Sbrooks 840147256Sbrooks switch (type) { 841147256Sbrooks case MOD_LOAD: 842147256Sbrooks if_register_com_alloc(IFT_IEEE1394, 843147256Sbrooks firewire_alloc, firewire_free); 844147256Sbrooks break; 845147256Sbrooks case MOD_UNLOAD: 846147256Sbrooks if_deregister_com_alloc(IFT_IEEE1394); 847147256Sbrooks break; 848147256Sbrooks default: 849147256Sbrooks return (EOPNOTSUPP); 850147256Sbrooks } 851147256Sbrooks 852147256Sbrooks return (0); 853147256Sbrooks} 854147256Sbrooks 855147256Sbrooksstatic moduledata_t firewire_mod = { 856150988Savatar "if_firewire", 857147256Sbrooks firewire_modevent, 858241394Skevlo 0 859147256Sbrooks}; 860147256Sbrooks 861150988SavatarDECLARE_MODULE(if_firewire, firewire_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 862150988SavatarMODULE_VERSION(if_firewire, 1); 863