1 /* $NetBSD: if_arcsubr.c,v 1.3 1995/04/14 17:06:39 chopps 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/syslog.h> 48 #include <sys/errno.h> 49 50 #include <machine/cpu.h> 51 52 #include <net/if.h> 53 #include <net/netisr.h> 54 #include <net/route.h> 55 #include <net/if_dl.h> 56 #include <net/if_types.h> 57 58 #ifdef INET 59 #include <netinet/in.h> 60 #include <netinet/in_var.h> 61 #endif 62 #include <netinet/if_arc.h> 63 64 u_char arcbroadcastaddr = 0; 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 with 194 * the ARCnet header. 195 */ 196 void 197 arc_input(ifp, m) 198 struct ifnet *ifp; 199 struct mbuf *m; 200 { 201 register struct arc_header *ah; 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 ah = mtod(m,struct arc_header *); 211 212 ifp->if_lastchange = time; 213 ifp->if_ibytes += m->m_pkthdr.len; 214 215 if (arcbroadcastaddr == ah->arc_dhost) { 216 m->m_flags |= M_BCAST; 217 ifp->if_imcasts++; 218 } 219 220 atype = ah->arc_type; 221 switch (atype) { 222 #ifdef INET 223 case ARCTYPE_IP_OLD: 224 m_adj(m,ARC_HDRLEN); 225 schednetisr(NETISR_IP); 226 inq = &ipintrq; 227 break; 228 #endif 229 default: 230 m_freem(m); 231 return; 232 } 233 234 s = splimp(); 235 if (IF_QFULL(inq)) { 236 IF_DROP(inq); 237 m_freem(m); 238 } else 239 IF_ENQUEUE(inq, m); 240 splx(s); 241 } 242 243 /* 244 * Convert Arcnet address to printable (loggable) representation. 245 */ 246 static char digits[] = "0123456789abcdef"; 247 char * 248 arc_sprintf(ap) 249 register u_char *ap; 250 { 251 static char arcbuf[3]; 252 register char *cp = arcbuf; 253 254 *cp++ = digits[*ap >> 4]; 255 *cp++ = digits[*ap++ & 0xf]; 256 *cp = 0; 257 return (arcbuf); 258 } 259 260 /* 261 * Perform common duties while attaching to interface list 262 */ 263 void 264 arc_ifattach(ifp) 265 register struct ifnet *ifp; 266 { 267 register struct ifaddr *ifa; 268 register struct sockaddr_dl *sdl; 269 270 ifp->if_type = IFT_ARCNET; 271 ifp->if_addrlen = 1; 272 ifp->if_hdrlen = ARC_HDRLEN; 273 ifp->if_mtu = ARCMTU; 274 if (((struct arccom *)ifp)->ac_anaddr == 0) { 275 log(LOG_ERR,"%s%d: link address 0 reserved for broadcasts.\n\ 276 Please change it and ifconfig %s%d down up\n", 277 ifp->if_name,ifp->if_unit,ifp->if_name,ifp->if_unit); 278 } 279 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 280 if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && 281 sdl->sdl_family == AF_LINK) { 282 sdl->sdl_type = IFT_ARCNET; 283 sdl->sdl_alen = ifp->if_addrlen; 284 bcopy((caddr_t)&((struct arccom *)ifp)->ac_anaddr, 285 LLADDR(sdl), ifp->if_addrlen); 286 break; 287 } 288 } 289