Home | History | Annotate | Line # | Download | only in common
      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