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