if_fwsubr.c revision 130407
1275988Sngie/* 2240116Smarcel * Copyright (c) 2004 Doug Rabson 3240116Smarcel * Copyright (c) 1982, 1989, 1993 4240116Smarcel * The Regents of the University of California. All rights reserved. 5240116Smarcel * 6240116Smarcel * Redistribution and use in source and binary forms, with or without 7240116Smarcel * modification, are permitted provided that the following conditions 8240116Smarcel * are met: 9240116Smarcel * 1. Redistributions of source code must retain the above copyright 10240116Smarcel * notice, this list of conditions and the following disclaimer. 11240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright 12240116Smarcel * notice, this list of conditions and the following disclaimer in the 13240116Smarcel * documentation and/or other materials provided with the distribution. 14240116Smarcel * 3. All advertising materials mentioning features or use of this software 15240116Smarcel * must display the following acknowledgement: 16240116Smarcel * This product includes software developed by the University of 17240116Smarcel * California, Berkeley and its contributors. 18240116Smarcel * 4. Neither the name of the University nor the names of its contributors 19240116Smarcel * may be used to endorse or promote products derived from this software 20240116Smarcel * without specific prior written permission. 21240116Smarcel * 22240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23240116Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24275988Sngie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25240116Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26275988Sngie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27275988Sngie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28240116Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29240116Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30240116Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31240116Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32240116Smarcel * SUCH DAMAGE. 33240116Smarcel * 34240116Smarcel * $FreeBSD: head/sys/net/if_fwsubr.c 130407 2004-06-13 10:54:36Z dfr $ 35240116Smarcel */ 36240116Smarcel 37240116Smarcel#include "opt_inet.h" 38240116Smarcel#include "opt_inet6.h" 39240116Smarcel 40240116Smarcel#include <sys/param.h> 41240116Smarcel#include <sys/systm.h> 42275988Sngie#include <sys/kernel.h> 43275988Sngie#include <sys/malloc.h> 44275988Sngie#include <sys/mbuf.h> 45275988Sngie#include <sys/socket.h> 46275988Sngie#include <sys/sockio.h> 47240116Smarcel 48240116Smarcel#include <net/if.h> 49240116Smarcel#include <net/netisr.h> 50240116Smarcel#include <net/route.h> 51240116Smarcel#include <net/if_llc.h> 52240116Smarcel#include <net/if_dl.h> 53240116Smarcel#include <net/if_types.h> 54240116Smarcel#include <net/bpf.h> 55240116Smarcel#include <net/firewire.h> 56240116Smarcel 57240116Smarcel#if defined(INET) || defined(INET6) 58240116Smarcel#include <netinet/in.h> 59240116Smarcel#include <netinet/in_var.h> 60240116Smarcel#include <netinet/if_ether.h> 61240116Smarcel#include <netinet/ip_fw.h> 62240116Smarcel#include <netinet/ip_dummynet.h> 63240116Smarcel#endif 64240116Smarcel#ifdef INET6 65240116Smarcel#include <netinet6/nd6.h> 66240116Smarcel#endif 67240116Smarcel 68240116Smarcel#define IFP2FC(IFP) ((struct fw_com *)IFP) 69240116Smarcel 70240116Smarcelstruct fw_hwaddr firewire_broadcastaddr = { 71240116Smarcel 0xffffffff, 72240116Smarcel 0xffffffff, 73240116Smarcel 0xff, 74240116Smarcel 0xff, 75240116Smarcel 0xffff, 76240116Smarcel 0xffffffff 77240116Smarcel}; 78240116Smarcel 79240116Smarcelstatic int 80240116Smarcelfirewire_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 81240116Smarcel struct rtentry *rt0) 82240116Smarcel{ 83240116Smarcel struct fw_com *fc = (struct fw_com *) ifp; 84240116Smarcel int error, type; 85240116Smarcel struct rtentry *rt; 86240116Smarcel struct m_tag *mtag; 87240116Smarcel union fw_encap *enc; 88240116Smarcel struct fw_hwaddr *destfw; 89240116Smarcel uint8_t speed; 90240116Smarcel uint16_t psize, fsize, dsize; 91240116Smarcel struct mbuf *mtail; 92240116Smarcel int unicast, dgl, foff; 93240116Smarcel static int next_dgl; 94240116Smarcel 95240116Smarcel GIANT_REQUIRED; 96240116Smarcel 97240116Smarcel if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 98240116Smarcel error = ENETDOWN; 99240116Smarcel goto bad; 100240116Smarcel } 101240116Smarcel 102240116Smarcel error = rt_check(&rt, &rt0, dst); 103240116Smarcel if (error) 104240116Smarcel goto bad; 105240116Smarcel 106240116Smarcel /* 107240116Smarcel * For unicast, we make a tag to store the lladdr of the 108240116Smarcel * destination. This might not be the first time we have seen 109240116Smarcel * the packet (for instance, the arp code might be trying to 110240116Smarcel * re-send it after receiving an arp reply) so we only 111240116Smarcel * allocate a tag if there isn't one there already. For 112240116Smarcel * multicast, we will eventually use a different tag to store 113240116Smarcel * the channel number. 114240116Smarcel */ 115240116Smarcel unicast = !(m->m_flags & (M_BCAST | M_MCAST)); 116240116Smarcel if (unicast) { 117240116Smarcel mtag = m_tag_locate(m, MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, NULL); 118240116Smarcel if (!mtag) { 119240116Smarcel mtag = m_tag_alloc(MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, 120240116Smarcel sizeof (struct fw_hwaddr), M_NOWAIT); 121240116Smarcel if (!mtag) { 122240116Smarcel error = ENOMEM; 123240116Smarcel goto bad; 124240116Smarcel } 125240116Smarcel m_tag_prepend(m, mtag); 126240116Smarcel } 127240116Smarcel destfw = (struct fw_hwaddr *)(mtag + 1); 128240116Smarcel } else { 129240116Smarcel destfw = 0; 130240116Smarcel } 131240116Smarcel 132240116Smarcel switch (dst->sa_family) { 133240116Smarcel#ifdef AF_INET 134240116Smarcel case AF_INET: 135240116Smarcel /* 136240116Smarcel * Only bother with arp for unicast. Allocation of 137240116Smarcel * channels etc. for firewire is quite different and 138240116Smarcel * doesn't fit into the arp model. 139240116Smarcel */ 140240116Smarcel if (unicast) { 141240116Smarcel error = arpresolve(ifp, rt, m, dst, (u_char *) destfw); 142240116Smarcel if (error) 143240116Smarcel return (error == EWOULDBLOCK ? 0 : error); 144240116Smarcel } 145240116Smarcel type = ETHERTYPE_IP; 146240116Smarcel break; 147240116Smarcel 148240116Smarcel case AF_ARP: 149240116Smarcel { 150240116Smarcel struct arphdr *ah; 151240116Smarcel ah = mtod(m, struct arphdr *); 152240116Smarcel ah->ar_hrd = htons(ARPHRD_IEEE1394); 153240116Smarcel type = ETHERTYPE_ARP; 154240116Smarcel if (unicast) 155240116Smarcel *destfw = *(struct fw_hwaddr *) ar_tha(ah); 156240116Smarcel 157240116Smarcel /* 158240116Smarcel * The standard arp code leaves a hole for the target 159240116Smarcel * hardware address which we need to close up. 160240116Smarcel */ 161240116Smarcel bcopy(ar_tpa(ah), ar_tha(ah), ah->ar_pln); 162240116Smarcel m_adj(m, -ah->ar_hln); 163240116Smarcel break; 164240116Smarcel } 165240116Smarcel#endif 166240116Smarcel 167240116Smarcel#ifdef INET6 168240116Smarcel case AF_INET6: 169240116Smarcel if (unicast) { 170240116Smarcel error = nd6_storelladdr(&fc->fc_if, rt, m, dst, 171240116Smarcel (u_char *) destfw); 172240116Smarcel if (error) 173240116Smarcel return (error); 174240116Smarcel } 175240116Smarcel type = ETHERTYPE_IPV6; 176240116Smarcel break; 177240116Smarcel#endif 178240116Smarcel 179240116Smarcel default: 180240116Smarcel if_printf(ifp, "can't handle af%d\n", dst->sa_family); 181240116Smarcel error = EAFNOSUPPORT; 182240116Smarcel goto bad; 183240116Smarcel } 184240116Smarcel 185240116Smarcel /* 186240116Smarcel * Let BPF tap off a copy before we encapsulate. 187240116Smarcel */ 188240116Smarcel if (ifp->if_bpf) { 189240116Smarcel struct fw_bpfhdr h; 190240116Smarcel if (unicast) 191240116Smarcel bcopy(destfw, h.firewire_dhost, 8); 192240116Smarcel else 193240116Smarcel bcopy(&firewire_broadcastaddr, h.firewire_dhost, 8); 194240116Smarcel bcopy(&fc->fc_hwaddr, h.firewire_shost, 8); 195240116Smarcel h.firewire_type = htons(type); 196240116Smarcel bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m); 197240116Smarcel } 198240116Smarcel 199240116Smarcel /* 200240116Smarcel * Punt on MCAP for now and send all multicast packets on the 201240116Smarcel * broadcast channel. 202240116Smarcel */ 203240116Smarcel if (m->m_flags & M_MCAST) 204240116Smarcel m->m_flags |= M_BCAST; 205240116Smarcel 206240116Smarcel /* 207240116Smarcel * Figure out what speed to use and what the largest supported 208240116Smarcel * packet size is. For unicast, this is the minimum of what we 209240116Smarcel * can speak and what they can hear. For broadcast, lets be 210240116Smarcel * conservative and use S100. We could possibly improve that 211240116Smarcel * by examining the bus manager's speed map or similar. We 212240116Smarcel * also reduce the packet size for broadcast to account for 213240116Smarcel * the GASP header. 214240116Smarcel */ 215240116Smarcel if (unicast) { 216240116Smarcel speed = min(fc->fc_speed, destfw->sspd); 217240116Smarcel psize = min(512 << speed, 2 << destfw->sender_max_rec); 218240116Smarcel } else { 219240116Smarcel speed = 0; 220240116Smarcel psize = 512 - 2*sizeof(uint32_t); 221240116Smarcel } 222240116Smarcel 223240116Smarcel /* 224240116Smarcel * Next, we encapsulate, possibly fragmenting the original 225240116Smarcel * datagram if it won't fit into a single packet. 226240116Smarcel */ 227240116Smarcel if (m->m_pkthdr.len <= psize - sizeof(uint32_t)) { 228240116Smarcel /* 229240116Smarcel * No fragmentation is necessary. 230240116Smarcel */ 231240116Smarcel M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT); 232240116Smarcel if (!m) { 233240116Smarcel error = ENOBUFS; 234240116Smarcel goto bad; 235240116Smarcel } 236240116Smarcel enc = mtod(m, union fw_encap *); 237240116Smarcel enc->unfrag.ether_type = type; 238240116Smarcel enc->unfrag.lf = FW_ENCAP_UNFRAG; 239240116Smarcel 240240116Smarcel /* 241240116Smarcel * Byte swap the encapsulation header manually. 242240116Smarcel */ 243240116Smarcel enc->ul[0] = htonl(enc->ul[0]); 244240116Smarcel 245240116Smarcel return (IF_HANDOFF(&ifp->if_snd, m, ifp) ? 0 : ENOBUFS); 246240116Smarcel } else { 247240116Smarcel /* 248240116Smarcel * Fragment the datagram, making sure to leave enough 249240116Smarcel * space for the encapsulation header in each packet. 250240116Smarcel */ 251240116Smarcel fsize = psize - 2*sizeof(uint32_t); 252240116Smarcel dgl = next_dgl++; 253240116Smarcel dsize = m->m_pkthdr.len; 254240116Smarcel foff = 0; 255240116Smarcel while (m) { 256240116Smarcel if (m->m_pkthdr.len > fsize) { 257240116Smarcel /* 258240116Smarcel * Split off the tail segment from the 259240116Smarcel * datagram, copying our tags over. 260240116Smarcel */ 261240116Smarcel mtail = m_split(m, fsize, M_DONTWAIT); 262240116Smarcel m_tag_copy_chain(mtail, m, M_NOWAIT); 263240116Smarcel } else { 264240116Smarcel mtail = 0; 265240116Smarcel } 266240116Smarcel 267240116Smarcel /* 268240116Smarcel * Add our encapsulation header to this 269240116Smarcel * fragment and hand it off to the link. 270240116Smarcel */ 271240116Smarcel M_PREPEND(m, 2*sizeof(uint32_t), M_DONTWAIT); 272240116Smarcel if (!m) { 273240116Smarcel error = ENOBUFS; 274240116Smarcel goto bad; 275240116Smarcel } 276240116Smarcel enc = mtod(m, union fw_encap *); 277240116Smarcel if (foff == 0) { 278240116Smarcel enc->firstfrag.lf = FW_ENCAP_FIRST; 279240116Smarcel enc->firstfrag.datagram_size = dsize - 1; 280240116Smarcel enc->firstfrag.ether_type = type; 281240116Smarcel enc->firstfrag.dgl = dgl; 282240116Smarcel } else { 283240116Smarcel if (mtail) 284240116Smarcel enc->nextfrag.lf = FW_ENCAP_NEXT; 285240116Smarcel else 286240116Smarcel enc->nextfrag.lf = FW_ENCAP_LAST; 287240116Smarcel enc->nextfrag.datagram_size = dsize - 1; 288240116Smarcel enc->nextfrag.fragment_offset = foff; 289240116Smarcel enc->nextfrag.dgl = dgl; 290240116Smarcel } 291240116Smarcel foff += m->m_pkthdr.len - 2*sizeof(uint32_t); 292240116Smarcel 293240116Smarcel /* 294240116Smarcel * Byte swap the encapsulation header manually. 295240116Smarcel */ 296240116Smarcel enc->ul[0] = htonl(enc->ul[0]); 297240116Smarcel enc->ul[1] = htonl(enc->ul[1]); 298240116Smarcel 299240116Smarcel if (!IF_HANDOFF(&ifp->if_snd, m, ifp)) { 300240116Smarcel if (mtail) 301240116Smarcel m_freem(mtail); 302240116Smarcel return (ENOBUFS); 303240116Smarcel } 304240116Smarcel 305240116Smarcel m = mtail; 306240116Smarcel } 307240116Smarcel 308240116Smarcel return (0); 309240116Smarcel } 310240116Smarcel 311240116Smarcelbad: 312240116Smarcel if (m) 313240116Smarcel m_freem(m); 314240116Smarcel return (error); 315240116Smarcel} 316240116Smarcel 317240116Smarcelstatic struct mbuf * 318240116Smarcelfirewire_input_fragment(struct fw_com *fc, struct mbuf *m, int src) 319240116Smarcel{ 320240116Smarcel union fw_encap *enc; 321240116Smarcel struct fw_reass *r; 322240116Smarcel struct mbuf *mf, *mprev; 323240116Smarcel int dsize; 324240116Smarcel int fstart, fend, start, end, islast; 325240116Smarcel uint32_t id; 326240116Smarcel 327240116Smarcel GIANT_REQUIRED; 328240116Smarcel 329240116Smarcel /* 330240116Smarcel * Find an existing reassembly buffer or create a new one. 331240116Smarcel */ 332240116Smarcel enc = mtod(m, union fw_encap *); 333240116Smarcel id = enc->firstfrag.dgl | (src << 16); 334240116Smarcel STAILQ_FOREACH(r, &fc->fc_frags, fr_link) 335240116Smarcel if (r->fr_id == id) 336240116Smarcel break; 337240116Smarcel if (!r) { 338240116Smarcel r = malloc(sizeof(struct fw_reass), M_TEMP, M_NOWAIT); 339240116Smarcel if (!r) { 340240116Smarcel m_freem(m); 341240116Smarcel return 0; 342240116Smarcel } 343240116Smarcel r->fr_id = id; 344240116Smarcel r->fr_frags = 0; 345240116Smarcel STAILQ_INSERT_HEAD(&fc->fc_frags, r, fr_link); 346240116Smarcel } 347240116Smarcel 348240116Smarcel /* 349240116Smarcel * If this fragment overlaps any other fragment, we must discard 350240116Smarcel * the partial reassembly and start again. 351240116Smarcel */ 352240116Smarcel if (enc->firstfrag.lf == FW_ENCAP_FIRST) 353240116Smarcel fstart = 0; 354240116Smarcel else 355240116Smarcel fstart = enc->nextfrag.fragment_offset; 356240116Smarcel fend = fstart + m->m_pkthdr.len - 2*sizeof(uint32_t); 357240116Smarcel dsize = enc->nextfrag.datagram_size; 358240116Smarcel islast = (enc->nextfrag.lf == FW_ENCAP_LAST); 359240116Smarcel 360240116Smarcel for (mf = r->fr_frags; mf; mf = mf->m_nextpkt) { 361240116Smarcel enc = mtod(mf, union fw_encap *); 362240116Smarcel if (enc->nextfrag.datagram_size != dsize) { 363240116Smarcel /* 364240116Smarcel * This fragment must be from a different 365240116Smarcel * packet. 366240116Smarcel */ 367240116Smarcel goto bad; 368240116Smarcel } 369240116Smarcel if (enc->firstfrag.lf == FW_ENCAP_FIRST) 370240116Smarcel start = 0; 371240116Smarcel else 372240116Smarcel start = enc->nextfrag.fragment_offset; 373240116Smarcel end = start + mf->m_pkthdr.len - 2*sizeof(uint32_t); 374240116Smarcel if ((fstart < end && fend > start) || 375240116Smarcel (islast && enc->nextfrag.lf == FW_ENCAP_LAST)) { 376240116Smarcel /* 377240116Smarcel * Overlap - discard reassembly buffer and start 378240116Smarcel * again with this fragment. 379240116Smarcel */ 380240116Smarcel goto bad; 381240116Smarcel } 382240116Smarcel } 383240116Smarcel 384240116Smarcel /* 385240116Smarcel * Find where to put this fragment in the list. 386240116Smarcel */ 387240116Smarcel for (mf = r->fr_frags, mprev = NULL; mf; 388240116Smarcel mprev = mf, mf = mf->m_nextpkt) { 389240116Smarcel enc = mtod(mf, union fw_encap *); 390240116Smarcel if (enc->firstfrag.lf == FW_ENCAP_FIRST) 391240116Smarcel start = 0; 392240116Smarcel else 393240116Smarcel start = enc->nextfrag.fragment_offset; 394240116Smarcel if (start >= fend) 395240116Smarcel break; 396240116Smarcel } 397240116Smarcel 398240116Smarcel /* 399240116Smarcel * If this is a last fragment and we are not adding at the end 400240116Smarcel * of the list, discard the buffer. 401240116Smarcel */ 402240116Smarcel if (islast && mprev && mprev->m_nextpkt) 403240116Smarcel goto bad; 404240116Smarcel 405240116Smarcel if (mprev) { 406240116Smarcel m->m_nextpkt = mprev->m_nextpkt; 407240116Smarcel mprev->m_nextpkt = m; 408240116Smarcel 409240116Smarcel /* 410240116Smarcel * Coalesce forwards and see if we can make a whole 411240116Smarcel * datagram. 412240116Smarcel */ 413240116Smarcel enc = mtod(mprev, union fw_encap *); 414240116Smarcel if (enc->firstfrag.lf == FW_ENCAP_FIRST) 415240116Smarcel start = 0; 416240116Smarcel else 417240116Smarcel start = enc->nextfrag.fragment_offset; 418240116Smarcel end = start + mprev->m_pkthdr.len - 2*sizeof(uint32_t); 419240116Smarcel while (end == fstart) { 420240116Smarcel /* 421240116Smarcel * Strip off the encap header from m and 422240116Smarcel * append it to mprev, freeing m. 423240116Smarcel */ 424240116Smarcel m_adj(m, 2*sizeof(uint32_t)); 425240116Smarcel mprev->m_nextpkt = m->m_nextpkt; 426240116Smarcel mprev->m_pkthdr.len += m->m_pkthdr.len; 427240116Smarcel m_cat(mprev, m); 428240116Smarcel 429240116Smarcel if (mprev->m_pkthdr.len == dsize + 1 + 2*sizeof(uint32_t)) { 430240116Smarcel /* 431240116Smarcel * We have assembled a complete packet 432240116Smarcel * we must be finished. Make sure we have 433240116Smarcel * merged the whole chain. 434240116Smarcel */ 435240116Smarcel STAILQ_REMOVE(&fc->fc_frags, r, fw_reass, fr_link); 436240116Smarcel free(r, M_TEMP); 437240116Smarcel m = mprev->m_nextpkt; 438240116Smarcel while (m) { 439240116Smarcel mf = m->m_nextpkt; 440240116Smarcel m_freem(m); 441240116Smarcel m = mf; 442240116Smarcel } 443240116Smarcel mprev->m_nextpkt = NULL; 444240116Smarcel 445240116Smarcel return (mprev); 446240116Smarcel } 447240116Smarcel 448240116Smarcel /* 449240116Smarcel * See if we can continue merging forwards. 450240116Smarcel */ 451240116Smarcel end = fend; 452240116Smarcel m = mprev->m_nextpkt; 453240116Smarcel if (m) { 454240116Smarcel enc = mtod(m, union fw_encap *); 455240116Smarcel if (enc->firstfrag.lf == FW_ENCAP_FIRST) 456240116Smarcel fstart = 0; 457240116Smarcel else 458240116Smarcel fstart = enc->nextfrag.fragment_offset; 459240116Smarcel fend = fstart + m->m_pkthdr.len 460240116Smarcel - 2*sizeof(uint32_t); 461240116Smarcel } else { 462240116Smarcel break; 463240116Smarcel } 464240116Smarcel } 465240116Smarcel } else { 466240116Smarcel m->m_nextpkt = 0; 467240116Smarcel r->fr_frags = m; 468240116Smarcel } 469240116Smarcel 470240116Smarcel return (0); 471240116Smarcel 472240116Smarcelbad: 473240116Smarcel while (r->fr_frags) { 474240116Smarcel mf = r->fr_frags; 475240116Smarcel r->fr_frags = mf->m_nextpkt; 476240116Smarcel m_freem(mf); 477240116Smarcel } 478240116Smarcel m->m_nextpkt = 0; 479240116Smarcel r->fr_frags = m; 480240116Smarcel 481240116Smarcel return (0); 482240116Smarcel} 483240116Smarcel 484240116Smarcelvoid 485240116Smarcelfirewire_input(struct ifnet *ifp, struct mbuf *m, uint16_t src) 486240116Smarcel{ 487240116Smarcel struct fw_com *fc = (struct fw_com *) ifp; 488240116Smarcel union fw_encap *enc; 489240116Smarcel int type, isr; 490240116Smarcel 491240116Smarcel GIANT_REQUIRED; 492240116Smarcel 493240116Smarcel /* 494240116Smarcel * The caller has already stripped off the packet header 495240116Smarcel * (stream or wreqb) and marked the mbuf's M_BCAST flag 496240116Smarcel * appropriately. We de-encapsulate the IP packet and pass it 497240116Smarcel * up the line after handling link-level fragmentation. 498240116Smarcel */ 499240116Smarcel if (m->m_pkthdr.len < sizeof(uint32_t)) { 500240116Smarcel if_printf(ifp, "discarding frame without " 501240116Smarcel "encapsulation header (len %u pkt len %u)\n", 502240116Smarcel m->m_len, m->m_pkthdr.len); 503240116Smarcel } 504240116Smarcel 505240116Smarcel m = m_pullup(m, sizeof(uint32_t)); 506240116Smarcel enc = mtod(m, union fw_encap *); 507240116Smarcel 508240116Smarcel /* 509240116Smarcel * Byte swap the encapsulation header manually. 510240116Smarcel */ 511240116Smarcel enc->ul[0] = htonl(enc->ul[0]); 512240116Smarcel 513240116Smarcel if (enc->unfrag.lf != 0) { 514240116Smarcel m = m_pullup(m, 2*sizeof(uint32_t)); 515240116Smarcel if (!m) 516240116Smarcel return; 517240116Smarcel enc = mtod(m, union fw_encap *); 518240116Smarcel enc->ul[1] = htonl(enc->ul[1]); 519240116Smarcel m = firewire_input_fragment(fc, m, src); 520240116Smarcel if (!m) 521240116Smarcel return; 522240116Smarcel enc = mtod(m, union fw_encap *); 523240116Smarcel type = enc->firstfrag.ether_type; 524240116Smarcel m_adj(m, 2*sizeof(uint32_t)); 525240116Smarcel } else { 526240116Smarcel type = enc->unfrag.ether_type; 527240116Smarcel m_adj(m, sizeof(uint32_t)); 528240116Smarcel } 529240116Smarcel 530240116Smarcel if (m->m_pkthdr.rcvif == NULL) { 531240116Smarcel if_printf(ifp, "discard frame w/o interface pointer\n"); 532240116Smarcel ifp->if_ierrors++; 533240116Smarcel m_freem(m); 534240116Smarcel return; 535240116Smarcel } 536240116Smarcel#ifdef DIAGNOSTIC 537240116Smarcel if (m->m_pkthdr.rcvif != ifp) { 538240116Smarcel if_printf(ifp, "Warning, frame marked as received on %s\n", 539240116Smarcel m->m_pkthdr.rcvif->if_xname); 540240116Smarcel } 541240116Smarcel#endif 542240116Smarcel 543240116Smarcel#ifdef MAC 544240116Smarcel /* 545240116Smarcel * Tag the mbuf with an appropriate MAC label before any other 546240116Smarcel * consumers can get to it. 547240116Smarcel */ 548240116Smarcel mac_create_mbuf_from_ifnet(ifp, m); 549240116Smarcel#endif 550240116Smarcel 551240116Smarcel /* 552240116Smarcel * Give bpf a chance at the packet. The link-level driver 553240116Smarcel * should have left us a tag with the EUID of the sender. 554240116Smarcel */ 555240116Smarcel if (ifp->if_bpf) { 556240116Smarcel struct fw_bpfhdr h; 557240116Smarcel struct m_tag *mtag; 558240116Smarcel 559240116Smarcel mtag = m_tag_locate(m, MTAG_FIREWIRE, MTAG_FIREWIRE_SENDER_EUID, 0); 560240116Smarcel if (mtag) 561240116Smarcel bcopy(mtag + 1, h.firewire_shost, 8); 562240116Smarcel else 563240116Smarcel bcopy(&firewire_broadcastaddr, h.firewire_dhost, 8); 564240116Smarcel bcopy(&fc->fc_hwaddr, h.firewire_dhost, 8); 565240116Smarcel h.firewire_type = htons(type); 566240116Smarcel bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m); 567240116Smarcel } 568240116Smarcel 569240116Smarcel if (ifp->if_flags & IFF_MONITOR) { 570240116Smarcel /* 571240116Smarcel * Interface marked for monitoring; discard packet. 572240116Smarcel */ 573240116Smarcel m_freem(m); 574240116Smarcel return; 575240116Smarcel } 576240116Smarcel 577240116Smarcel ifp->if_ibytes += m->m_pkthdr.len; 578240116Smarcel 579240116Smarcel /* Discard packet if interface is not up */ 580240116Smarcel if ((ifp->if_flags & IFF_UP) == 0) { 581240116Smarcel m_freem(m); 582240116Smarcel return; 583240116Smarcel } 584240116Smarcel 585240116Smarcel if (m->m_flags & (M_BCAST|M_MCAST)) 586240116Smarcel ifp->if_imcasts++; 587240116Smarcel 588240116Smarcel switch (type) { 589240116Smarcel#ifdef INET 590240116Smarcel case ETHERTYPE_IP: 591240116Smarcel if (ip_fastforward(m)) 592240116Smarcel return; 593240116Smarcel isr = NETISR_IP; 594240116Smarcel break; 595240116Smarcel 596240116Smarcel case ETHERTYPE_ARP: 597240116Smarcel { 598240116Smarcel struct arphdr *ah; 599240116Smarcel ah = mtod(m, struct arphdr *); 600240116Smarcel 601240116Smarcel /* 602240116Smarcel * Adjust the arp packet to insert an empty tha slot. 603240116Smarcel */ 604240116Smarcel m->m_len += ah->ar_hln; 605240116Smarcel m->m_pkthdr.len += ah->ar_hln; 606240116Smarcel bcopy(ar_tha(ah), ar_tpa(ah), ah->ar_pln); 607240116Smarcel isr = NETISR_ARP; 608240116Smarcel break; 609240116Smarcel } 610240116Smarcel#endif 611240116Smarcel 612240116Smarcel#ifdef INET6 613240116Smarcel case ETHERTYPE_IPV6: 614240116Smarcel isr = NETISR_IPV6; 615240116Smarcel break; 616240116Smarcel#endif 617240116Smarcel 618240116Smarcel default: 619240116Smarcel m_freem(m); 620240116Smarcel return; 621240116Smarcel } 622240116Smarcel 623240116Smarcel netisr_dispatch(isr, m); 624240116Smarcel} 625240116Smarcel 626240116Smarcelint 627240116Smarcelfirewire_ioctl(struct ifnet *ifp, int command, caddr_t data) 628240116Smarcel{ 629240116Smarcel struct ifaddr *ifa = (struct ifaddr *) data; 630240116Smarcel struct ifreq *ifr = (struct ifreq *) data; 631240116Smarcel int error = 0; 632240116Smarcel 633240116Smarcel switch (command) { 634240116Smarcel case SIOCSIFADDR: 635240116Smarcel ifp->if_flags |= IFF_UP; 636240116Smarcel 637240116Smarcel switch (ifa->ifa_addr->sa_family) { 638240116Smarcel#ifdef INET 639240116Smarcel case AF_INET: 640240116Smarcel ifp->if_init(ifp->if_softc); /* before arpwhohas */ 641240116Smarcel arp_ifinit(ifp, ifa); 642240116Smarcel break; 643240116Smarcel#endif 644240116Smarcel default: 645240116Smarcel ifp->if_init(ifp->if_softc); 646240116Smarcel break; 647240116Smarcel } 648240116Smarcel break; 649240116Smarcel 650240116Smarcel case SIOCGIFADDR: 651240116Smarcel { 652240116Smarcel struct sockaddr *sa; 653240116Smarcel 654240116Smarcel sa = (struct sockaddr *) & ifr->ifr_data; 655240116Smarcel bcopy(&IFP2FC(ifp)->fc_hwaddr, 656240116Smarcel (caddr_t) sa->sa_data, sizeof(struct fw_hwaddr)); 657240116Smarcel } 658240116Smarcel break; 659240116Smarcel 660240116Smarcel case SIOCSIFMTU: 661240116Smarcel /* 662240116Smarcel * Set the interface MTU. 663240116Smarcel */ 664240116Smarcel if (ifr->ifr_mtu > 1500) { 665240116Smarcel error = EINVAL; 666240116Smarcel } else { 667240116Smarcel ifp->if_mtu = ifr->ifr_mtu; 668240116Smarcel } 669240116Smarcel break; 670240116Smarcel default: 671240116Smarcel error = EINVAL; /* XXX netbsd has ENOTTY??? */ 672240116Smarcel break; 673240116Smarcel } 674240116Smarcel return (error); 675240116Smarcel} 676240116Smarcel 677240116Smarcelstatic int 678240116Smarcelfirewire_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, 679240116Smarcel struct sockaddr *sa) 680240116Smarcel{ 681240116Smarcel#ifdef INET 682240116Smarcel struct sockaddr_in *sin; 683240116Smarcel#endif 684240116Smarcel#ifdef INET6 685240116Smarcel struct sockaddr_in6 *sin6; 686240116Smarcel#endif 687240116Smarcel 688240116Smarcel switch(sa->sa_family) { 689240116Smarcel case AF_LINK: 690240116Smarcel /* 691240116Smarcel * No mapping needed. 692240116Smarcel */ 693240116Smarcel *llsa = 0; 694240116Smarcel return 0; 695240116Smarcel 696240116Smarcel#ifdef INET 697240116Smarcel case AF_INET: 698240116Smarcel sin = (struct sockaddr_in *)sa; 699240116Smarcel if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 700240116Smarcel return EADDRNOTAVAIL; 701240116Smarcel *llsa = 0; 702240116Smarcel return 0; 703240116Smarcel#endif 704240116Smarcel#ifdef INET6 705240116Smarcel case AF_INET6: 706240116Smarcel sin6 = (struct sockaddr_in6 *)sa; 707240116Smarcel if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 708240116Smarcel /* 709240116Smarcel * An IP6 address of 0 means listen to all 710240116Smarcel * of the Ethernet multicast address used for IP6. 711240116Smarcel * (This is used for multicast routers.) 712240116Smarcel */ 713240116Smarcel ifp->if_flags |= IFF_ALLMULTI; 714240116Smarcel *llsa = 0; 715240116Smarcel return 0; 716240116Smarcel } 717240116Smarcel if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 718240116Smarcel return EADDRNOTAVAIL; 719240116Smarcel *llsa = 0; 720240116Smarcel return 0; 721240116Smarcel#endif 722240116Smarcel 723240116Smarcel default: 724240116Smarcel /* 725240116Smarcel * Well, the text isn't quite right, but it's the name 726240116Smarcel * that counts... 727240116Smarcel */ 728240116Smarcel return EAFNOSUPPORT; 729240116Smarcel } 730240116Smarcel} 731240116Smarcel 732240116Smarcelvoid 733240116Smarcelfirewire_ifattach(struct ifnet *ifp, struct fw_hwaddr *llc) 734240116Smarcel{ 735240116Smarcel struct fw_com *fc = (struct fw_com *) ifp; 736240116Smarcel struct ifaddr *ifa; 737240116Smarcel struct sockaddr_dl *sdl; 738240116Smarcel static const char* speeds[] = { 739240116Smarcel "S100", "S200", "S400", "S800", 740240116Smarcel "S1600", "S3200" 741240116Smarcel }; 742240116Smarcel 743240116Smarcel fc->fc_speed = llc->sspd; 744240116Smarcel STAILQ_INIT(&fc->fc_frags); 745240116Smarcel 746240116Smarcel ifp->if_type = IFT_IEEE1394; 747240116Smarcel ifp->if_addrlen = sizeof(struct fw_hwaddr); 748240116Smarcel ifp->if_hdrlen = 0; 749240116Smarcel if_attach(ifp); 750240116Smarcel ifp->if_mtu = 1500; /* XXX */ 751240116Smarcel ifp->if_output = firewire_output; 752240116Smarcel ifp->if_resolvemulti = firewire_resolvemulti; 753240116Smarcel ifp->if_broadcastaddr = (u_char *) &firewire_broadcastaddr; 754240116Smarcel 755240116Smarcel ifa = ifaddr_byindex(ifp->if_index); 756240116Smarcel KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 757240116Smarcel sdl = (struct sockaddr_dl *)ifa->ifa_addr; 758240116Smarcel sdl->sdl_type = IFT_IEEE1394; 759240116Smarcel sdl->sdl_alen = ifp->if_addrlen; 760240116Smarcel bcopy(llc, LLADDR(sdl), ifp->if_addrlen); 761240116Smarcel 762240116Smarcel bpfattach(ifp, DLT_APPLE_IP_OVER_IEEE1394, 763240116Smarcel sizeof(struct fw_hwaddr)); 764240116Smarcel 765240116Smarcel if_printf(ifp, "Firewire address: %8D @ 0x%04x%08x, %s, maxrec %d\n", 766240116Smarcel (uint8_t *) &llc->sender_unique_ID_hi, ":", 767240116Smarcel ntohs(llc->sender_unicast_FIFO_hi), 768240116Smarcel ntohl(llc->sender_unicast_FIFO_lo), 769240116Smarcel speeds[llc->sspd], 770240116Smarcel (2 << llc->sender_max_rec)); 771240116Smarcel} 772240116Smarcel 773240116Smarcelvoid 774240116Smarcelfirewire_ifdetach(struct ifnet *ifp) 775240116Smarcel{ 776240116Smarcel bpfdetach(ifp); 777240116Smarcel if_detach(ifp); 778240116Smarcel} 779240116Smarcel 780240116Smarcelvoid 781240116Smarcelfirewire_busreset(struct ifnet *ifp) 782240116Smarcel{ 783240116Smarcel struct fw_com *fc = (struct fw_com *) ifp; 784240116Smarcel struct fw_reass *r; 785240116Smarcel struct mbuf *m; 786240116Smarcel 787240116Smarcel /* 788240116Smarcel * Discard any partial datagrams since the host ids may have changed. 789240116Smarcel */ 790240116Smarcel while ((r = STAILQ_FIRST(&fc->fc_frags))) { 791240116Smarcel STAILQ_REMOVE_HEAD(&fc->fc_frags, fr_link); 792240116Smarcel while (r->fr_frags) { 793240116Smarcel m = r->fr_frags; 794240116Smarcel r->fr_frags = m->m_nextpkt; 795240116Smarcel m_freem(m); 796240116Smarcel } 797240116Smarcel free(r, M_TEMP); 798240116Smarcel } 799240116Smarcel} 800240116Smarcel