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 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 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 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 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 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 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 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 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