ofnet.c revision 1.2
1/* $NetBSD: ofnet.c,v 1.2 1996/10/10 21:20:36 christos 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 NKGDB_OFN > 0 53#include <kgdb/kgdb.h> 54#include <machine/kgdb.h> 55 56struct cfattach kgdb_ofn_ca = { 57 0, kgdb_probe, kgdb_attach 58}; 59 60static struct kgdb_if *kifp; 61static struct ofn_softc *kgdb_of; 62 63static int kgdbprobe __P((void *, void *)); 64#endif 65 66struct ofn_softc { 67 struct device sc_dev; 68 int sc_phandle; 69 int sc_ihandle; 70 struct arpcom sc_arpcom; 71}; 72 73static int ofnprobe __P((struct device *, void *, void *)); 74static void ofnattach __P((struct device *, struct device *, void *)); 75 76struct cfattach ofnet_ca = { 77 sizeof(struct ofn_softc), ofnprobe, ofnattach 78}; 79 80struct cfdriver ofnet_cd = { 81 NULL, "ofnet", DV_IFNET 82}; 83 84static void ofnread __P((struct ofn_softc *)); 85static void ofntimer __P((struct ofn_softc *)); 86static void ofninit __P((struct ofn_softc *)); 87static void ofnstop __P((struct ofn_softc *)); 88 89static void ofnstart __P((struct ifnet *)); 90static int ofnioctl __P((struct ifnet *, u_long, caddr_t)); 91static void ofnwatchdog __P((struct ifnet *)); 92 93static int 94ofnprobe(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 NKGDB_OFN > 0 103 if (!parent) 104 return kgdbprobe(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 116static void 117ofnattach(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 NKGDB_OFN > 0 129 if (kifp 130 && kifp->unit - 1 == of->sc_dev.dv_unit 131 && OF_instance_to_package(kifp->port) == ofp->phandle) { 132 kgdb_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 kprintf(": 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 164static char buf[ETHERMTU + sizeof(struct ether_header)]; 165 166static void 167ofnread(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 NKGDB_OFN > 0 177 kgdbrint(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 241static void 242ofntimer(of) 243 struct ofn_softc *of; 244{ 245 ofnread(of); 246 timeout(ofntimer, of, 1); 247} 248 249static void 250ofninit(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 265static void 266ofnstop(of) 267 struct ofn_softc *of; 268{ 269 untimeout(ofntimer, of); 270 of->sc_arpcom.ac_if.if_flags &= ~IFF_RUNNING; 271} 272 273static void 274ofnstart(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 321static int 322ofnioctl(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 367static void 368ofnwatchdog(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 NKGDB_OFN > 0 380static void 381kgdbofstart(kip) 382 struct kgdb_if *kip; 383{ 384 int unit = kip->unit - 1; 385 386 if (kgdb_of) 387 kgdbattach(kip, &kgdb_of->sc_arpcom); 388} 389 390static void 391kgdbofleave(kip) 392 struct kgdb_if *kip; 393{ 394} 395 396static int 397kgdbofrcv(kip, buf, poll) 398 struct kgdb_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 412static void 413kgdbofsend(kip, buf, l) 414 struct kgdb_if *kip; 415 u_char *buf; 416 int l; 417{ 418 OF_write(kip->port, buf, l); 419} 420 421static int 422kgdbprobe(match, aux) 423 void *match, *aux; 424{ 425 struct cfdata *cf = match; 426 struct kgdb_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 |= KGDB_MYHW; 446 kip->name = name; 447 kip->start = kgdbofstart; 448 kip->leave = kgdbofleave; 449 kip->receive = kgdbofrcv; 450 kip->send = kgdbofsend; 451 452 kifp = kip; 453 454 return 0; 455} 456#endif 457