1 /* $NetBSD: if_prom.c,v 1.11 2011/01/12 15:32:43 tsutsui Exp $ */
2
3 /* Copyright (c) 1999 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Gregory McGarry.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <sys/param.h>
32 #include <sys/types.h>
33
34 #include <net/if_ether.h>
35 #include <netinet/in.h>
36 #include <netinet/in_systm.h>
37 #include <netinet/ip.h>
38
39 #include <lib/libsa/stand.h>
40 #include <lib/libsa/net.h>
41 #include <lib/libsa/netif.h>
42 #include <lib/libsa/dev_net.h>
43 #include <lib/libkern/libkern.h>
44
45 #include <machine/dec_prom.h>
46 #include <stand/common/common.h>
47
48 #ifdef NET_DEBUG
49 #define DPRINTF(x) printf(x)
50 #else
51 #define DPRINTF(x)
52 #endif
53
54 #ifdef NET_DEBUG
55 void dump_packet_info(void *, int);
56 #endif
57
58 /*
59 * For some reason the proms won't pass arp responses back to us. I
60 * have checked if the first parameter to bootread/bootwrite do anything
61 * but it doesn't appear so. Therefore, we stop the upper layers from
62 * sending arp requests in the first place, by monitoring packets which
63 * come in and filling the arp cache ourselves. - gmcgarry
64 */
65 #ifdef FILL_ARPCACHE
66 struct arp_list {
67 struct in_addr addr;
68 u_char ea[6];
69 };
70 extern struct arp_list arp_list[8];
71 extern int arp_num;
72 void fill_arpcache(void *, int);
73 #endif
74
75 /* forward declarations */
76 int prom_probe(struct netif *, void *);
77 int prom_match(struct netif *, void *);
78 void prom_init(struct iodesc *, void *);
79 int prom_get(struct iodesc *, void *, size_t, saseconds_t);
80 int prom_put(struct iodesc *, void *, size_t);
81 void prom_end(struct netif *);
82
83 extern struct netif_stats prom_stats[];
84 struct netif_dif prom_ifs[] = {
85 /* dif_unit dif_nsel dif_stats dif_private */
86 { 0, 1, &prom_stats[0], 0, },
87 };
88 #define NPROM_IFS (sizeof(prom_ifs) / sizeof(prom_ifs[0]))
89 struct netif_stats prom_stats[NPROM_IFS];
90
91 struct netif_driver prom_netif_driver = {
92 "prom", /* netif_bname */
93 prom_match, /* netif_match */
94 prom_probe, /* netif_probe */
95 prom_init, /* netif_init */
96 prom_get, /* netif_get */
97 prom_put, /* netif_put */
98 prom_end, /* netif_end */
99 prom_ifs, /* netif_ifs */
100 NPROM_IFS /* netif_nifs */
101 };
102
103 static int sc_fd; /* PROM file id */
104
105 int
prom_match(struct netif * nif,void * machdep_hint)106 prom_match(struct netif *nif, void *machdep_hint)
107 {
108
109 DPRINTF(("prom_match: called\n"));
110 return 1;
111 }
112
113
114 int
prom_probe(struct netif * nif,void * machdep_hint)115 prom_probe(struct netif *nif, void *machdep_hint)
116 {
117
118 DPRINTF(("prom_probe: called\n"));
119 return 0;
120 }
121
122
123 void
prom_init(struct iodesc * desc,void * machdep_hint)124 prom_init(struct iodesc *desc, void *machdep_hint)
125 {
126 struct netif *nif;
127 char *device, *enet;
128 uint8_t *cp, *dest;
129 int i;
130
131 DPRINTF(("prom_init: called\n"));
132
133 try_bootp = 1;
134
135 /*
136 * Get our hardware address (this prom call is one of the rare ones
137 * which is the same for new and old proms)
138 */
139 enet = (*callv->_getenv)("enet");
140
141 if (enet == NULL) {
142 printf("No `enet' environment variable found.\n"
143 "Set MAC address to `enet' manually by setenv command.\n");
144 prom_restart();
145 /* NOTREACHED */
146 }
147
148 #ifdef NET_DEBUG
149 if (debug)
150 printf("enet=%s\n", enet);
151 #endif
152
153 #define atox(c) (((c) <= '9') ? ((c) - '0') : ((toupper(c) - 'A') + 10))
154
155 cp = (uint8_t *)enet;
156 dest = desc->myea;
157 for (i = 0; i < 6; i++) {
158 if (isxdigit(*cp)) {
159 *dest = atox(*cp);
160 cp++;
161 if (isxdigit(*cp)) {
162 *dest = (*dest << 4) | atox(*cp);
163 cp++;
164 }
165 }
166 dest++;
167 cp++; /* skip '-' or ':' etc. */
168 }
169
170 desc->xid = 0x66d30000;
171
172 nif = desc->io_netif;
173 device = nif->nif_driver->netif_bname;
174 if (callv == &callvec)
175 sc_fd = prom_open(device, 0);
176 else
177 sc_fd = (*callv->_bootinit)(device);
178
179 if (sc_fd < 0)
180 printf("problem initialising device\n");
181 }
182
183
184 int
prom_put(struct iodesc * desc,void * pkt,size_t len)185 prom_put(struct iodesc *desc, void *pkt, size_t len)
186 {
187 int s;
188
189 DPRINTF(("prom_put: called\n"));
190
191 #ifdef NET_DEBUG
192 if (debug)
193 dump_packet_info(pkt,len);
194 #endif
195
196 if (callv == &callvec)
197 s = prom_write(sc_fd, pkt, len);
198 else {
199 s = (*callv->_bootwrite)(0, pkt, len);
200 (*callv->_wbflush)(); /* didn't really make a difference */
201 }
202 if (s < 0)
203 return EIO;
204 return s;
205 }
206
207
208 int
prom_get(struct iodesc * desc,void * pkt,size_t len,saseconds_t timeout)209 prom_get(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout)
210 {
211 int s;
212 satime_t t;
213
214 DPRINTF(("prom_get: called\n"));
215
216 t = getsecs();
217 s = 0;
218 while (((getsecs() - t) < timeout) && !s) {
219 if (callv == &callvec)
220 s = prom_read(sc_fd, pkt, len);
221 else
222 s = (*callv->_bootread)(0, pkt, len);
223 }
224
225 #ifdef FILL_ARPCACHE
226 if (s > 0)
227 fill_arpcache(pkt,s);
228 #endif
229
230 return s;
231 }
232
233
234 void
prom_end(struct netif * nif)235 prom_end(struct netif *nif)
236 {
237
238 DPRINTF(("prom_end: called\n"));
239
240 if (callv == &callvec)
241 prom_close(sc_fd);
242 }
243
244
245 #ifdef FILL_ARPCACHE
246 void
fill_arpcache(void * pkt,int len)247 fill_arpcache(void *pkt, int len)
248 {
249 int i;
250 struct arp_list *al;
251 struct ether_header *eh = (struct ether_header *)pkt;
252 struct ip *ih = (struct ip *)(eh + 1);
253
254 #ifdef NET_DEBUG
255 if (debug)
256 dump_packet_info(pkt, len);
257 #endif
258
259 if (ntohs(eh->ether_type) == 0x0800) {
260
261 /* check arp cache */
262 for (i=0, al=arp_list; i<arp_num; ++i, ++al) {
263 if (al->addr.s_addr == ih->ip_src.s_addr) {
264 /* already in cache */
265 return;
266 }
267 }
268 if (arp_num > 7)
269 arp_num = 1; /* recycle */
270 al->addr.s_addr = ih->ip_src.s_addr;
271 for (i = 0; i < 6; i++)
272 al->ea[i] = eh->ether_shost[i];
273 ++arp_num;
274 }
275 }
276 #endif
277
278 #ifdef NET_DEBUG
279 void
dump_packet_info(void * pkt,int len)280 dump_packet_info(void *pkt, int len)
281 {
282 struct ether_header *eh = (struct ether_header *)pkt;
283 struct ip *ih = (struct ip *)(eh + 1);
284
285 printf("ether_dhost = %s\n", ether_sprintf(eh->ether_dhost));
286 printf("ether_shost = %s\n", ether_sprintf(eh->ether_shost));
287 printf("ether_type = 0x%x\n", ntohs(eh->ether_type));
288
289 if (ntohs(eh->ether_type) == 0x0800) {
290 printf("ip packet version %d\n", ih->ip_v);
291 printf("source ip: 0x%x\n", ih->ip_src.s_addr);
292 printf("dest ip: 0x%x\n", ih->ip_dst.s_addr);
293 }
294 }
295 #endif
296