1 /* $NetBSD: ofnet.c,v 1.8 1997/04/24 08:05:24 mycroft Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 5 * Copyright (C) 1995, 1996 TooLs GmbH. 6 * 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 TooLs GmbH. 19 * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 #include "ofnet.h" 34 #include "bpfilter.h" 35 36 #include <sys/param.h> 37 #include <sys/device.h> 38 #include <sys/ioctl.h> 39 #include <sys/mbuf.h> 40 #include <sys/socket.h> 41 #include <sys/syslog.h> 42 43 #include <net/if.h> 44 #include <net/if_ether.h> 45 46 #ifdef INET 47 #include <netinet/in.h> 48 #include <netinet/if_inarp.h> 49 #endif 50 51 #if NBPFILTER > 0 52 #include <net/bpf.h> 53 #include <net/bpfdesc.h> 54 #endif 55 56 #include <dev/ofw/openfirm.h> 57 58 #if NIPKDB_OFN > 0 59 #include <ipkdb/ipkdb.h> 60 #include <machine/ipkdb.h> 61 62 struct cfattach ipkdb_ofn_ca = { 63 0, ipkdb_probe, ipkdb_attach 64 }; 65 66 static struct ipkdb_if *kifp; 67 static struct ofn_softc *ipkdb_of; 68 69 static int ipkdbprobe __P((struct cfdata *, void *)); 70 #endif 71 72 struct ofn_softc { 73 struct device sc_dev; 74 int sc_phandle; 75 int sc_ihandle; 76 struct ethercom sc_ethercom; 77 }; 78 79 static int ofnprobe __P((struct device *, struct cfdata *, void *)); 80 static void ofnattach __P((struct device *, struct device *, void *)); 81 82 struct cfattach ofnet_ca = { 83 sizeof(struct ofn_softc), ofnprobe, ofnattach 84 }; 85 86 struct cfdriver ofnet_cd = { 87 NULL, "ofnet", DV_IFNET 88 }; 89 90 static void ofnread __P((struct ofn_softc *)); 91 static void ofntimer __P((struct ofn_softc *)); 92 static void ofninit __P((struct ofn_softc *)); 93 static void ofnstop __P((struct ofn_softc *)); 94 95 static void ofnstart __P((struct ifnet *)); 96 static int ofnioctl __P((struct ifnet *, u_long, caddr_t)); 97 static void ofnwatchdog __P((struct ifnet *)); 98 99 static int 100 ofnprobe(parent, match, aux) 101 struct device *parent; 102 struct cfdata *match; 103 void *aux; 104 { 105 struct ofprobe *ofp = aux; 106 char type[32]; 107 int l; 108 109 #if NIPKDB_OFN > 0 110 if (!parent) 111 return ipkdbprobe(match, aux); 112 #endif 113 if ((l = OF_getprop(ofp->phandle, "device_type", type, sizeof type - 1)) < 0) 114 return 0; 115 if (l >= sizeof type) 116 return 0; 117 type[l] = 0; 118 if (strcmp(type, "network")) 119 return 0; 120 return 1; 121 } 122 123 static void 124 ofnattach(parent, self, aux) 125 struct device *parent, *self; 126 void *aux; 127 { 128 struct ofn_softc *of = (void *)self; 129 struct ifnet *ifp = &of->sc_ethercom.ec_if; 130 struct ofprobe *ofp = aux; 131 char path[256]; 132 int l; 133 u_int8_t myaddr[ETHER_ADDR_LEN]; 134 135 of->sc_phandle = ofp->phandle; 136 #if NIPKDB_OFN > 0 137 if (kifp 138 && kifp->unit - 1 == of->sc_dev.dv_unit 139 && OF_instance_to_package(kifp->port) == ofp->phandle) { 140 ipkdb_of = of; 141 of->sc_ihandle = kifp->port; 142 } else 143 #endif 144 if ((l = OF_package_to_path(ofp->phandle, path, sizeof path - 1)) < 0 145 || l >= sizeof path 146 || (path[l] = 0, !(of->sc_ihandle = OF_open(path)))) 147 panic("ofnattach: unable to open"); 148 if (OF_getprop(ofp->phandle, "mac-address", 149 myaddr, sizeof myaddr) 150 < 0) 151 panic("ofnattach: no max-address"); 152 printf(": address %s\n", ether_sprintf(myaddr)); 153 154 bcopy(of->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); 155 ifp->if_softc = of; 156 ifp->if_start = ofnstart; 157 ifp->if_ioctl = ofnioctl; 158 ifp->if_watchdog = ofnwatchdog; 159 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; 160 161 if_attach(ifp); 162 ether_ifattach(ifp, myaddr); 163 164 #if NBPFILTER > 0 165 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 166 #endif 167 168 dk_establish(0, self); /* XXX */ 169 } 170 171 static char buf[ETHERMTU + sizeof(struct ether_header)]; 172 173 static void 174 ofnread(of) 175 struct ofn_softc *of; 176 { 177 struct ifnet *ifp = &of->sc_ethercom.ec_if; 178 struct ether_header *eh; 179 struct mbuf *m, **mp, *head; 180 int l, len; 181 char *bufp; 182 183 #if NIPKDB_OFN > 0 184 ipkdbrint(kifp, ifp); 185 #endif 186 while (1) { 187 if ((len = OF_read(of->sc_ihandle, buf, sizeof buf)) < 0) { 188 if (len == -2) 189 return; 190 ifp->if_ierrors++; 191 continue; 192 } 193 if (len < sizeof(struct ether_header)) { 194 ifp->if_ierrors++; 195 continue; 196 } 197 bufp = buf; 198 199 /* Allocate a header mbuf */ 200 MGETHDR(m, M_DONTWAIT, MT_DATA); 201 if (m == 0) { 202 ifp->if_ierrors++; 203 continue; 204 } 205 m->m_pkthdr.rcvif = ifp; 206 m->m_pkthdr.len = len; 207 l = MHLEN; 208 head = 0; 209 mp = &head; 210 211 while (len > 0) { 212 if (head) { 213 MGET(m, M_DONTWAIT, MT_DATA); 214 if (m == 0) { 215 ifp->if_ierrors++; 216 m_freem(head); 217 head = 0; 218 break; 219 } 220 l = MLEN; 221 } 222 if (len >= MINCLSIZE) { 223 MCLGET(m, M_DONTWAIT); 224 if ((m->m_flags & M_EXT) == 0) { 225 ifp->if_ierrors++; 226 m_freem(head); 227 head = 0; 228 break; 229 } 230 l = MCLBYTES; 231 } 232 m->m_len = l = min(len, l); 233 bcopy(bufp, mtod(m, char *), l); 234 bufp += l; 235 len -= l; 236 *mp = m; 237 mp = &m->m_next; 238 } 239 if (head == 0) 240 continue; 241 eh = mtod(head, struct ether_header *); 242 243 #if NBPFILTER > 0 244 if (ifp->if_bpf) 245 bpf_mtap(ifp->if_bpf, m); 246 #endif 247 m_adj(head, sizeof(struct ether_header)); 248 ifp->if_ipackets++; 249 ether_input(ifp, eh, head); 250 } 251 } 252 253 static void 254 ofntimer(of) 255 struct ofn_softc *of; 256 { 257 ofnread(of); 258 timeout(ofntimer, of, 1); 259 } 260 261 static void 262 ofninit(of) 263 struct ofn_softc *of; 264 { 265 struct ifnet *ifp = &of->sc_ethercom.ec_if; 266 267 if (ifp->if_flags & IFF_RUNNING) 268 return; 269 270 ifp->if_flags |= IFF_RUNNING; 271 /* Start reading from interface */ 272 ofntimer(of); 273 /* Attempt to start output */ 274 ofnstart(ifp); 275 } 276 277 static void 278 ofnstop(of) 279 struct ofn_softc *of; 280 { 281 untimeout(ofntimer, of); 282 of->sc_ethercom.ec_if.if_flags &= ~IFF_RUNNING; 283 } 284 285 static void 286 ofnstart(ifp) 287 struct ifnet *ifp; 288 { 289 struct ofn_softc *of = ifp->if_softc; 290 struct mbuf *m, *m0; 291 char *bufp; 292 int len; 293 294 if (!(ifp->if_flags & IFF_RUNNING)) 295 return; 296 297 for (;;) { 298 /* First try reading any packets */ 299 ofnread(of); 300 301 /* Now get the first packet on the queue */ 302 IF_DEQUEUE(&ifp->if_snd, m0); 303 if (!m0) 304 return; 305 306 if (!(m0->m_flags & M_PKTHDR)) 307 panic("ofnstart: no header mbuf"); 308 len = m0->m_pkthdr.len; 309 310 #if NBPFILTER > 0 311 if (ifp->if_bpf) 312 bpf_mtap(ifp->if_bpf, m0); 313 #endif 314 315 if (len > ETHERMTU + sizeof(struct ether_header)) { 316 /* packet too large, toss it */ 317 ifp->if_oerrors++; 318 m_freem(m0); 319 continue; 320 } 321 322 for (bufp = buf; m = m0;) { 323 bcopy(mtod(m, char *), bufp, m->m_len); 324 bufp += m->m_len; 325 MFREE(m, m0); 326 } 327 if (OF_write(of->sc_ihandle, buf, bufp - buf) != bufp - buf) 328 ifp->if_oerrors++; 329 else 330 ifp->if_opackets++; 331 } 332 } 333 334 static int 335 ofnioctl(ifp, cmd, data) 336 struct ifnet *ifp; 337 u_long cmd; 338 caddr_t data; 339 { 340 struct ofn_softc *of = ifp->if_softc; 341 struct ifaddr *ifa = (struct ifaddr *)data; 342 struct ifreq *ifr = (struct ifreq *)data; 343 int error = 0; 344 345 switch (cmd) { 346 case SIOCSIFADDR: 347 ifp->if_flags |= IFF_UP; 348 349 switch (ifa->ifa_addr->sa_family) { 350 #ifdef INET 351 case AF_INET: 352 arp_ifinit(ifp, ifa); 353 break; 354 #endif 355 default: 356 break; 357 } 358 ofninit(of); 359 break; 360 case SIOCSIFFLAGS: 361 if (!(ifp->if_flags & IFF_UP) 362 && (ifp->if_flags & IFF_RUNNING)) { 363 /* If interface is down, but running, stop it. */ 364 ofnstop(of); 365 } else if ((ifp->if_flags & IFF_UP) 366 && !(ifp->if_flags & IFF_RUNNING)) { 367 /* If interface is up, but not running, start it. */ 368 ofninit(of); 369 } else { 370 /* Other flags are ignored. */ 371 } 372 break; 373 default: 374 error = EINVAL; 375 break; 376 } 377 return error; 378 } 379 380 static void 381 ofnwatchdog(ifp) 382 struct ifnet *ifp; 383 { 384 struct ofn_softc *of = ifp->if_softc; 385 386 log(LOG_ERR, "%s: device timeout\n", of->sc_dev.dv_xname); 387 ifp->if_oerrors++; 388 ofnstop(of); 389 ofninit(of); 390 } 391 392 #if NIPKDB_OFN > 0 393 static void 394 ipkdbofstart(kip) 395 struct ipkdb_if *kip; 396 { 397 int unit = kip->unit - 1; 398 399 if (ipkdb_of) 400 ipkdbattach(kip, &ipkdb_of->sc_ethercom); 401 } 402 403 static void 404 ipkdbofleave(kip) 405 struct ipkdb_if *kip; 406 { 407 } 408 409 static int 410 ipkdbofrcv(kip, buf, poll) 411 struct ipkdb_if *kip; 412 u_char *buf; 413 int poll; 414 { 415 int l; 416 417 do { 418 l = OF_read(kip->port, buf, ETHERMTU); 419 if (l < 0) 420 l = 0; 421 } while (!poll && !l); 422 return l; 423 } 424 425 static void 426 ipkdbofsend(kip, buf, l) 427 struct ipkdb_if *kip; 428 u_char *buf; 429 int l; 430 { 431 OF_write(kip->port, buf, l); 432 } 433 434 static int 435 ipkdbprobe(match, aux) 436 struct cfdata *match; 437 void *aux; 438 { 439 struct ipkdb_if *kip = aux; 440 static char name[256]; 441 int len; 442 int phandle; 443 444 kip->unit = match->cf_unit + 1; 445 446 if (!(kip->port = OF_open("net"))) 447 return -1; 448 if ((len = OF_instance_to_path(kip->port, name, sizeof name - 1)) < 0 449 || len >= sizeof name) 450 return -1; 451 name[len] = 0; 452 if ((phandle = OF_instance_to_package(kip->port)) == -1) 453 return -1; 454 if (OF_getprop(phandle, "mac-address", kip->myenetaddr, sizeof kip->myenetaddr) 455 < 0) 456 return -1; 457 458 kip->flags |= IPKDB_MYHW; 459 kip->name = name; 460 kip->start = ipkdbofstart; 461 kip->leave = ipkdbofleave; 462 kip->receive = ipkdbofrcv; 463 kip->send = ipkdbofsend; 464 465 kifp = kip; 466 467 return 0; 468 } 469 #endif 470