Changeset View
Changeset View
Standalone View
Standalone View
tools/tools/mq-testing/tcp/vmeif.c
- This file was added.
/* | |||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science. | |||||
* Copyright (c) 2015 Tiwei Bie <btw@FreeBSD.org> | |||||
* | |||||
* All rights reserved. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without modification, | |||||
* are permitted provided that the following conditions are met: | |||||
* | |||||
* 1. Redistributions of source code must retain the above copyright notice, | |||||
* this list of conditions and the following disclaimer. | |||||
* 2. Redistributions in binary form must reproduce the above copyright notice, | |||||
* this list of conditions and the following disclaimer in the documentation | |||||
* and/or other materials provided with the distribution. | |||||
* 3. The name of the author may not be used to endorse or promote products | |||||
* derived from this software without specific prior written permission. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | |||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT | |||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT | |||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY | |||||
* OF SUCH DAMAGE. | |||||
* | |||||
* This file is part of the lwIP TCP/IP stack. | |||||
* | |||||
* Author: Adam Dunkels <adam@sics.se> | |||||
*/ | |||||
#include <fcntl.h> | |||||
#include <stdlib.h> | |||||
#include <stdio.h> | |||||
#include <string.h> | |||||
#include <unistd.h> | |||||
#include <sys/types.h> | |||||
#include <sys/uio.h> | |||||
#include <sys/socket.h> | |||||
#include "lwip/debug.h" | |||||
#include "lwip/opt.h" | |||||
#include "lwip/def.h" | |||||
#include "lwip/ip.h" | |||||
#include "lwip/mem.h" | |||||
#include "lwip/pbuf.h" | |||||
#include "lwip/sys.h" | |||||
#include "netif/etharp.h" | |||||
#include "vmeif.h" | |||||
#define IFCONFIG_BIN "/sbin/ifconfig " | |||||
#define DEVVME "/dev/vme0" | |||||
#define IFCONFIG_ARGS "vme0 inet %d.%d.%d.%d" | |||||
#define IFNAME0 't' | |||||
#define IFNAME1 'p' | |||||
#ifndef VMEIF_DEBUG | |||||
#define VMEIF_DEBUG LWIP_DBG_OFF | |||||
#endif | |||||
struct vmeif { | |||||
struct eth_addr *ethaddr; | |||||
int fd; | |||||
}; | |||||
/* Forward declarations. */ | |||||
static void vmeif_input(struct netif *netif); | |||||
static void vmeif_thread(void *data); | |||||
static void | |||||
low_level_init(struct netif *netif) | |||||
{ | |||||
struct vmeif *vmeif; | |||||
char buf[sizeof(IFCONFIG_ARGS) + sizeof(IFCONFIG_BIN) + 50]; | |||||
vmeif = (struct vmeif *)netif->state; | |||||
/* Obtain MAC address from network interface. */ | |||||
/* (We just fake an address...) */ | |||||
vmeif->ethaddr->addr[0] = 0xbc; | |||||
vmeif->ethaddr->addr[1] = 0xae; | |||||
vmeif->ethaddr->addr[2] = 0xc5; | |||||
vmeif->ethaddr->addr[3] = 0x23; | |||||
vmeif->ethaddr->addr[4] = 0x61; | |||||
vmeif->ethaddr->addr[5] = 0x22; | |||||
/* Do whatever else is needed to initialize interface. */ | |||||
vmeif->fd = open(DEVVME, O_RDWR); | |||||
LWIP_DEBUGF(VMEIF_DEBUG, ("vmeif_init: fd %d\n", vmeif->fd)); | |||||
if (vmeif->fd == -1) { | |||||
perror("vmeif_init: cannot open " DEVVME); | |||||
exit(1); | |||||
} | |||||
sprintf(buf, IFCONFIG_BIN IFCONFIG_ARGS, | |||||
ip4_addr1(&(netif->gw)), | |||||
ip4_addr2(&(netif->gw)), | |||||
ip4_addr3(&(netif->gw)), ip4_addr4(&(netif->gw))); | |||||
LWIP_DEBUGF(VMEIF_DEBUG, ("vmeif_init: system(\"%s\");\n", buf)); | |||||
system(buf); | |||||
sys_thread_new("vmeif_thread", vmeif_thread, netif, | |||||
DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); | |||||
} | |||||
/* | |||||
* low_level_output(): | |||||
* | |||||
* Should do the actual transmission of the packet. The packet is | |||||
* contained in the pbuf that is passed to the function. This pbuf | |||||
* might be chained. | |||||
*/ | |||||
static err_t | |||||
low_level_output(struct netif *netif, struct pbuf *p) | |||||
{ | |||||
struct pbuf *q; | |||||
char buf[1514]; | |||||
char *bufptr; | |||||
struct vmeif *vmeif; | |||||
vmeif = (struct vmeif *)netif->state; | |||||
/* initiate transfer(); */ | |||||
bufptr = &buf[0]; | |||||
for (q = p; q != NULL; q = q->next) { | |||||
/* Send the data from the pbuf to the interface, one pbuf at a | |||||
time. The size of the data in each pbuf is kept in the ->len | |||||
variable. */ | |||||
/* send data from(q->payload, q->len); */ | |||||
memcpy(bufptr, q->payload, q->len); | |||||
bufptr += q->len; | |||||
} | |||||
/* signal that packet should be sent(); */ | |||||
if (write(vmeif->fd, buf, p->tot_len) == -1) { | |||||
perror("vmeif: write"); | |||||
} | |||||
return (ERR_OK); | |||||
} | |||||
/* | |||||
* low_level_input(): | |||||
* | |||||
* Should allocate a pbuf and transfer the bytes of the incoming | |||||
* packet from the interface into the pbuf. | |||||
*/ | |||||
static struct pbuf * | |||||
low_level_input(struct vmeif *vmeif) | |||||
{ | |||||
struct pbuf *p, *q; | |||||
u16_t len; | |||||
char buf[1514]; | |||||
char *bufptr; | |||||
/* Obtain the size of the packet and put it into the "len" | |||||
variable. */ | |||||
len = read(vmeif->fd, buf, sizeof(buf)); | |||||
/* We allocate a pbuf chain of pbufs from the pool. */ | |||||
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); | |||||
if (p != NULL) { | |||||
/* We iterate over the pbuf chain until we have read the entire | |||||
packet into the pbuf. */ | |||||
bufptr = &buf[0]; | |||||
for (q = p; q != NULL; q = q->next) { | |||||
/* Read enough bytes to fill this pbuf in the chain. The | |||||
available data in the pbuf is given by the q->len | |||||
variable. */ | |||||
/* read data into(q->payload, q->len); */ | |||||
memcpy(q->payload, bufptr, q->len); | |||||
bufptr += q->len; | |||||
} | |||||
/* acknowledge that packet has been read(); */ | |||||
} else { | |||||
/* drop packet(); */ | |||||
} | |||||
return (p); | |||||
} | |||||
static void | |||||
vmeif_thread(void *arg) | |||||
{ | |||||
struct netif *netif; | |||||
struct vmeif *vmeif; | |||||
fd_set fdset; | |||||
int ret; | |||||
netif = (struct netif *)arg; | |||||
vmeif = (struct vmeif *)netif->state; | |||||
while (1) { | |||||
FD_ZERO(&fdset); | |||||
FD_SET(vmeif->fd, &fdset); | |||||
/* Wait for a packet to arrive. */ | |||||
ret = select(vmeif->fd + 1, &fdset, NULL, NULL, NULL); | |||||
if (ret == 1) { | |||||
/* Handle incoming packet. */ | |||||
vmeif_input(netif); | |||||
} else if (ret == -1) { | |||||
perror("vmeif_thread: select"); | |||||
} | |||||
} | |||||
} | |||||
/* | |||||
* vmeif_input(): | |||||
* | |||||
* This function should be called when a packet is ready to be read | |||||
* from the interface. It uses the function low_level_input() that | |||||
* should handle the actual reception of bytes from the network | |||||
* interface. | |||||
*/ | |||||
static void | |||||
vmeif_input(struct netif *netif) | |||||
{ | |||||
struct vmeif *vmeif; | |||||
struct eth_hdr *ethhdr; | |||||
struct pbuf *p; | |||||
vmeif = (struct vmeif *)netif->state; | |||||
p = low_level_input(vmeif); | |||||
if (p == NULL) { | |||||
LWIP_DEBUGF(VMEIF_DEBUG, | |||||
("vmeif_input: low_level_input returned NULL\n")); | |||||
return; | |||||
} | |||||
ethhdr = (struct eth_hdr *)p->payload; | |||||
switch (htons(ethhdr->type)) { | |||||
/* IP or ARP packet? */ | |||||
case ETHTYPE_IP: | |||||
case ETHTYPE_ARP: | |||||
/* full packet send to tcpip_thread to process */ | |||||
if (netif->input(p, netif) != ERR_OK) { | |||||
LWIP_DEBUGF(NETIF_DEBUG, | |||||
("ethernetif_input: IP input error\n")); | |||||
pbuf_free(p); | |||||
p = NULL; | |||||
} | |||||
break; | |||||
default: | |||||
pbuf_free(p); | |||||
break; | |||||
} | |||||
} | |||||
/* | |||||
* vmeif_init(): | |||||
* | |||||
* Should be called at the beginning of the program to set up the | |||||
* network interface. It calls the function low_level_init() to do the | |||||
* actual setup of the hardware. | |||||
*/ | |||||
err_t | |||||
vmeif_init(struct netif *netif) | |||||
{ | |||||
struct vmeif *vmeif; | |||||
vmeif = mem_malloc(sizeof(struct vmeif)); | |||||
if (!vmeif) | |||||
return (ERR_MEM); | |||||
netif->state = vmeif; | |||||
netif->name[0] = IFNAME0; | |||||
netif->name[1] = IFNAME1; | |||||
netif->output = etharp_output; | |||||
netif->linkoutput = low_level_output; | |||||
netif->mtu = 1500; | |||||
/* hardware address length */ | |||||
netif->hwaddr_len = 6; | |||||
vmeif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); | |||||
netif->flags = | |||||
NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP; | |||||
low_level_init(netif); | |||||
return (ERR_OK); | |||||
} |