1 /* $NetBSD: if_arcsubr.c,v 1.1 1995/02/23 07:19:51 glass Exp $ */ 2 3 /* 4 * Copyright (c) 1994, 1995 Ignatios Souvatzis 5 * Copyright (c) 1982, 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp 37 * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93 38 * 39 */ 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/malloc.h> 45 #include <sys/mbuf.h> 46 #include <sys/socket.h> 47 #include <sys/errno.h> 48 49 #include <machine/cpu.h> 50 51 #include <net/if.h> 52 #include <net/netisr.h> 53 #include <net/route.h> 54 #include <net/if_dl.h> 55 #include <net/if_types.h> 56 57 #ifdef INET 58 #include <netinet/in.h> 59 #include <netinet/in_var.h> 60 #endif 61 #include <netinet/if_arc.h> 62 63 u_char arcbroadcastaddr = 0; 64 extern struct ifnet loif; 65 66 #define senderr(e) { error = (e); goto bad;} 67 68 #define SIN(s) ((struct sockaddr_in *)s) 69 70 /* 71 * ARCnet output routine. 72 * Encapsulate a packet of type family for the local net. 73 * Assumes that ifp is actually pointer to arccom structure. 74 */ 75 int 76 arc_output(ifp, m0, dst, rt0) 77 register struct ifnet *ifp; 78 struct mbuf *m0; 79 struct sockaddr *dst; 80 struct rtentry *rt0; 81 { 82 int s, error = 0; 83 u_char atype, adst; 84 register struct mbuf *m = m0; 85 register struct rtentry *rt; 86 struct mbuf *mcopy = (struct mbuf *)0; 87 register struct arc_header *ah; 88 int off, len = m->m_pkthdr.len; 89 struct arccom *ac = (struct arccom *)ifp; 90 91 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 92 senderr(ENETDOWN); 93 ifp->if_lastchange = time; 94 if (rt = rt0) { 95 if ((rt->rt_flags & RTF_UP) == 0) { 96 if (rt0 = rt = rtalloc1(dst, 1)) 97 rt->rt_refcnt--; 98 else 99 senderr(EHOSTUNREACH); 100 } 101 if (rt->rt_flags & RTF_GATEWAY) { 102 if (rt->rt_gwroute == 0) 103 goto lookup; 104 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 105 rtfree(rt); rt = rt0; 106 lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); 107 if ((rt = rt->rt_gwroute) == 0) 108 senderr(EHOSTUNREACH); 109 } 110 } 111 if (rt->rt_flags & RTF_REJECT) 112 if (rt->rt_rmx.rmx_expire == 0 || 113 time.tv_sec < rt->rt_rmx.rmx_expire) 114 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 115 } 116 switch (dst->sa_family) { 117 118 #ifdef INET 119 case AF_INET: 120 121 /* 122 * For now, use the simple IP addr -> ARCnet addr mapping 123 */ 124 if (m->m_flags & M_BCAST) 125 adst = arcbroadcastaddr; /* ARCnet broadcast address */ 126 else 127 adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF; 128 129 /* If broadcasting on a simplex interface, loopback a copy */ 130 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) 131 mcopy = m_copy(m, 0, (int)M_COPYALL); 132 off = m->m_pkthdr.len - m->m_len; 133 atype = ARCTYPE_IP_OLD; 134 break; 135 #endif 136 case AF_UNSPEC: 137 ah = (struct arc_header *)dst->sa_data; 138 adst = ah->arc_dhost; 139 atype = ah->arc_type; 140 break; 141 142 default: 143 printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, 144 dst->sa_family); 145 senderr(EAFNOSUPPORT); 146 } 147 148 149 if (mcopy) 150 (void) looutput(ifp, mcopy, dst, rt); 151 /* 152 * Add local net header. If no space in first mbuf, 153 * allocate another. 154 * 155 * For ARCnet, this is just symbolic. The header changes 156 * form and position on its way into the hardware and out of 157 * the wire. At this point, it contains source, destination and 158 * packet type. 159 */ 160 M_PREPEND(m, ARC_HDRLEN, M_DONTWAIT); 161 if (m == 0) 162 senderr(ENOBUFS); 163 ah = mtod(m, struct arc_header *); 164 ah->arc_type = atype; 165 ah->arc_dhost= adst; 166 ah->arc_shost= ac->ac_anaddr; 167 s = splimp(); 168 /* 169 * Queue message on interface, and start output if interface 170 * not yet active. 171 */ 172 if (IF_QFULL(&ifp->if_snd)) { 173 IF_DROP(&ifp->if_snd); 174 splx(s); 175 senderr(ENOBUFS); 176 } 177 IF_ENQUEUE(&ifp->if_snd, m); 178 if ((ifp->if_flags & IFF_OACTIVE) == 0) 179 (*ifp->if_start)(ifp); 180 splx(s); 181 182 ifp->if_obytes += len + ARC_HDRLEN; 183 return (error); 184 185 bad: 186 if (m) 187 m_freem(m); 188 return (error); 189 } 190 191 /* 192 * Process a received Arcnet packet; 193 * the packet is in the mbuf chain m without 194 * the ARCnet header, which is provided separately. 195 */ 196 void 197 arc_input(ifp, ah, m) 198 struct ifnet *ifp; 199 register struct arc_header *ah; 200 struct mbuf *m; 201 { 202 register struct ifqueue *inq; 203 u_char atype; 204 int s; 205 206 if ((ifp->if_flags & IFF_UP) == 0) { 207 m_freem(m); 208 return; 209 } 210 ifp->if_lastchange = time; 211 ifp->if_ibytes += m->m_pkthdr.len + sizeof (*ah); 212 213 if (arcbroadcastaddr == ah->arc_dhost) { 214 m->m_flags |= M_BCAST; 215 ifp->if_imcasts++; 216 } 217 218 atype = ah->arc_type; 219 switch (atype) { 220 #ifdef INET 221 case ARCTYPE_IP_OLD: 222 schednetisr(NETISR_IP); 223 inq = &ipintrq; 224 break; 225 #endif 226 default: 227 m_freem(m); 228 return; 229 } 230 231 s = splimp(); 232 if (IF_QFULL(inq)) { 233 IF_DROP(inq); 234 m_freem(m); 235 } else 236 IF_ENQUEUE(inq, m); 237 splx(s); 238 } 239 240 /* 241 * Convert Arcnet address to printable (loggable) representation. 242 */ 243 static char digits[] = "0123456789abcdef"; 244 char * 245 arc_sprintf(ap) 246 register u_char *ap; 247 { 248 static char arcbuf[3]; 249 register char *cp = arcbuf; 250 251 *cp++ = digits[*ap >> 4]; 252 *cp++ = digits[*ap++ & 0xf]; 253 *cp = 0; 254 return (arcbuf); 255 } 256 257 /* 258 * Perform common duties while attaching to interface list 259 */ 260 void 261 arc_ifattach(ifp) 262 register struct ifnet *ifp; 263 { 264 register struct ifaddr *ifa; 265 register struct sockaddr_dl *sdl; 266 267 ifp->if_type = IFT_ARCNET; 268 ifp->if_addrlen = 1; 269 ifp->if_hdrlen = ARC_HDRLEN; 270 ifp->if_mtu = ARCMTU; 271 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 272 if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && 273 sdl->sdl_family == AF_LINK) { 274 sdl->sdl_type = IFT_ARCNET; 275 sdl->sdl_alen = ifp->if_addrlen; 276 bcopy((caddr_t)&((struct arccom *)ifp)->ac_anaddr, 277 LLADDR(sdl), ifp->if_addrlen); 278 break; 279 } 280 } 281