1 /* $NetBSD: ofnet.c,v 1.9 1997/04/28 18:32:58 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 || len == 0) 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_free(m); 227 m_freem(head); 228 head = 0; 229 break; 230 } 231 l = MCLBYTES; 232 } 233 m->m_len = l = min(len, l); 234 bcopy(bufp, mtod(m, char *), l); 235 bufp += l; 236 len -= l; 237 *mp = m; 238 mp = &m->m_next; 239 } 240 if (head == 0) 241 continue; 242 eh = mtod(head, struct ether_header *); 243 244 #if NBPFILTER > 0 245 if (ifp->if_bpf) 246 bpf_mtap(ifp->if_bpf, m); 247 #endif 248 m_adj(head, sizeof(struct ether_header)); 249 ifp->if_ipackets++; 250 ether_input(ifp, eh, head); 251 } 252 } 253 254 static void 255 ofntimer(of) 256 struct ofn_softc *of; 257 { 258 ofnread(of); 259 timeout(ofntimer, of, 1); 260 } 261 262 static void 263 ofninit(of) 264 struct ofn_softc *of; 265 { 266 struct ifnet *ifp = &of->sc_ethercom.ec_if; 267 268 if (ifp->if_flags & IFF_RUNNING) 269 return; 270 271 ifp->if_flags |= IFF_RUNNING; 272 /* Start reading from interface */ 273 ofntimer(of); 274 /* Attempt to start output */ 275 ofnstart(ifp); 276 } 277 278 static void 279 ofnstop(of) 280 struct ofn_softc *of; 281 { 282 untimeout(ofntimer, of); 283 of->sc_ethercom.ec_if.if_flags &= ~IFF_RUNNING; 284 } 285 286 static void 287 ofnstart(ifp) 288 struct ifnet *ifp; 289 { 290 struct ofn_softc *of = ifp->if_softc; 291 struct mbuf *m, *m0; 292 char *bufp; 293 int len; 294 295 if (!(ifp->if_flags & IFF_RUNNING)) 296 return; 297 298 for (;;) { 299 /* First try reading any packets */ 300 ofnread(of); 301 302 /* Now get the first packet on the queue */ 303 IF_DEQUEUE(&ifp->if_snd, m0); 304 if (!m0) 305 return; 306 307 if (!(m0->m_flags & M_PKTHDR)) 308 panic("ofnstart: no header mbuf"); 309 len = m0->m_pkthdr.len; 310 311 #if NBPFILTER > 0 312 if (ifp->if_bpf) 313 bpf_mtap(ifp->if_bpf, m0); 314 #endif 315 316 if (len > ETHERMTU + sizeof(struct ether_header)) { 317 /* packet too large, toss it */ 318 ifp->if_oerrors++; 319 m_freem(m0); 320 continue; 321 } 322 323 for (bufp = buf; m = m0;) { 324 bcopy(mtod(m, char *), bufp, m->m_len); 325 bufp += m->m_len; 326 MFREE(m, m0); 327 } 328 if (OF_write(of->sc_ihandle, buf, bufp - buf) != bufp - buf) 329 ifp->if_oerrors++; 330 else 331 ifp->if_opackets++; 332 } 333 } 334 335 static int 336 ofnioctl(ifp, cmd, data) 337 struct ifnet *ifp; 338 u_long cmd; 339 caddr_t data; 340 { 341 struct ofn_softc *of = ifp->if_softc; 342 struct ifaddr *ifa = (struct ifaddr *)data; 343 struct ifreq *ifr = (struct ifreq *)data; 344 int error = 0; 345 346 switch (cmd) { 347 case SIOCSIFADDR: 348 ifp->if_flags |= IFF_UP; 349 350 switch (ifa->ifa_addr->sa_family) { 351 #ifdef INET 352 case AF_INET: 353 arp_ifinit(ifp, ifa); 354 break; 355 #endif 356 default: 357 break; 358 } 359 ofninit(of); 360 break; 361 case SIOCSIFFLAGS: 362 if (!(ifp->if_flags & IFF_UP) 363 && (ifp->if_flags & IFF_RUNNING)) { 364 /* If interface is down, but running, stop it. */ 365 ofnstop(of); 366 } else if ((ifp->if_flags & IFF_UP) 367 && !(ifp->if_flags & IFF_RUNNING)) { 368 /* If interface is up, but not running, start it. */ 369 ofninit(of); 370 } else { 371 /* Other flags are ignored. */ 372 } 373 break; 374 default: 375 error = EINVAL; 376 break; 377 } 378 return error; 379 } 380 381 static void 382 ofnwatchdog(ifp) 383 struct ifnet *ifp; 384 { 385 struct ofn_softc *of = ifp->if_softc; 386 387 log(LOG_ERR, "%s: device timeout\n", of->sc_dev.dv_xname); 388 ifp->if_oerrors++; 389 ofnstop(of); 390 ofninit(of); 391 } 392 393 #if NIPKDB_OFN > 0 394 static void 395 ipkdbofstart(kip) 396 struct ipkdb_if *kip; 397 { 398 int unit = kip->unit - 1; 399 400 if (ipkdb_of) 401 ipkdbattach(kip, &ipkdb_of->sc_ethercom); 402 } 403 404 static void 405 ipkdbofleave(kip) 406 struct ipkdb_if *kip; 407 { 408 } 409 410 static int 411 ipkdbofrcv(kip, buf, poll) 412 struct ipkdb_if *kip; 413 u_char *buf; 414 int poll; 415 { 416 int l; 417 418 do { 419 l = OF_read(kip->port, buf, ETHERMTU); 420 if (l < 0) 421 l = 0; 422 } while (!poll && !l); 423 return l; 424 } 425 426 static void 427 ipkdbofsend(kip, buf, l) 428 struct ipkdb_if *kip; 429 u_char *buf; 430 int l; 431 { 432 OF_write(kip->port, buf, l); 433 } 434 435 static int 436 ipkdbprobe(match, aux) 437 struct cfdata *match; 438 void *aux; 439 { 440 struct ipkdb_if *kip = aux; 441 static char name[256]; 442 int len; 443 int phandle; 444 445 kip->unit = match->cf_unit + 1; 446 447 if (!(kip->port = OF_open("net"))) 448 return -1; 449 if ((len = OF_instance_to_path(kip->port, name, sizeof name - 1)) < 0 450 || len >= sizeof name) 451 return -1; 452 name[len] = 0; 453 if ((phandle = OF_instance_to_package(kip->port)) == -1) 454 return -1; 455 if (OF_getprop(phandle, "mac-address", kip->myenetaddr, sizeof kip->myenetaddr) 456 < 0) 457 return -1; 458 459 kip->flags |= IPKDB_MYHW; 460 kip->name = name; 461 kip->start = ipkdbofstart; 462 kip->leave = ipkdbofleave; 463 kip->receive = ipkdbofrcv; 464 kip->send = ipkdbofsend; 465 466 kifp = kip; 467 468 return 0; 469 } 470 #endif 471