]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/libofw/ofw_net.c
libarchive: merge from vendor branch
[FreeBSD/FreeBSD.git] / stand / libofw / ofw_net.c
1 /*-
2  * Copyright (c) 2000-2001 Benno Rice
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33
34 #include <net/if.h>
35 #include <netinet/in.h>
36 #include <netinet/in_systm.h>
37 #include <netinet/if_ether.h>
38 #include <netinet/ip.h>
39
40 #include <stand.h>
41 #include <net.h>
42 #include <netif.h>
43
44 #include "libofw.h"
45 #include "openfirm.h"
46
47 static int      ofwn_probe(struct netif *, void *);
48 static int      ofwn_match(struct netif *, void *);
49 static void     ofwn_init(struct iodesc *, void *);
50 static ssize_t  ofwn_get(struct iodesc *, void **, time_t);
51 static ssize_t  ofwn_put(struct iodesc *, void *, size_t);
52 static void     ofwn_end(struct netif *);
53
54 extern struct netif_stats       ofwn_stats[];
55
56 struct netif_dif ofwn_ifs[] = {
57         {
58                 .dif_unit=0,
59                 .dif_nsel=1,
60                 .dif_stats=&ofwn_stats[0],
61                 .dif_private=0,
62         },
63 };
64
65 struct netif_stats ofwn_stats[nitems(ofwn_ifs)];
66
67 struct netif_driver ofwnet = {
68         .netif_bname="net",
69         .netif_match=ofwn_match,
70         .netif_probe=ofwn_probe,
71         .netif_init=ofwn_init,
72         .netif_get=ofwn_get,
73         .netif_put=ofwn_put,
74         .netif_end=ofwn_end,
75         .netif_ifs=ofwn_ifs,
76         .netif_nifs=nitems(ofwn_ifs)
77 };
78
79 static ihandle_t        netinstance;
80
81 static void             *dmabuf;
82
83 static int
84 ofwn_match(struct netif *nif, void *machdep_hint)
85 {
86         return 1;
87 }
88
89 static int
90 ofwn_probe(struct netif *nif, void *machdep_hint)
91 {
92         return 0;
93 }
94
95 static ssize_t
96 ofwn_put(struct iodesc *desc, void *pkt, size_t len)
97 {
98         size_t                  sendlen;
99         ssize_t                 rv;
100
101 #if defined(NETIF_DEBUG)
102         struct ether_header     *eh;
103         printf("netif_put: desc=0x%x pkt=0x%x len=%d\n", desc, pkt, len);
104         eh = pkt;
105         printf("dst: %s ", ether_sprintf(eh->ether_dhost));
106         printf("src: %s ", ether_sprintf(eh->ether_shost));
107         printf("type: 0x%x\n", eh->ether_type & 0xffff);
108 #endif
109
110         sendlen = len;
111         if (sendlen < 60) {
112                 sendlen = 60;
113 #if defined(NETIF_DEBUG)
114                 printf("netif_put: length padded to %d\n", sendlen);
115 #endif
116         }
117
118         if (dmabuf) {
119                 bcopy(pkt, dmabuf, sendlen);
120                 pkt = dmabuf;
121         }
122
123         rv = OF_write(netinstance, pkt, len);
124
125 #if defined(NETIF_DEBUG)
126         printf("netif_put: OF_write returned %d\n", rv);
127 #endif
128
129         return rv;
130 }
131
132 static ssize_t
133 ofwn_get(struct iodesc *desc, void **pkt, time_t timeout)
134 {
135         time_t  t;
136         ssize_t length;
137         size_t  len;
138         char    *buf, *ptr;
139
140 #if defined(NETIF_DEBUG)
141         printf("netif_get: pkt=%p, timeout=%d\n", pkt, timeout);
142 #endif
143
144         /*
145          * We should read the "max-frame-size" int property instead,
146          * but at this time the iodesc does not have mtu, so we will take
147          * a small shortcut here.
148          */
149         len = ETHER_MAX_LEN;
150         buf = malloc(len + ETHER_ALIGN);
151         if (buf == NULL)
152                 return (-1);
153         ptr = buf + ETHER_ALIGN;
154
155         t = getsecs();
156         do {
157                 length = OF_read(netinstance, ptr, len);
158         } while ((length == -2 || length == 0) &&
159                 (getsecs() - t < timeout));
160
161 #if defined(NETIF_DEBUG)
162         printf("netif_get: received length=%d (%x)\n", length, length);
163 #endif
164
165         if (length < 12) {
166                 free(buf);
167                 return (-1);
168         }
169
170 #if defined(NETIF_VERBOSE_DEBUG)
171         {
172                 char *ch = ptr;
173                 int i;
174
175                 for(i = 0; i < 96; i += 4) {
176                         printf("%02x%02x%02x%02x  ", ch[i], ch[i+1],
177                             ch[i+2], ch[i+3]);
178                 }
179                 printf("\n");
180         }
181 #endif
182
183 #if defined(NETIF_DEBUG)
184         {
185                 struct ether_header *eh = ptr;
186
187                 printf("dst: %s ", ether_sprintf(eh->ether_dhost));
188                 printf("src: %s ", ether_sprintf(eh->ether_shost));
189                 printf("type: 0x%x\n", eh->ether_type & 0xffff);
190         }
191 #endif
192
193         *pkt = buf;
194         return (length);
195 }
196
197 static void
198 ofwn_init(struct iodesc *desc, void *machdep_hint)
199 {
200         phandle_t       netdev;
201         char            path[64];
202         char            *ch;
203         int             pathlen;
204
205         pathlen = OF_getprop(chosen, "bootpath", path, 64);
206         if ((ch = strchr(path, ':')) != NULL)
207                 *ch = '\0';
208         netdev = OF_finddevice(path);
209         if (OF_getprop(netdev, "local-mac-address", desc->myea, 6) == -1)
210                 goto punt;
211
212         printf("boot: ethernet address: %s\n", ether_sprintf(desc->myea));
213
214         if ((netinstance = OF_open(path)) == -1) {
215                 printf("Could not open network device.\n");
216                 goto punt;
217         }
218
219 #if defined(NETIF_DEBUG)
220         printf("ofwn_init: Open Firmware instance handle: %08x\n", netinstance);
221 #endif
222         dmabuf = NULL;
223         if (OF_call_method("dma-alloc", netinstance, 1, 1, (64 * 1024), &dmabuf)
224             < 0) {
225                 printf("Failed to allocate DMA buffer (got %p).\n", dmabuf);
226                 goto punt;
227         }
228 #if defined(NETIF_DEBUG)
229         printf("ofwn_init: allocated DMA buffer: %p\n", dmabuf);
230 #endif
231
232         return;
233
234 punt:
235         printf("\n");
236         printf("Could not boot from %s.\n", path);
237         OF_enter();
238 }
239
240 static void
241 ofwn_end(struct netif *nif)
242 {
243 #ifdef BROKEN
244         /* dma-free freezes at least some Apple ethernet controllers */
245         OF_call_method("dma-free", netinstance, 2, 0, dmabuf, MAXPHYS);
246 #endif
247         OF_close(netinstance);
248 }
249
250 #if 0
251 int
252 ofwn_getunit(const char *path)
253 {
254         int             i;
255         char            newpath[255];
256
257         OF_canon(path, newpath, 254);
258
259         for (i = 0; i < nofwninfo; i++) {
260                 printf(">>> test =\t%s\n", ofwninfo[i].ofwn_path);
261                 if (strcmp(path, ofwninfo[i].ofwn_path) == 0)
262                         return i;
263
264                 if (strcmp(newpath, ofwninfo[i].ofwn_path) == 0)
265                         return i;
266         }
267
268         return -1;
269 }
270 #endif
271
272 /*
273  * To properly match network devices, we have to subclass the netdev device.
274  * It has a different devdesc than a normal network device (which is fine:
275  * it's a struct superset) and different matching criteria (since it has to
276  * look at the path, find a handle and see if that handle is a network node
277  * or not).
278  */
279
280 static int ofwnd_init(void);
281 static int ofwnd_parsedev(struct devdesc **, const char *, const char **);
282 static bool ofwnd_match(struct devsw *, const char *);
283 static char *ofwnd_fmtdev(struct devdesc *);
284
285 struct devsw ofw_netdev = {
286         .dv_name = "network",
287         .dv_type = DEVT_NET,
288         .dv_init = ofwnd_init,
289         .dv_match = ofwnd_match,
290         .dv_fmtdev = ofwnd_fmtdev,
291         .dv_parsedev = ofwnd_parsedev,
292 };
293
294 static int ofwnd_init(void)
295 {
296         netdev.dv_init();
297         ofw_netdev.dv_strategy = netdev.dv_strategy;
298         ofw_netdev.dv_open = netdev.dv_open;
299         ofw_netdev.dv_close = netdev.dv_close;
300         ofw_netdev.dv_ioctl = netdev.dv_ioctl;
301         ofw_netdev.dv_print = netdev.dv_print;
302         ofw_netdev.dv_fmtdev = netdev.dv_fmtdev;
303         /* parsedev is unique to ofwnd */
304         /* match is unique to ofwnd */
305         return (0);
306 }
307
308 static int
309 ofwnd_parsedev(struct devdesc **dev, const char *devspec, const char **path)
310 {
311         return (ofw_common_parsedev(dev, devspec, path, ofw_netdev.dv_name));
312 }
313
314 static bool
315 ofwnd_match(struct devsw *devsw, const char *devspec)
316 {
317         const char *path;
318
319         return (ofw_path_to_handle(devspec, devsw->dv_name, &path) != -1);
320 }
321
322 static char *
323 ofwnd_fmtdev(struct devdesc *idev)
324 {
325         struct ofw_devdesc *dev = (struct ofw_devdesc *)idev;
326
327         return (dev->d_path);
328 }