1/* $NetBSD: if_prom.c,v 1.10 2011/01/10 17:01:17 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 55void 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 66struct arp_list { 67 struct in_addr addr; 68 u_char ea[6]; 69}; 70extern struct arp_list arp_list[8]; 71extern int arp_num; 72void fill_arpcache(void *, int); 73#endif 74 75/* forward declarations */ 76int prom_probe(struct netif *, void *); 77int prom_match(struct netif *, void *); 78void prom_init(struct iodesc *, void *); 79int prom_get(struct iodesc *, void *, size_t, saseconds_t); 80int prom_put(struct iodesc *, void *, size_t); 81void prom_end(struct netif *); 82 83extern struct netif_stats prom_stats[]; 84struct 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])) 89struct netif_stats prom_stats[NPROM_IFS]; 90 91struct 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 103static int sc_fd; /* PROM file id */ 104 105int 106prom_match(struct netif *nif, void *machdep_hint) 107{ 108 109 DPRINTF(("prom_match: called\n")); 110 return 1; 111} 112 113 114int 115prom_probe(struct netif *nif, void *machdep_hint) 116{ 117 118 DPRINTF(("prom_probe: called\n")); 119 return 0; 120} 121 122 123void 124prom_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 184int 185prom_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 208int 209prom_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 234void 235prom_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 246void 247fill_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 279void 280dump_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