if_arcsubr.c revision 109771
1139804Simp/* $NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $ */ 213675Sdyson/* $FreeBSD: head/sys/net/if_arcsubr.c 109771 2003-01-24 01:32:20Z fjoe $ */ 3232055Skmacy 413675Sdyson/* 513675Sdyson * Copyright (c) 1994, 1995 Ignatios Souvatzis 613675Sdyson * Copyright (c) 1982, 1989, 1993 713675Sdyson * The Regents of the University of California. All rights reserved. 813675Sdyson * 913675Sdyson * Redistribution and use in source and binary forms, with or without 1013675Sdyson * modification, are permitted provided that the following conditions 1113675Sdyson * are met: 1213675Sdyson * 1. Redistributions of source code must retain the above copyright 1313675Sdyson * notice, this list of conditions and the following disclaimer. 1413675Sdyson * 2. Redistributions in binary form must reproduce the above copyright 1513675Sdyson * notice, this list of conditions and the following disclaimer in the 1613675Sdyson * documentation and/or other materials provided with the distribution. 1714037Sdyson * 3. All advertising materials mentioning features or use of this software 1813675Sdyson * must display the following acknowledgement: 1913675Sdyson * This product includes software developed by the University of 2013675Sdyson * California, Berkeley and its contributors. 2113675Sdyson * 4. Neither the name of the University nor the names of its contributors 2213675Sdyson * may be used to endorse or promote products derived from this software 2313675Sdyson * without specific prior written permission. 2413675Sdyson * 2513675Sdyson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2613675Sdyson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2713675Sdyson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2813907Sdyson * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2913907Sdyson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3013907Sdyson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3113907Sdyson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3213907Sdyson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33219801Salc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34219801Salc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35219801Salc * SUCH DAMAGE. 3613907Sdyson * 3713907Sdyson * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp 3813913Sdyson * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93 3913907Sdyson * 4013907Sdyson */ 4113907Sdyson#include "opt_inet.h" 4213907Sdyson#include "opt_inet6.h" 4313907Sdyson#include "opt_ipx.h" 4413907Sdyson 4513907Sdyson#include <sys/param.h> 4613907Sdyson#include <sys/systm.h> 47118764Ssilby#include <sys/kernel.h> 48117325Ssilby#include <sys/malloc.h> 49118764Ssilby#include <sys/mbuf.h> 50117325Ssilby#include <sys/protosw.h> 51118764Ssilby#include <sys/socket.h> 52133790Ssilby#include <sys/sockio.h> 53133790Ssilby#include <sys/errno.h> 54117325Ssilby#include <sys/syslog.h> 55133790Ssilby 56133790Ssilby#include <machine/cpu.h> 57117325Ssilby 58133790Ssilby#include <net/if.h> 59133790Ssilby#include <net/netisr.h> 60117325Ssilby#include <net/route.h> 61133790Ssilby#include <net/if_dl.h> 62133790Ssilby#include <net/if_types.h> 63133790Ssilby#include <net/if_arc.h> 64133790Ssilby#include <net/if_arp.h> 65133790Ssilby#include <net/bpf.h> 66133790Ssilby 67133790Ssilby#if defined(INET) || defined(INET6) 68133790Ssilby#include <netinet/in.h> 69133790Ssilby#include <netinet/in_var.h> 70133049Ssilby#include <netinet/if_ether.h> 71133790Ssilby#endif 72133790Ssilby 73133790Ssilby#ifdef INET6 74133790Ssilby#include <netinet6/nd6.h> 75133790Ssilby#endif 76133790Ssilby 77133790Ssilby#ifdef IPX 78133790Ssilby#include <netipx/ipx.h> 79133790Ssilby#include <netipx/ipx_if.h> 80133049Ssilby#endif 81133049Ssilby 82133049SsilbyMODULE_VERSION(arcnet, 1); 83133049Ssilby 84133790Ssilby#define ARCNET_ALLOW_BROKEN_ARP 85133790Ssilby 86133049Ssilbystatic struct mbuf *arc_defrag(struct ifnet *, struct mbuf *); 87133049Ssilbystatic int arc_resolvemulti(struct ifnet *, struct sockaddr **, 88133049Ssilby struct sockaddr *); 89133049Ssilby 9013907Sdysonu_int8_t arcbroadcastaddr = 0; 9113907Sdyson 92116182Sobrien#define senderr(e) { error = (e); goto bad;} 93116182Sobrien#define SIN(s) ((struct sockaddr_in *)s) 94116182Sobrien#define SIPX(s) ((struct sockaddr_ipx *)s) 9513675Sdyson 9613675Sdyson/* 97226042Skib * ARCnet output routine. 9824131Sbde * Encapsulate a packet of type family for the local net. 9913675Sdyson * Assumes that ifp is actually pointer to arccom structure. 10013675Sdyson */ 10124206Sbdeint 10291372Salfredarc_output(ifp, m, dst, rt0) 10376166Smarkm struct ifnet *ifp; 10476827Salfred struct mbuf *m; 10524206Sbde struct sockaddr *dst; 10613675Sdyson struct rtentry *rt0; 10791968Salfred{ 10829356Speter struct rtentry *rt; 10970834Swollman struct arccom *ac; 11013675Sdyson struct arc_header *ah; 111184849Sed int error; 112117325Ssilby u_int8_t atype, adst; 11313675Sdyson int loop_copy = 0; 11413675Sdyson 11576166Smarkm if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 11655112Sbde return(ENETDOWN); /* m, m1 aren't initialized yet */ 11734924Sbde 11859288Sjlemon error = 0; 11913675Sdyson ac = (struct arccom *)ifp; 120163606Srwatson 121163606Srwatson if ((rt = rt0)) { 12213675Sdyson if ((rt->rt_flags & RTF_UP) == 0) { 12313675Sdyson if ((rt0 = rt = rtalloc1(dst, 1, 0UL))) 12413675Sdyson rt->rt_refcnt--; 12513675Sdyson else 12613675Sdyson senderr(EHOSTUNREACH); 12713675Sdyson } 12813675Sdyson if (rt->rt_flags & RTF_GATEWAY) { 12913907Sdyson if (rt->rt_gwroute == 0) 13092751Sjeff goto lookup; 13113675Sdyson if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 132232055Skmacy rtfree(rt); rt = rt0; 133232055Skmacy lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL); 13414037Sdyson if ((rt = rt->rt_gwroute) == 0) 13514037Sdyson senderr(EHOSTUNREACH); 13614037Sdyson } 13714037Sdyson } 13814037Sdyson if (rt->rt_flags & RTF_REJECT) 13914037Sdyson if (rt->rt_rmx.rmx_expire == 0 || 14014037Sdyson time_second < rt->rt_rmx.rmx_expire) 141232055Skmacy senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 142232055Skmacy } 143232055Skmacy 14414037Sdyson switch (dst->sa_family) { 14514037Sdyson#ifdef INET 14614037Sdyson case AF_INET: 147108255Sphk 148108255Sphk /* 149175140Sjhb * For now, use the simple IP addr -> ARCnet addr mapping 150108255Sphk */ 151108255Sphk if (m->m_flags & (M_BCAST|M_MCAST)) 152108255Sphk adst = arcbroadcastaddr; /* ARCnet broadcast address */ 153108255Sphk else if (ifp->if_flags & IFF_NOARP) 154108255Sphk adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF; 155232183Sjilles else if (!arpresolve(ifp, rt, m, dst, &adst, rt0)) 156232183Sjilles return 0; /* not resolved yet */ 15713675Sdyson 158232055Skmacy atype = (ifp->if_flags & IFF_LINK0) ? 159116546Sphk ARCTYPE_IP_OLD : ARCTYPE_IP; 160116546Sphk break; 161175140Sjhb#endif 162116546Sphk#ifdef INET6 163116546Sphk case AF_INET6: 164116546Sphk#ifdef OLDIP6OUTPUT 165116546Sphk if (!nd6_resolve(ifp, rt, m, dst, (u_char *)&adst)) 166116546Sphk return(0); /* if not yet resolves */ 167232183Sjilles#else 168232183Sjilles if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)&adst)) 169116546Sphk return(0); /* it must be impossible, but... */ 17072521Sjlemon#endif /* OLDIP6OUTPUT */ 17113675Sdyson atype = ARCTYPE_INET6; 17259288Sjlemon break; 173232055Skmacy#endif 174232055Skmacy#ifdef IPX 17559288Sjlemon case AF_IPX: 17659288Sjlemon adst = SIPX(dst)->sipx_addr.x_host.c_host[5]; 17759288Sjlemon atype = ARCTYPE_IPX; 178232055Skmacy if (adst == 0xff) 179232055Skmacy adst = arcbroadcastaddr; 180232055Skmacy break; 181232055Skmacy#endif 182232055Skmacy 183197134Srwatson case AF_UNSPEC: 184197134Srwatson loop_copy = -1; 185197134Srwatson ah = (struct arc_header *)dst->sa_data; 186197134Srwatson adst = ah->arc_dhost; 187197134Srwatson atype = ah->arc_type; 188197134Srwatson 189197134Srwatson if (atype == ARCTYPE_ARP) { 190197134Srwatson atype = (ifp->if_flags & IFF_LINK0) ? 191197134Srwatson ARCTYPE_ARP_OLD: ARCTYPE_ARP; 192197134Srwatson 19359288Sjlemon#ifdef ARCNET_ALLOW_BROKEN_ARP 19413675Sdyson /* 19513675Sdyson * XXX It's not clear per RFC826 if this is needed, but 19613675Sdyson * "assigned numbers" say this is wrong. 19713675Sdyson * However, e.g., AmiTCP 3.0Beta used it... we make this 19813675Sdyson * switchable for emergency cases. Not perfect, but... 19913675Sdyson */ 20013907Sdyson if (ifp->if_flags & IFF_LINK2) 20113907Sdyson mtod(m, struct arphdr *)->ar_pro = atype - 1; 20213675Sdyson#endif 203189649Sjhb } 204133790Ssilby break; 205133790Ssilby 206133790Ssilby default: 207133790Ssilby if_printf(ifp, "can't handle af%d\n", dst->sa_family); 20813907Sdyson senderr(EAFNOSUPPORT); 209189649Sjhb } 210117325Ssilby 211189649Sjhb M_PREPEND(m, ARC_HDRLEN, M_NOWAIT); 212117325Ssilby if (m == 0) 213133790Ssilby senderr(ENOBUFS); 214133790Ssilby ah = mtod(m, struct arc_header *); 215133790Ssilby ah->arc_type = atype; 216133790Ssilby ah->arc_dhost = adst; 217133790Ssilby ah->arc_shost = *IF_LLADDR(ifp); 218133790Ssilby 219133790Ssilby if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 220133790Ssilby if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 221117325Ssilby struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 22291413Salfred 22391413Salfred (void) if_simloop(ifp, n, dst->sa_family, ARC_HDRLEN); 22491413Salfred } else if (ah->arc_dhost == ah->arc_shost) { 225133790Ssilby (void) if_simloop(ifp, m, dst->sa_family, ARC_HDRLEN); 226232055Skmacy return (0); /* XXX */ 22791413Salfred } 22891413Salfred } 22991413Salfred 23014037Sdyson BPF_MTAP(ifp, m); 23191413Salfred 23291413Salfred if (!IF_HANDOFF(&ifp->if_snd, m, ifp)) { 23391413Salfred m = 0; 23491413Salfred senderr(ENOBUFS); 23514037Sdyson } 23691413Salfred 237132579Srwatson return (error); 23813675Sdyson 239132987Sgreenbad: 240132987Sgreen if (m) 241125293Srwatson m_freem(m); 242125293Srwatson return (error); 24392751Sjeff} 244226042Skib 245226042Skibvoid 24627899Sdysonarc_frag_init(ifp) 24791372Salfred struct ifnet *ifp; 24891372Salfred{ 24991372Salfred struct arccom *ac; 25091372Salfred 25191372Salfred ac = (struct arccom *)ifp; 252118880Salc ac->curr_frag = 0; 253170022Srwatson} 254170022Srwatson 255125293Srwatsonstruct mbuf * 256118880Salcarc_frag_next(ifp) 257226042Skib struct ifnet *ifp; 258226042Skib{ 259226042Skib struct arccom *ac; 260226042Skib struct mbuf *m; 26191372Salfred struct arc_header *ah; 26291372Salfred 263132987Sgreen ac = (struct arccom *)ifp; 264132987Sgreen if ((m = ac->curr_frag) == 0) { 265125293Srwatson int tfrags; 266125293Srwatson 267125293Srwatson /* dequeue new packet */ 268125293Srwatson IF_DEQUEUE(&ifp->if_snd, m); 269125293Srwatson if (m == 0) 270125293Srwatson return 0; 271125293Srwatson 272125293Srwatson ah = mtod(m, struct arc_header *); 273125293Srwatson if (!arc_isphds(ah->arc_type)) 274125293Srwatson return m; 275125293Srwatson 276125293Srwatson ++ac->ac_seqid; /* make the seqid unique */ 277125293Srwatson tfrags = (m->m_pkthdr.len + ARC_MAX_DATA - 1) / ARC_MAX_DATA; 278125293Srwatson ac->fsflag = 2 * tfrags - 3; 279125293Srwatson ac->sflag = 0; 280125293Srwatson ac->rsflag = ac->fsflag; 281125293Srwatson ac->arc_dhost = ah->arc_dhost; 282125293Srwatson ac->arc_shost = ah->arc_shost; 283125293Srwatson ac->arc_type = ah->arc_type; 284125293Srwatson 285125293Srwatson m_adj(m, ARC_HDRLEN); 286125293Srwatson ac->curr_frag = m; 287125293Srwatson } 288125293Srwatson 289125293Srwatson /* split out next fragment and return it */ 290125293Srwatson if (ac->sflag < ac->fsflag) { 291125293Srwatson /* we CAN'T have short packets here */ 292125293Srwatson ac->curr_frag = m_split(m, ARC_MAX_DATA, M_NOWAIT); 293125293Srwatson if (ac->curr_frag == 0) { 294125293Srwatson m_freem(m); 295125293Srwatson return 0; 296125293Srwatson } 297125293Srwatson 298179243Skib M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT); 299179243Skib if (m == 0) { 300125293Srwatson m_freem(ac->curr_frag); 301125293Srwatson ac->curr_frag = 0; 302125293Srwatson return 0; 303125293Srwatson } 304125293Srwatson 305125293Srwatson ah = mtod(m, struct arc_header *); 306125293Srwatson ah->arc_flag = ac->rsflag; 307125293Srwatson ah->arc_seqid = ac->ac_seqid; 308132987Sgreen 309125293Srwatson ac->sflag += 2; 310125293Srwatson ac->rsflag = ac->sflag; 311132987Sgreen } else if ((m->m_pkthdr.len >= 312132987Sgreen ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) && 313125293Srwatson (m->m_pkthdr.len <= 314125293Srwatson ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) { 315125293Srwatson ac->curr_frag = 0; 316125293Srwatson 317125293Srwatson M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_NOWAIT); 318125293Srwatson if (m == 0) 319125293Srwatson return 0; 320125293Srwatson 321132987Sgreen ah = mtod(m, struct arc_header *); 322125293Srwatson ah->arc_flag = 0xFF; 323125293Srwatson ah->arc_seqid = 0xFFFF; 324125293Srwatson ah->arc_type2 = ac->arc_type; 325125293Srwatson ah->arc_flag2 = ac->sflag; 326125293Srwatson ah->arc_seqid2 = ac->ac_seqid; 327125293Srwatson } else { 328125293Srwatson ac->curr_frag = 0; 329125293Srwatson 330125293Srwatson M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT); 331125293Srwatson if (m == 0) 332125293Srwatson return 0; 333125293Srwatson 334125293Srwatson ah = mtod(m, struct arc_header *); 335125293Srwatson ah->arc_flag = ac->sflag; 336232055Skmacy ah->arc_seqid = ac->ac_seqid; 337232055Skmacy } 33813675Sdyson 339125293Srwatson ah->arc_dhost = ac->arc_dhost; 34013675Sdyson ah->arc_shost = ac->arc_shost; 341232055Skmacy ah->arc_type = ac->arc_type; 34227899Sdyson 343232055Skmacy return m; 344125293Srwatson} 345125293Srwatson 346126249Srwatson/* 347172930Srwatson * Defragmenter. Returns mbuf if last packet found, else 348126249Srwatson * NULL. frees imcoming mbuf as necessary. 349125293Srwatson */ 350172930Srwatson 351172930Srwatsonstatic __inline struct mbuf * 352125293Srwatsonarc_defrag(ifp, m) 353125293Srwatson struct ifnet *ifp; 354125293Srwatson struct mbuf *m; 355125293Srwatson{ 356193951Skib struct arc_header *ah, *ah1; 357193951Skib struct arccom *ac; 358140369Ssilby struct ac_frag *af; 359133790Ssilby struct mbuf *m1; 360155035Sglebius char *s; 361155035Sglebius int newflen; 362124394Sdes u_char src,dst,typ; 363124394Sdes 364155035Sglebius ac = (struct arccom *)ifp; 36576364Salfred 366124394Sdes if (m->m_len < ARC_HDRNEWLEN) { 36713907Sdyson m = m_pullup(m, ARC_HDRNEWLEN); 36813907Sdyson if (m == NULL) { 369232055Skmacy ++ifp->if_ierrors; 370232055Skmacy return NULL; 37113675Sdyson } 372232055Skmacy } 373232055Skmacy 374232055Skmacy ah = mtod(m, struct arc_header *); 375232055Skmacy typ = ah->arc_type; 376232055Skmacy 377232055Skmacy if (!arc_isphds(typ)) 378232055Skmacy return m; 379232055Skmacy 380232055Skmacy src = ah->arc_shost; 381232055Skmacy dst = ah->arc_dhost; 382232055Skmacy 383232055Skmacy if (ah->arc_flag == 0xff) { 384232055Skmacy m_adj(m, 4); 385232055Skmacy 386232055Skmacy if (m->m_len < ARC_HDRNEWLEN) { 387232055Skmacy m = m_pullup(m, ARC_HDRNEWLEN); 388232055Skmacy if (m == NULL) { 389232055Skmacy ++ifp->if_ierrors; 390232055Skmacy return NULL; 391232055Skmacy } 392232055Skmacy } 393232055Skmacy 394232055Skmacy ah = mtod(m, struct arc_header *); 395232055Skmacy } 396232055Skmacy 397232055Skmacy af = &ac->ac_fragtab[src]; 398232055Skmacy m1 = af->af_packet; 399232055Skmacy s = "debug code error"; 400232055Skmacy 401232055Skmacy if (ah->arc_flag & 1) { 402232055Skmacy /* 403232055Skmacy * first fragment. We always initialize, which is 404232055Skmacy * about the right thing to do, as we only want to 405232055Skmacy * accept one fragmented packet per src at a time. 406232055Skmacy */ 407232055Skmacy if (m1 != NULL) 408232055Skmacy m_freem(m1); 409232055Skmacy 410232055Skmacy af->af_packet = m; 411232055Skmacy m1 = m; 412232055Skmacy af->af_maxflag = ah->arc_flag; 413232055Skmacy af->af_lastseen = 0; 414232055Skmacy af->af_seqid = ah->arc_seqid; 415232055Skmacy 416232055Skmacy return NULL; 417232055Skmacy /* notreached */ 418232055Skmacy } else { 419232055Skmacy /* check for unfragmented packet */ 420232055Skmacy if (ah->arc_flag == 0) 421232055Skmacy return m; 422220245Skib 42370915Sdwmalone /* do we have a first packet from that src? */ 42470915Sdwmalone if (m1 == NULL) { 42570915Sdwmalone s = "no first frag"; 42670915Sdwmalone goto outofseq; 42770915Sdwmalone } 428121256Sdwmalone 429184849Sed ah1 = mtod(m1, struct arc_header *); 43070915Sdwmalone 43170803Sdwmalone if (ah->arc_seqid != ah1->arc_seqid) { 43270803Sdwmalone s = "seqid differs"; 43370803Sdwmalone goto outofseq; 43470803Sdwmalone } 43570803Sdwmalone 43670803Sdwmalone if (typ != ah1->arc_type) { 437174988Sjeff s = "type differs"; 438220245Skib goto outofseq; 43970915Sdwmalone } 440184849Sed 44183366Sjulian if (dst != ah1->arc_dhost) { 44270915Sdwmalone s = "dest host differs"; 44370915Sdwmalone goto outofseq; 44470915Sdwmalone } 44570915Sdwmalone 446121256Sdwmalone /* typ, seqid and dst are ok here. */ 447174988Sjeff 448121256Sdwmalone if (ah->arc_flag == af->af_lastseen) { 449184849Sed m_freem(m); 45083366Sjulian return NULL; 45113675Sdyson } 45213675Sdyson 45313675Sdyson if (ah->arc_flag == af->af_lastseen + 2) { 45413675Sdyson /* ok, this is next fragment */ 455184849Sed af->af_lastseen = ah->arc_flag; 456184849Sed m_adj(m,ARC_HDRNEWLEN); 457225617Skmacy 458184849Sed /* 459184849Sed * m_cat might free the first mbuf (with pkthdr) 460184849Sed * in 2nd chain; therefore: 461184849Sed */ 462184849Sed 463184849Sed newflen = m->m_pkthdr.len; 464184849Sed 465184849Sed m_cat(m1,m); 466184849Sed 467184849Sed m1->m_pkthdr.len += newflen; 468184849Sed 469184849Sed /* is it the last one? */ 470184849Sed if (af->af_lastseen > af->af_maxflag) { 471184849Sed af->af_packet = NULL; 47213909Sdyson return(m1); 47313909Sdyson } else 47476364Salfred return NULL; 47576364Salfred } 47676364Salfred s = "other reason"; 47713909Sdyson /* if all else fails, it is out of sequence, too */ 47876364Salfred } 479132579Srwatsonoutofseq: 48013675Sdyson if (m1) { 48176364Salfred m_freem(m1); 48213675Sdyson af->af_packet = NULL; 48376364Salfred } 484133790Ssilby 485117325Ssilby if (m) 486117325Ssilby m_freem(m); 48713675Sdyson 488125293Srwatson log(LOG_INFO,"%s%d: got out of seq. packet: %s\n", 489133790Ssilby ifp->if_name, ifp->if_unit, s); 490133790Ssilby 491133790Ssilby return NULL; 492133790Ssilby} 493133790Ssilby 494133790Ssilby/* 49579224Sdillon * return 1 if Packet Header Definition Standard, else 0. 496118764Ssilby * For now: old IP, old ARP aren't obviously. Lacking correct information, 497118764Ssilby * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS. 49813675Sdyson * (Apple and Novell corporations were involved, among others, in PHDS work). 499122163Salc * Easiest is to assume that everybody else uses that, too. 50076364Salfred */ 50113688Sdysonint 50276364Salfredarc_isphds(type) 503133790Ssilby u_int8_t type; 504133790Ssilby{ 505133790Ssilby return (type != ARCTYPE_IP_OLD && 506133790Ssilby type != ARCTYPE_ARP_OLD && 507133790Ssilby type != ARCTYPE_DIAGNOSE); 508133790Ssilby} 509133790Ssilby 510133790Ssilby/* 511133790Ssilby * Process a received Arcnet packet; 512133790Ssilby * the packet is in the mbuf chain m with 513133790Ssilby * the ARCnet header. 514133790Ssilby */ 515133790Ssilbyvoid 51676364Salfredarc_input(ifp, m) 51776364Salfred struct ifnet *ifp; 51876364Salfred struct mbuf *m; 519133790Ssilby{ 520133790Ssilby struct arc_header *ah; 521133790Ssilby struct ifqueue *inq; 522133790Ssilby u_int8_t atype; 523133790Ssilby 524133790Ssilby if ((ifp->if_flags & IFF_UP) == 0) { 525133790Ssilby m_freem(m); 526133790Ssilby return; 527133790Ssilby } 528133790Ssilby 529133790Ssilby /* possibly defragment: */ 530133790Ssilby m = arc_defrag(ifp, m); 531133790Ssilby if (m == NULL) 532133790Ssilby return; 53376364Salfred 53476364Salfred BPF_MTAP(ifp, m); 53576364Salfred 536133790Ssilby ah = mtod(m, struct arc_header *); 53776364Salfred /* does this belong to us? */ 538133790Ssilby if ((ifp->if_flags & IFF_PROMISC) != 0 539189649Sjhb && ah->arc_dhost != arcbroadcastaddr 54076364Salfred && ah->arc_dhost != *IF_LLADDR(ifp)) { 54113907Sdyson m_freem(m); 54213688Sdyson return; 54313907Sdyson } 544132579Srwatson 545132579Srwatson ifp->if_ibytes += m->m_pkthdr.len; 546132579Srwatson 547132579Srwatson if (ah->arc_dhost == arcbroadcastaddr) { 548132579Srwatson m->m_flags |= M_BCAST|M_MCAST; 549132579Srwatson ifp->if_imcasts++; 550132579Srwatson } 551132579Srwatson 552133049Ssilby atype = ah->arc_type; 553133049Ssilby switch (atype) { 554132579Srwatson#ifdef INET 555132579Srwatson case ARCTYPE_IP: 556132579Srwatson m_adj(m, ARC_HDRNEWLEN); 557132579Srwatson if (ipflow_fastforward(m)) 55813675Sdyson return; 55913675Sdyson schednetisr(NETISR_IP); 56013675Sdyson inq = &ipintrq; 56113907Sdyson break; 56213675Sdyson 56313907Sdyson case ARCTYPE_IP_OLD: 56413675Sdyson m_adj(m, ARC_HDRLEN); 56513776Sdyson if (ipflow_fastforward(m)) 56676364Salfred return; 56791362Salfred schednetisr(NETISR_IP); 56891362Salfred inq = &ipintrq; 56913675Sdyson break; 57091362Salfred 57191362Salfred case ARCTYPE_ARP: 57276760Salfred if (ifp->if_flags & IFF_NOARP) { 573124394Sdes /* Discard packet if ARP is disabled on interface */ 57476760Salfred m_freem(m); 57513675Sdyson return; 57691362Salfred } 57776760Salfred m_adj(m, ARC_HDRNEWLEN); 57813675Sdyson schednetisr(NETISR_ARP); 57913675Sdyson inq = &arpintrq; 58013675Sdyson#ifdef ARCNET_ALLOW_BROKEN_ARP 58113675Sdyson mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP); 58213675Sdyson#endif 58313675Sdyson break; 58413675Sdyson 58513675Sdyson case ARCTYPE_ARP_OLD: 58613675Sdyson if (ifp->if_flags & IFF_NOARP) { 58776364Salfred /* Discard packet if ARP is disabled on interface */ 58891362Salfred m_freem(m); 589133049Ssilby return; 590133049Ssilby } 59191362Salfred m_adj(m, ARC_HDRLEN); 59213675Sdyson schednetisr(NETISR_ARP); 59313675Sdyson inq = &arpintrq; 59414177Sdyson#ifdef ARCNET_ALLOW_BROKEN_ARP 59513675Sdyson mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP); 59613675Sdyson#endif 59713675Sdyson break; 59814037Sdyson#endif 59914037Sdyson#ifdef INET6 60014037Sdyson case ARCTYPE_INET6: 60114037Sdyson m_adj(m, ARC_HDRNEWLEN); 60276364Salfred schednetisr(NETISR_IPV6); 603126252Srwatson inq = &ip6intrq; 60414037Sdyson break; 605122352Stanimura#endif 606174647Sjeff#ifdef IPX 607174647Sjeff case ARCTYPE_IPX: 60814037Sdyson m_adj(m, ARC_HDRNEWLEN); 60941086Struckman schednetisr(NETISR_IPX); 61095883Salfred inq = &ipxintrq; 611133741Sjmg break; 61214037Sdyson#endif 61314037Sdyson default: 614126131Sgreen m_freem(m); 615126131Sgreen return; 616126131Sgreen } 617126131Sgreen 618126131Sgreen IF_HANDOFF(inq, m, NULL); 619133790Ssilby} 620126131Sgreen 621133790Ssilby/* 622126131Sgreen * Register (new) link level address. 623126131Sgreen */ 624126131Sgreenvoid 625133790Ssilbyarc_storelladdr(ifp, lla) 626133790Ssilby struct ifnet *ifp; 627133790Ssilby u_int8_t lla; 628133790Ssilby{ 629133790Ssilby *IF_LLADDR(ifp) = lla; 630133790Ssilby} 631133790Ssilby 632133790Ssilby/* 633133790Ssilby * Perform common duties while attaching to interface list 634228306Skib */ 635132579Srwatsonvoid 636126131Sgreenarc_ifattach(ifp, lla) 637126131Sgreen struct ifnet *ifp; 63813675Sdyson u_int8_t lla; 63913675Sdyson{ 640101941Srwatson struct ifaddr *ifa; 64113675Sdyson struct sockaddr_dl *sdl; 64213675Sdyson struct arccom *ac; 643101941Srwatson 64483366Sjulian if_attach(ifp); 64545311Sdt ifp->if_type = IFT_ARCNET; 64613675Sdyson ifp->if_addrlen = 1; 647232055Skmacy ifp->if_hdrlen = ARC_HDRLEN; 64847748Salc ifp->if_mtu = 1500; 64913675Sdyson ifp->if_resolvemulti = arc_resolvemulti; 65018863Sdyson if (ifp->if_baudrate == 0) 65113675Sdyson ifp->if_baudrate = 2500000; 652232055Skmacy#if __FreeBSD_version < 500000 65391362Salfred ifa = ifnet_addrs[ifp->if_index - 1]; 65413675Sdyson#else 65547748Salc ifa = ifaddr_byindex(ifp->if_index); 65647748Salc#endif 65747748Salc KASSERT(ifa != NULL, ("%s: no lladdr!\n", __FUNCTION__)); 65847748Salc sdl = (struct sockaddr_dl *)ifa->ifa_addr; 659101768Srwatson sdl->sdl_type = IFT_ARCNET; 660172930Srwatson sdl->sdl_alen = ifp->if_addrlen; 661101768Srwatson 662101768Srwatson if (ifp->if_flags & IFF_BROADCAST) 663101768Srwatson ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI; 664133790Ssilby 665133790Ssilby ac = (struct arccom *)ifp; 666133790Ssilby ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */ 667133790Ssilby if (lla == 0) { 668133790Ssilby /* XXX this message isn't entirely clear, to me -- cgd */ 669133790Ssilby log(LOG_ERR,"%s%d: link address 0 reserved for broadcasts. Please change it and ifconfig %s%d down up\n", 670133790Ssilby ifp->if_name, ifp->if_unit, ifp->if_name, ifp->if_unit); 671133790Ssilby } 672133790Ssilby arc_storelladdr(ifp, lla); 673133790Ssilby 674101768Srwatson ifp->if_broadcastaddr = &arcbroadcastaddr; 67513675Sdyson 67613907Sdyson bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN); 67713907Sdyson} 67813907Sdyson 67913675Sdysonvoid 68018863Sdysonarc_ifdetach(ifp) 68113675Sdyson struct ifnet *ifp; 68213675Sdyson{ 683231949Skib bpfdetach(ifp); 68418863Sdyson if_detach(ifp); 68547748Salc} 68691362Salfred 687116127Smuxint 688116127Smuxarc_ioctl(ifp, command, data) 689116127Smux struct ifnet *ifp; 69091362Salfred int command; 69176760Salfred caddr_t data; 69213675Sdyson{ 69376760Salfred struct ifaddr *ifa = (struct ifaddr *) data; 69413675Sdyson struct ifreq *ifr = (struct ifreq *) data; 69513675Sdyson int error = 0; 69613675Sdyson 69713675Sdyson switch (command) { 69813675Sdyson case SIOCSIFADDR: 69947748Salc ifp->if_flags |= IFF_UP; 70047748Salc switch (ifa->ifa_addr->sa_family) { 70147748Salc#ifdef INET 70247748Salc case AF_INET: 70347748Salc ifp->if_init(ifp->if_softc); /* before arpwhohas */ 70447748Salc arp_ifinit(ifp, ifa); 70547748Salc break; 70647748Salc#endif 70747748Salc#ifdef IPX 70847748Salc /* 70913675Sdyson * XXX This code is probably wrong 71014037Sdyson */ 71113907Sdyson case AF_IPX: 71213907Sdyson { 71313907Sdyson struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 71413907Sdyson 71547748Salc if (ipx_nullhost(*ina)) 716231949Skib ina->x_host.c_host[5] = *IF_LLADDR(ifp); 71718863Sdyson else 71847748Salc arc_storelladdr(ifp, ina->x_host.c_host[5]); 71991362Salfred 720127501Salc /* 721127501Salc * Set new address 72291362Salfred */ 72313907Sdyson ifp->if_init(ifp->if_softc); 72413907Sdyson break; 72513907Sdyson } 72613907Sdyson#endif 72713907Sdyson default: 72813907Sdyson ifp->if_init(ifp->if_softc); 72913907Sdyson break; 73013907Sdyson } 73113907Sdyson break; 73214037Sdyson 73313675Sdyson case SIOCGIFADDR: 73413675Sdyson { 73513675Sdyson struct sockaddr *sa; 73676760Salfred 73713675Sdyson sa = (struct sockaddr *) &ifr->ifr_data; 73876760Salfred bcopy(IF_LLADDR(ifp), 73913675Sdyson (caddr_t) sa->sa_data, ARC_ADDR_LEN); 74043623Sdillon } 74113675Sdyson break; 74213675Sdyson 74313675Sdyson case SIOCADDMULTI: 74413675Sdyson case SIOCDELMULTI: 74513675Sdyson if (ifr == NULL) 74613675Sdyson error = EAFNOSUPPORT; 74713675Sdyson else { 74843623Sdillon switch (ifr->ifr_addr.sa_family) { 74943623Sdillon case AF_INET: 75047748Salc case AF_INET6: 75143623Sdillon error = 0; 75247748Salc break; 75313675Sdyson default: 75416960Sdyson error = EAFNOSUPPORT; 75543623Sdillon break; 756124394Sdes } 757116127Smux } 758116127Smux break; 75943623Sdillon 76047748Salc case SIOCSIFMTU: 76143623Sdillon /* 76213675Sdyson * Set the interface MTU. 76347748Salc * mtu can't be larger than ARCMTU for RFC1051 76447748Salc * and can't be larger than ARC_PHDS_MTU 76513675Sdyson */ 76676760Salfred if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) || 76747748Salc ifr->ifr_mtu > ARC_PHDS_MAXMTU) 76876760Salfred error = EINVAL; 76947748Salc else 77091362Salfred ifp->if_mtu = ifr->ifr_mtu; 77191362Salfred break; 77277140Salfred } 77347748Salc 77413675Sdyson return (error); 77547748Salc} 77647748Salc 77713675Sdyson/* based on ether_resolvemulti() */ 77813675Sdysonint 779101768Srwatsonarc_resolvemulti(ifp, llsa, sa) 780101768Srwatson struct ifnet *ifp; 781101768Srwatson struct sockaddr **llsa; 78247748Salc struct sockaddr *sa; 78313675Sdyson{ 78491362Salfred struct sockaddr_dl *sdl; 78524101Sbde struct sockaddr_in *sin; 78655112Sbde#ifdef INET6 78747748Salc struct sockaddr_in6 *sin6; 78847748Salc#endif 78913913Sdyson 79047748Salc switch(sa->sa_family) { 79147748Salc case AF_LINK: 79247748Salc /* 79313675Sdyson * No mapping needed. Just check that it's a valid MC address. 79413675Sdyson */ 79513675Sdyson sdl = (struct sockaddr_dl *)sa; 79613675Sdyson if (*LLADDR(sdl) != arcbroadcastaddr) 79713675Sdyson return EADDRNOTAVAIL; 79847748Salc *llsa = 0; 79913675Sdyson return 0; 80013675Sdyson#ifdef INET 80113675Sdyson case AF_INET: 80213675Sdyson sin = (struct sockaddr_in *)sa; 80313675Sdyson if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 80413675Sdyson return EADDRNOTAVAIL; 80514037Sdyson MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 80614802Sdyson M_ZERO); 80714037Sdyson sdl->sdl_len = sizeof *sdl; 80814037Sdyson sdl->sdl_family = AF_LINK; 80991362Salfred sdl->sdl_index = ifp->if_index; 81076760Salfred sdl->sdl_type = IFT_ARCNET; 81113675Sdyson sdl->sdl_alen = ARC_ADDR_LEN; 81213675Sdyson *LLADDR(sdl) = 0; 81314037Sdyson *llsa = (struct sockaddr *)sdl; 81413907Sdyson return 0; 81513907Sdyson#endif 81613907Sdyson#ifdef INET6 81713907Sdyson case AF_INET6: 81813675Sdyson sin6 = (struct sockaddr_in6 *)sa; 81913907Sdyson if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 82013907Sdyson /* 82113675Sdyson * An IP6 address of 0 means listen to all 82213675Sdyson * of the Ethernet multicast address used for IP6. 82318863Sdyson * (This is used for multicast routers.) 824216511Salc */ 82513907Sdyson ifp->if_flags |= IFF_ALLMULTI; 82691412Salfred *llsa = 0; 827133790Ssilby return 0; 828133790Ssilby } 82979224Sdillon if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 830231949Skib return EADDRNOTAVAIL; 831231949Skib MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 832231949Skib M_ZERO); 833231949Skib sdl->sdl_len = sizeof *sdl; 83413907Sdyson sdl->sdl_family = AF_LINK; 835216699Salc sdl->sdl_index = ifp->if_index; 836216699Salc sdl->sdl_type = IFT_ARCNET; 837216699Salc sdl->sdl_alen = ARC_ADDR_LEN; 838193893Scperciva *LLADDR(sdl) = 0; 83913907Sdyson *llsa = (struct sockaddr *)sdl; 84013907Sdyson return 0; 84113907Sdyson#endif 84213907Sdyson 84313907Sdyson default: 84476760Salfred /* 84576760Salfred * Well, the text isn't quite right, but it's the name 84613907Sdyson * that counts... 84713907Sdyson */ 84813907Sdyson return EAFNOSUPPORT; 84913907Sdyson } 85013907Sdyson} 85113907Sdyson