/* * Copyright (c) 1997-2000, 2002 University of Utah and the Flux Group. * All rights reserved. * * This file is part of the Flux OSKit. The OSKit is free software, also known * as "open source;" you can redistribute it and/or modify it under the terms * of the GNU General Public License (GPL), version 2, as published by the Free * Software Foundation (FSF). To explore alternate licensing terms, contact * the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271. * * The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have * received a copy of the GPL along with the OSKit; see the file COPYING. If * not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA. */ /* * This file simulates the "receive" of a FreeBSD device driver * "bsdnet_net_receive" is the callback function used for the push * method of the fdev netio instance. There, incoming packets are * analyzed and "mbuf"ized before they're passed up to the networking * code via ether_input(). * * ether_input() will queue the packet on the interface, and might * post a software irq for the processing. If it does, we immediately * execute the software irq. * * Note the use of the spl*() and save_cpl/restore_cpl here. * We must simulate what the code in /usr/src/sys/i386/isa/vector.s and * /usr/src/sys/i386/isa/icu.s does * * In particular, it does: * movl _cpl,%eax ; \ * pushl %eax ; \ * ... * orl _intr_mask + (irq_num) * 4,%eax ; \ * movl %eax,_cpl ; \ * ... * call *_intr_handler + (irq_num) * 4 ; \ * ... * jmp _doreti * <...> * _doreti: * ... * popl %eax cpl to restore * ... * movl %eax,_cpl * ... * iret * * Also, compare to the "send" side of things in bsdnet_driver.c */ /* * OSKit headers */ #include #include #include #include #include /* * include BSD headers */ #include #include #include #include #include #include #include #include #include #include #include #include "bsdnet_net_io.h" #define VERBOSITY 0 extern volatile unsigned oskit_freebsd_ipending; extern unsigned oskit_freebsd_idelayed; volatile unsigned int netisr; char * ethtoa(unsigned char p[6]); /* * We don't see the 64bit preamble or 32bit CRC so our * ETHERMAX is a little less than the 1526 ethernet frame size. */ #define ETHERMAX (1526-8-4) oskit_error_t bsdnet_net_receive(void *data, oskit_bufio_t *b, oskit_size_t pkt_size) { struct mbuf *m; struct ether_header *eh; unsigned char *frame; int rval = 0, err = 0, length, payload; caddr_t rb; oskit_freebsd_net_ether_if_t *eif = data; struct ifnet *ifp = eif->ifp; unsigned cpl; int s; if (pkt_size > ETHERMAX) { osenv_log(OSENV_LOG_WARNING, "%s: Hey Wally, I caught a big one! -- %d bytes\n", eif->info.name, pkt_size); return OSKIT_E_DEV_BADPARAM; } /* we are not associated with an interface yet * so we can't do anything */ if (!ifp) return 0; /* map data in */ /* buf, dest, offset, count */ err = oskit_bufio_map(b, (void **)&frame, 0, pkt_size); if (err) osenv_panic("oskit_bufio_map returned 0x%x\n", err); /* only used by ether_input... -> just pass a pointer to our buffer */ eh = (struct ether_header *)frame; { int type = ntohs(eh->ether_type); /* ignore IEEE 802.3 packets */ if (type < ETHERMTU) return 0; #if VERBOSITY > 0 osenv_log(OSENV_LOG_INFO, "RECV: src = %s", ethtoa(eh->ether_shost)); osenv_log(OSENV_LOG_INFO, " to %s, type = x%x, size = %d\n", ethtoa(eh->ether_dhost), type, pkt_size); #endif } /* keep a reference around! */ oskit_bufio_addref(b); /* NOW we're getting BSDish... */ /* save cpl */ save_cpl(&cpl); /* we set the cpl to what it would be if BSD processed that interrupt */ osenv_assert(osenv_intr_enabled() != 0); s = splimp(); /* * this code is modeled from /usr/src/sys/....../if_ix.c */ MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == 0) { osenv_log(OSENV_LOG_INFO, "MGETHDR:"); /* ZZZ need to add drop counters */ goto done; } length = pkt_size; payload = length - sizeof(struct ether_header); m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = payload; /* * here we go, faking an mbuf cluster */ m->m_ext.ext_buf = frame; m->m_ext.ext_size = length; m->m_data = rb = frame + sizeof(struct ether_header); m->m_len = payload; /* * mark this mbuf as referring to an oskit bufio */ m->m_ext.ext_bufio = b; m->m_flags |= M_EXT; /* we set the cpl to what it would be if BSD processed that interrupt */ splnet(); /* * hand packet up as if it came fresh from a device driver */ ether_input(ifp, eh, m); ifp->if_ipackets++; done: osenv_assert(osenv_intr_enabled() == 0); splx(s); /* now restore the cpl */ restore_cpl(cpl); return rval; } void bsdnet_net_softnet(void) { int s = splnet(); int i; osenv_assert((oskit_freebsd_ipending & SWI_NET_PENDING) != 0); for (i = 0; i < 32; i++) { if (netisr & (1 << i)) { netisrs[i](); } netisr &= ~(1 << i); } oskit_freebsd_ipending &= ~SWI_NET_PENDING; splx(s); }