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