| /* |
| * sheep_net.cpp - Net server add-on for SheepShaver and Basilisk II |
| * |
| * SheepShaver (C) 1997-2008 Marc Hellwig and Christian Bauer |
| * Basilisk II (C) 1997-2008 Christian Bauer |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program 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 |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #include <KernelKit.h> |
| #include <SupportKit.h> |
| #include <add-ons/net_server/NetDevice.h> |
| #include <add-ons/net_server/NetProtocol.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stdarg.h> |
| #include <string.h> |
| #include <time.h> |
| |
| #include "sheep_net.h" |
| |
| #define DEBUG 0 |
| |
| #if DEBUG==1 |
| #define bug pprintf |
| #elif DEBUG==2 |
| #define bug kprintf |
| #endif |
| |
| #if DEBUG |
| #define D(x) (x) |
| #else |
| #define D(x) ; |
| #endif |
| |
| static int pprintf(const char* format, ...) |
| { |
| port_id PortNum; |
| int len,Ret; |
| char Buffer[1024]; |
| va_list ap; |
| |
| if ((PortNum = find_port("PortLogger")) == B_NAME_NOT_FOUND) |
| return(PortNum); |
| for (len=0; len<1024; len++) |
| Buffer[len]='\0'; |
| va_start(ap, format); |
| vsprintf(Buffer, format, ap); |
| Ret = write_port(PortNum, 0, Buffer, strlen(Buffer)); |
| return(Ret); |
| } |
| |
| |
| // Constants |
| #define NETDUMP_PRIO 1 // Default is 0 |
| |
| const uint32 buffer_size = (sizeof(net_buffer) / B_PAGE_SIZE + 1) * B_PAGE_SIZE; |
| |
| |
| // SheepNet add-on object |
| class SheepNetAddOn : public BNetProtocol, BPacketHandler { |
| public: |
| void AddDevice(BNetDevice *dev, const char *name); |
| bool PacketReceived(BNetPacket *buf, BNetDevice *dev); |
| }; |
| |
| |
| // Global variables |
| static bool shutdown_now = false; |
| static bool active = false; |
| |
| static thread_id write_thread; // Packet writer |
| static sem_id write_sem; // Semaphore to trigger packet writing |
| static BNetDevice *EtherCard = NULL; // The Ethernet card we are attached to |
| static area_id buffer_area; // Packet buffer area |
| static net_buffer *net_buffer_ptr; // Pointer to packet buffer |
| |
| static uint32 rd_pos; // Current read position in packet buffer |
| static uint32 wr_pos; // Current write position in packet buffer |
| |
| |
| /* |
| * Clear packet buffer |
| */ |
| |
| static void clear(void) |
| { |
| int i; |
| for (i=0;i<READ_PACKET_COUNT;i++) { |
| net_buffer_ptr->read[i].cmd = 0; |
| net_buffer_ptr->read[i].length = 0; |
| net_buffer_ptr->read[i].card = 0; |
| net_buffer_ptr->read[i].reserved = 0; |
| } |
| for (i=0;i<WRITE_PACKET_COUNT;i++) { |
| net_buffer_ptr->write[i].cmd = 0; |
| net_buffer_ptr->write[i].length = 0; |
| net_buffer_ptr->write[i].card = 0; |
| net_buffer_ptr->write[i].reserved = 0; |
| } |
| rd_pos = wr_pos = 0; |
| } |
| |
| |
| /* |
| * Packet writer thread |
| */ |
| |
| static status_t write_packet_func(void *arg) |
| { |
| while (!shutdown_now) { |
| |
| // Read and execute command |
| net_packet *p = &net_buffer_ptr->write[wr_pos]; |
| while (p->cmd & IN_USE) { |
| D(bug("wp: %d\n", wr_pos)); |
| switch (p->cmd >> 8) { |
| |
| case ACTIVATE_SHEEP_NET: |
| D(bug("activate sheep-net\n")); |
| active = false; |
| clear(); |
| active = true; |
| goto next; |
| |
| case DEACTIVATE_SHEEP_NET: |
| D(bug("deactivate sheep-net\n")); |
| active = false; |
| clear(); |
| goto next; |
| |
| case SHUTDOWN_SHEEP_NET: |
| D(bug("shutdown sheep-net\n")); |
| active = false; |
| clear(); |
| shutdown_now = true; |
| goto next; |
| |
| case ADD_MULTICAST: { |
| const char *data = (const char *)p->data; |
| D(bug("add multicast %02x %02x %02x %02x %02x %02x\n", data[0], data[1], data[2], data[3], data[4], data[5])); |
| if (active) { |
| status_t result; |
| if ((result = EtherCard->AddMulticastAddress(data)) != B_OK) { |
| // !! handle error !! error while creating multicast address |
| D(bug("error while creating multicast address %d\n", result)); |
| } |
| } |
| break; |
| } |
| |
| case REMOVE_MULTICAST: { |
| const char *data = (const char *)p->data; |
| D(bug("remove multicast %02x %02x %02x %02x %02x %02x\n", data[0], data[1], data[2], data[3], data[4], data[5])); |
| if (active) { |
| status_t result; |
| if ((result = EtherCard->RemoveMulticastAddress(data)) != B_OK) { |
| // !! handle error !! error while removing multicast address |
| D(bug("error while removing multicast address %d\n", result)); |
| } |
| } |
| break; |
| } |
| |
| case SHEEP_PACKET: { |
| uint32 length = p->length; |
| // D(bug("sheep packet %d\n", length)); |
| if (active) { |
| BStandardPacket *packet = new BStandardPacket(length); |
| packet->Write(0, (const char *)p->data, length); |
| EtherCard->SendPacket(packet); |
| } |
| break; |
| } |
| |
| default: |
| D(bug("error: unknown port packet type\n")); |
| break; |
| } |
| p->cmd = 0; // Free packet |
| wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT; |
| p = &net_buffer_ptr->write[wr_pos]; |
| } |
| |
| // Wait for next packet |
| next: acquire_sem_etc(write_sem, 1, B_TIMEOUT, 25000); |
| } |
| return 0; |
| } |
| |
| |
| /* |
| * Init the net add-on |
| */ |
| |
| static void init_addon() |
| { |
| int i; |
| D(bug("init sheep-net\n")); |
| |
| // Create packet buffer |
| if ((buffer_area = create_area("packet buffer", (void **)&net_buffer_ptr, B_ANY_ADDRESS, buffer_size, B_FULL_LOCK, B_READ_AREA | B_WRITE_AREA)) < B_NO_ERROR) { |
| D(bug("FATAL ERROR: can't create shared area\n")); |
| return; |
| } |
| |
| // Init packet buffer |
| clear(); |
| EtherCard->Address((char *)net_buffer_ptr->ether_addr); |
| net_buffer_ptr->read_sem = -1; |
| net_buffer_ptr->read_ofs = (uint32)(net_buffer_ptr->read) - (uint32)net_buffer_ptr; |
| net_buffer_ptr->read_packet_size = sizeof(net_packet); |
| net_buffer_ptr->read_packet_count = READ_PACKET_COUNT; |
| if ((write_sem = create_sem(0, "ether write")) < B_NO_ERROR) { |
| D(bug("FATAL ERROR: can't create semaphore\n")); |
| return; |
| } |
| net_buffer_ptr->write_sem = write_sem; |
| net_buffer_ptr->write_ofs = (uint32)(net_buffer_ptr->write) - (uint32)net_buffer_ptr; |
| net_buffer_ptr->write_packet_size = sizeof(net_packet); |
| net_buffer_ptr->write_packet_count = WRITE_PACKET_COUNT; |
| |
| // Start packet writer thread |
| write_thread = spawn_thread(write_packet_func, "sheep_net ether write", B_URGENT_DISPLAY_PRIORITY, NULL); |
| resume_thread(write_thread); |
| } |
| |
| |
| /* |
| * Add-on attached to Ethernet card |
| */ |
| |
| void SheepNetAddOn::AddDevice(BNetDevice *dev, const char *name) |
| { |
| if (dev->Type() != B_ETHER_NET_DEVICE) |
| return; |
| if (EtherCard != NULL) { |
| // !! handle error !! support for multiple ethernet cards ... |
| D(bug("error: SheepShaver doesn't support multiple Ethernetcards !\n")); |
| return; |
| } |
| EtherCard = dev; |
| init_addon(); |
| register_packet_handler(this, dev, NETDUMP_PRIO); |
| } |
| |
| |
| /* |
| * Ethernet packet received |
| */ |
| |
| bool SheepNetAddOn::PacketReceived(BNetPacket *pkt, BNetDevice *dev) |
| { |
| if (shutdown_now) { |
| unregister_packet_handler(this, dev); |
| return false; |
| } |
| // D(bug("read_packet_func %d\n", pkt->Size())); |
| if (active) { |
| D(bug("rp: %d\n", rd_pos)); |
| net_packet *p = &net_buffer_ptr->read[rd_pos]; |
| if (p->cmd & IN_USE) { |
| D(bug("error: full read buffer ... lost packet\n")); |
| } else { |
| memcpy(p->data, pkt->Data(), pkt->Size()); |
| p->length = pkt->Size(); |
| p->cmd = IN_USE | (SHEEP_PACKET << 8); |
| rd_pos = (rd_pos + 1) % READ_PACKET_COUNT; |
| release_sem(net_buffer_ptr->read_sem); |
| } |
| } |
| //D(bug("%02x %02x %02x %02x %02x %02x", (uchar) (pkt->Data())[0],(uchar) (pkt->Data())[1],(uchar) (pkt->Data())[2],(uchar) (pkt->Data())[3],(uchar) (pkt->Data())[4],(uchar) (pkt->Data())[5])); |
| return false; |
| } |
| |
| #pragma export on |
| extern "C" BNetProtocol *open_protocol(const char *device) |
| { |
| SheepNetAddOn *dev = new SheepNetAddOn; |
| return dev; |
| } |
| #pragma export off |