home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Emulation / BasiliskII / src / Unix / Linux / ether_linux.cpp next >
Encoding:
C/C++ Source or Header  |  1999-11-03  |  9.5 KB  |  443 lines

  1. /*
  2.  *  ether_unix.cpp - Ethernet device driver, Unix specific stuff
  3.  *
  4.  *  Basilisk II (C) 1997-1999 Christian Bauer
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. #include "sysdeps.h"
  22.  
  23. #include <sys/ioctl.h>
  24. #include <sys/poll.h>
  25. #include <semaphore.h>
  26. #include <errno.h>
  27. #include <stdio.h>
  28.  
  29. #include "cpu_emulation.h"
  30. #include "main.h"
  31. #include "macos_util.h"
  32. #include "prefs.h"
  33. #include "user_strings.h"
  34. #include "ether.h"
  35. #include "ether_defs.h"
  36.  
  37. #define DEBUG 0
  38. #include "debug.h"
  39.  
  40. #define MONITOR 0
  41.  
  42.  
  43. // List of attached protocols
  44. struct NetProtocol {
  45.     NetProtocol *next;
  46.     uint16 type;
  47.     uint32 handler;
  48. };
  49.  
  50. static NetProtocol *prot_list = NULL;
  51.  
  52.  
  53. // Global variables
  54. static int fd = -1;                            // fd of sheep_net device
  55. static pthread_t ether_thread;                // Packet reception thread
  56. static pthread_attr_t ether_thread_attr;    // Packet reception thread attributes
  57. static bool thread_active = false;            // Flag: Packet reception thread installed
  58. static sem_t int_ack;                        // Interrupt acknowledge semaphore
  59. static bool is_ethertap;                    // Flag: Ethernet device is ethertap
  60.  
  61. // Prototypes
  62. static void *receive_func(void *arg);
  63.  
  64.  
  65. /*
  66.  *  Find protocol in list
  67.  */
  68.  
  69. static NetProtocol *find_protocol(uint16 type)
  70. {
  71.     // All 802.2 types are the same
  72.     if (type <= 1500)
  73.         type = 0;
  74.  
  75.     // Search list (we could use hashing here but there are usually only three
  76.     // handlers installed: 0x0000 for AppleTalk and 0x0800/0x0806 for TCP/IP)
  77.     NetProtocol *p = prot_list;
  78.     while (p) {
  79.         if (p->type == type)
  80.             return p;
  81.         p = p->next;
  82.     }
  83.     return NULL;
  84. }
  85.  
  86.  
  87. /*
  88.  *  Remove all protocols
  89.  */
  90.  
  91. static void remove_all_protocols(void)
  92. {
  93.     NetProtocol *p = prot_list;
  94.     while (p) {
  95.         NetProtocol *next = p->next;
  96.         delete p;
  97.         p = next;
  98.     }
  99.     prot_list = NULL;
  100. }
  101.  
  102.  
  103. /*
  104.  *  Initialization
  105.  */
  106.  
  107. void EtherInit(void)
  108. {
  109.     int nonblock = 1;
  110.     char str[256];
  111.  
  112.     // Do nothing if no Ethernet device specified
  113.     const char *name = PrefsFindString("ether");
  114.     if (name == NULL)
  115.         return;
  116.  
  117.     // Is it Ethertap?
  118.     is_ethertap = (strncmp(name, "tap", 3) == 0);
  119.  
  120.     // Open sheep_net or ethertap device
  121.     char dev_name[16];
  122.     if (is_ethertap)
  123.         sprintf(dev_name, "/dev/%s", name);
  124.     else
  125.         strcpy(dev_name, "/dev/sheep_net");
  126.     fd = open(dev_name, O_RDWR);
  127.     if (fd < 0) {
  128.         sprintf(str, GetString(STR_NO_SHEEP_NET_DRIVER_WARN), dev_name, strerror(errno));
  129.         WarningAlert(str);
  130.         goto open_error;
  131.     }
  132.  
  133.     // Attach sheep_net to selected Ethernet card
  134.     if (!is_ethertap && ioctl(fd, SIOCSIFLINK, name) < 0) {
  135.         sprintf(str, GetString(STR_SHEEP_NET_ATTACH_WARN), strerror(errno));
  136.         WarningAlert(str);
  137.         goto open_error;
  138.     }
  139.  
  140.     // Set nonblocking I/O
  141.     ioctl(fd, FIONBIO, &nonblock);
  142.  
  143.     // Get Ethernet address
  144.     if (is_ethertap) {
  145.         pid_t p = getpid();    // If configured for multicast, ethertap requires that the lower 32 bit of the Ethernet address are our PID
  146.         ether_addr[0] = 0xfe;
  147.         ether_addr[1] = 0xfd;
  148.         ether_addr[2] = p >> 24;
  149.         ether_addr[3] = p >> 16;
  150.         ether_addr[4] = p >> 8;
  151.         ether_addr[5] = p;
  152.     } else
  153.         ioctl(fd, SIOCGIFADDR, ether_addr);
  154.     D(bug("Ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5]));
  155.  
  156.     // Start packet reception thread
  157.     if (sem_init(&int_ack, 0, 0) < 0) {
  158.         printf("WARNING: Cannot init semaphore");
  159.         goto open_error;
  160.     }
  161.     pthread_attr_init(ðer_thread_attr);
  162. #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
  163.     if (geteuid() == 0) {
  164.         pthread_attr_setinheritsched(ðer_thread_attr, PTHREAD_EXPLICIT_SCHED);
  165.         pthread_attr_setschedpolicy(ðer_thread_attr, SCHED_FIFO);
  166.         struct sched_param fifo_param;
  167.         fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2 + 1;
  168.         pthread_attr_setschedparam(ðer_thread_attr, &fifo_param);
  169.     }
  170. #endif
  171.     thread_active = (pthread_create(ðer_thread, ðer_thread_attr, receive_func, NULL) == 0);
  172.     if (!thread_active) {
  173.         printf("WARNING: Cannot start Ethernet thread");
  174.         goto open_error;
  175.     }
  176.  
  177.     // Everything OK
  178.     net_open = true;
  179.     return;
  180.  
  181. open_error:
  182.     if (thread_active) {
  183.         pthread_cancel(ether_thread);
  184.         pthread_join(ether_thread, NULL);
  185.         sem_destroy(&int_ack);
  186.         thread_active = false;
  187.     }
  188.     if (fd > 0) {
  189.         close(fd);
  190.         fd = -1;
  191.     }
  192. }
  193.  
  194.  
  195. /*
  196.  *  Deinitialization
  197.  */
  198.  
  199. void EtherExit(void)
  200. {
  201.     // Stop reception thread
  202.     if (thread_active) {
  203.         pthread_cancel(ether_thread);
  204.         pthread_join(ether_thread, NULL);
  205.         sem_destroy(&int_ack);
  206.         thread_active = false;
  207.     }
  208.  
  209.     // Close sheep_net device
  210.     if (fd > 0)
  211.         close(fd);
  212.  
  213.     // Remove all protocols
  214.     remove_all_protocols();
  215. }
  216.  
  217.  
  218. /*
  219.  *  Reset
  220.  */
  221.  
  222. void EtherReset(void)
  223. {
  224.     remove_all_protocols();
  225. }
  226.  
  227.  
  228. /*
  229.  *  Add multicast address
  230.  */
  231.  
  232. int16 ether_add_multicast(uint32 pb)
  233. {
  234.     if (ioctl(fd, SIOCADDMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
  235.         D(bug("WARNING: Couldn't enable multicast address\n"));
  236.         if (is_ethertap)
  237.             return noErr;
  238.         else
  239.             return eMultiErr;
  240.     } else
  241.         return noErr;
  242. }
  243.  
  244.  
  245. /*
  246.  *  Delete multicast address
  247.  */
  248.  
  249. int16 ether_del_multicast(uint32 pb)
  250. {
  251.     if (ioctl(fd, SIOCDELMULTI, Mac2HostAddr(pb + eMultiAddr)) < 0) {
  252.         D(bug("WARNING: Couldn't disable multicast address\n"));
  253.         return eMultiErr;
  254.     } else
  255.         return noErr;
  256. }
  257.  
  258.  
  259. /*
  260.  *  Attach protocol handler
  261.  */
  262.  
  263. int16 ether_attach_ph(uint16 type, uint32 handler)
  264. {
  265.     // Already attached?
  266.     NetProtocol *p = find_protocol(type);
  267.     if (p != NULL)
  268.         return lapProtErr;
  269.     else {
  270.         // No, create and attach
  271.         p = new NetProtocol;
  272.         p->next = prot_list;
  273.         p->type = type;
  274.         p->handler = handler;
  275.         prot_list = p;
  276.         return noErr;
  277.     }
  278. }
  279.  
  280.  
  281. /*
  282.  *  Detach protocol handler
  283.  */
  284.  
  285. int16 ether_detach_ph(uint16 type)
  286. {
  287.     NetProtocol *p = find_protocol(type);
  288.     if (p != NULL) {
  289.         NetProtocol *q = prot_list;
  290.         if (p == q) {
  291.             prot_list = p->next;
  292.             delete p;
  293.             return noErr;
  294.         }
  295.         while (q) {
  296.             if (q->next == p) {
  297.                 q->next = p->next;
  298.                 delete p;
  299.                 return noErr;
  300.             }
  301.             q = q->next;
  302.         }
  303.         return lapProtErr;
  304.     } else
  305.         return lapProtErr;
  306. }
  307.  
  308.  
  309. /*
  310.  *  Transmit raw ethernet packet
  311.  */
  312.  
  313. int16 ether_write(uint32 wds)
  314. {
  315.     // Set source address
  316.     uint32 hdr = ReadMacInt32(wds + 2);
  317.     Host2Mac_memcpy(hdr + 6, ether_addr, 6);
  318.  
  319.     // Copy packet to buffer
  320.     uint8 packet[1516], *p = packet;
  321.     int len = 0;
  322.     if (is_ethertap) {
  323.         *p++ = 0;    // Ethertap discards the first 2 bytes
  324.         *p++ = 0;
  325.         len += 2;
  326.     }
  327.     for (;;) {
  328.         int w = ReadMacInt16(wds);
  329.         if (w == 0)
  330.             break;
  331.         Mac2Host_memcpy(p, ReadMacInt32(wds + 2), w);
  332.         len += w;
  333.         p += w;
  334.         wds += 6;
  335.     }
  336.  
  337. #if MONITOR
  338.     bug("Sending Ethernet packet:\n");
  339.     for (int i=0; i<len; i++) {
  340.         bug("%02x ", packet[i]);
  341.     }
  342.     bug("\n");
  343. #endif
  344.  
  345.     // Transmit packet
  346.     if (write(fd, packet, len) < 0) {
  347.         D(bug("WARNING: Couldn't transmit packet\n"));
  348.         return excessCollsns;
  349.     } else
  350.         return noErr;
  351. }
  352.  
  353.  
  354. /*
  355.  *  Packet reception thread
  356.  */
  357.  
  358. static void *receive_func(void *arg)
  359. {
  360.     for (;;) {
  361.  
  362.         // Wait for packets to arrive
  363.         struct pollfd pf = {fd, POLLIN, 0};
  364.         int res = poll(&pf, 1, -1);
  365.         if (res <= 0)
  366.             break;
  367.  
  368.         // Trigger Ethernet interrupt
  369.         D(bug(" packet received, triggering Ethernet interrupt\n"));
  370.         SetInterruptFlag(INTFLAG_ETHER);
  371.         TriggerInterrupt();
  372.  
  373.         // Wait for interrupt acknowledge by EtherInterrupt()
  374.         sem_wait(&int_ack);
  375.     }
  376.     return NULL;
  377. }
  378.  
  379.  
  380. /*
  381.  *  Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers
  382.  */
  383.  
  384. void EtherInterrupt(void)
  385. {
  386.     D(bug("EtherIRQ\n"));
  387.  
  388.     // Call protocol handler for received packets
  389.     uint8 packet[1516];
  390.     for (;;) {
  391.  
  392.         // Read packet from sheep_net device
  393.         ssize_t length = read(fd, packet, is_ethertap ? 1516 : 1514);
  394.         if (length < 14)
  395.             break;
  396.  
  397. #if MONITOR
  398.         bug("Receiving Ethernet packet:\n");
  399.         for (int i=0; i<length; i++) {
  400.             bug("%02x ", packet[i]);
  401.         }
  402.         bug("\n");
  403. #endif
  404.  
  405.         // Pointer to packet data (Ethernet header)
  406.         uint8 *p = packet;
  407.         if (is_ethertap) {
  408.             p += 2;            // Ethertap has two random bytes before the packet
  409.             length -= 2;
  410.         }
  411.  
  412.         // Get packet type
  413.         uint16 type = ntohs(*(uint16 *)(p + 12));
  414.  
  415.         // Look for protocol
  416.         NetProtocol *prot = find_protocol(type);
  417.         if (prot == NULL)
  418.             continue;
  419.  
  420.         // No default handler
  421.         if (prot->handler == 0)
  422.             continue;
  423.  
  424.         // Copy header to RHA
  425.         Host2Mac_memcpy(ether_data + ed_RHA, p, 14);
  426.         D(bug(" header %08lx%04lx %08lx%04lx %04lx\n", ReadMacInt32(ether_data + ed_RHA), ReadMacInt16(ether_data + ed_RHA + 4), ReadMacInt32(ether_data + ed_RHA + 6), ReadMacInt16(ether_data + ed_RHA + 10), ReadMacInt16(ether_data + ed_RHA + 12)));
  427.  
  428.         // Call protocol handler
  429.         M68kRegisters r;
  430.         r.d[0] = type;                                    // Packet type
  431.         r.d[1] = length - 14;                            // Remaining packet length (without header, for ReadPacket)
  432.         r.a[0] = (uint32)p + 14;                        // Pointer to packet (host address, for ReadPacket)
  433.         r.a[3] = ether_data + ed_RHA + 14;                // Pointer behind header in RHA
  434.         r.a[4] = ether_data + ed_ReadPacket;            // Pointer to ReadPacket/ReadRest routines
  435.         D(bug(" calling protocol handler %08lx, type %08lx, length %08lx, data %08lx, rha %08lx, read_packet %08lx\n", prot->handler, r.d[0], r.d[1], r.a[0], r.a[3], r.a[4]));
  436.         Execute68k(prot->handler, &r);
  437.     }
  438.  
  439.     // Acknowledge interrupt to reception thread
  440.     D(bug(" EtherIRQ done\n"));
  441.     sem_post(&int_ack);
  442. }
  443.