home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Emulation / BasiliskII / src / BeOS / ether_beos.cpp < prev    next >
C/C++ Source or Header  |  1999-11-03  |  12KB  |  468 lines

  1. /*
  2.  *  ether_beos.cpp - Ethernet device driver, BeOS specific stuff
  3.  *
  4.  *  Basilisk II (C) 1997-1999 Christian Bauer
  5.  *  Portions (C) 1997-1999 Marc Hellwig
  6.  *
  7.  *  This program is free software; you can redistribute it and/or modify
  8.  *  it under the terms of the GNU General Public License as published by
  9.  *  the Free Software Foundation; either version 2 of the License, or
  10.  *  (at your option) any later version.
  11.  *
  12.  *  This program is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *  GNU General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU General Public License
  18.  *  along with this program; if not, write to the Free Software
  19.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20.  */
  21.  
  22. #include <KernelKit.h>
  23. #include <AppKit.h>
  24. #include <StorageKit.h>
  25. #include <support/List.h>
  26.  
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30.  
  31. #include "sysdeps.h"
  32. #include "cpu_emulation.h"
  33. #include "main.h"
  34. #include "prefs.h"
  35. #include "user_strings.h"
  36. #include "macos_util.h"
  37. #include "ether.h"
  38. #include "ether_defs.h"
  39.  
  40. #include "sheep_net.h"
  41.  
  42. #define DEBUG 0
  43. #include "debug.h"
  44.  
  45. #define MONITOR 0
  46.  
  47.  
  48. // List of attached protocols
  49. struct NetProtocol {
  50.     uint16 type;
  51.     uint32 handler;
  52. };
  53.  
  54. static BList prot_list;
  55.  
  56.  
  57. // Global variables
  58. static thread_id read_thread;                // Packet reception thread
  59. static bool ether_thread_active = true;        // Flag for quitting the reception thread
  60.  
  61. static area_id buffer_area;                    // Packet buffer area
  62. static net_buffer *net_buffer_ptr;            // Pointer to packet buffer
  63. static uint32 rd_pos;                        // Current read position in packet buffer
  64. static uint32 wr_pos;                        // Current write position in packet buffer
  65. static sem_id read_sem, write_sem;            // Semaphores to trigger packet reading/writing
  66.  
  67.  
  68. // Prototypes
  69. static status_t receive_proc(void *data);
  70.  
  71.  
  72. /*
  73.  *  Find protocol in list
  74.  */
  75.  
  76. static NetProtocol *find_protocol(uint16 type)
  77. {
  78.     // All 802.2 types are the same
  79.     if (type <= 1500)
  80.         type = 0;
  81.  
  82.     // Search list (we could use hashing here but there are usually only three
  83.     // handlers installed: 0x0000 for AppleTalk and 0x0800/0x0806 for TCP/IP)
  84.     NetProtocol *p;
  85.     for (int i=0; (p = (NetProtocol *)prot_list.ItemAt(i)) != NULL; i++)
  86.         if (p->type == type)
  87.             return p;
  88.     return NULL;
  89. }
  90.  
  91.  
  92. /*
  93.  *  Remove all protocols
  94.  */
  95.  
  96. static void remove_all_protocols(void)
  97. {
  98.     NetProtocol *p;
  99.     while ((p = (NetProtocol *)prot_list.RemoveItem((long)0)) != NULL)
  100.         delete p;
  101. }
  102.  
  103.  
  104. /*
  105.  *  Initialization
  106.  */
  107.  
  108. void EtherInit(void)
  109. {
  110.     // Do nothing if no Ethernet device specified
  111.     if (PrefsFindString("ether") == NULL)
  112.         return;
  113.  
  114.     // Find net_server team
  115. i_wanna_try_that_again:
  116.     bool found_add_on = false;
  117.     team_info t_info;
  118.     int32 t_cookie = 0;
  119.     image_info i_info;
  120.     int32 i_cookie = 0;
  121.     while (get_next_team_info(&t_cookie, &t_info) == B_NO_ERROR) {
  122.         if (strstr(t_info.args,"net_server")!=NULL) {
  123.  
  124.             // Check if sheep_net add-on is loaded
  125.             while (get_next_image_info(t_info.team, &i_cookie, &i_info) == B_NO_ERROR) {
  126.                 if (strstr(i_info.name, "sheep_net") != NULL) {
  127.                     found_add_on = true;
  128.                     break;                    
  129.                 }
  130.             }
  131.         } 
  132.         if (found_add_on) break;
  133.     }
  134.     if (!found_add_on) {
  135.  
  136.         // Search for sheep_net in network config file
  137.         char str[1024];
  138.         bool sheep_net_found = false;
  139.         FILE *fin = fopen("/boot/home/config/settings/network", "r");
  140.         while (!feof(fin)) {
  141.             fgets(str, 1024, fin);
  142.             if (strstr(str, "PROTOCOLS"))
  143.                 if (strstr(str, "sheep_net"))
  144.                     sheep_net_found = true;
  145.         }
  146.         fclose(fin);
  147.  
  148.         // It was found, so something else must be wrong
  149.         if (sheep_net_found) {
  150.             WarningAlert(GetString(STR_NO_NET_ADDON_WARN));
  151.             return;
  152.         }
  153.  
  154.         // Not found, inform the user
  155.         if (!ChoiceAlert(GetString(STR_NET_CONFIG_MODIFY_WARN), GetString(STR_OK_BUTTON), GetString(STR_CANCEL_BUTTON)))
  156.             return;
  157.  
  158.         // Change the network config file and restart the network
  159.         fin = fopen("/boot/home/config/settings/network", "r");
  160.         FILE *fout = fopen("/boot/home/config/settings/network.2", "w");
  161.         bool global_found = false;
  162.         bool modified = false;
  163.         while (!feof(fin)) {
  164.             str[0] = 0;
  165.             fgets(str, 1024, fin);
  166.             if (!global_found && strstr(str, "GLOBAL:")) {
  167.                 global_found = true;
  168.             } else if (global_found && !modified && strstr(str, "PROTOCOLS")) {
  169.                 str[strlen(str)-1] = 0;
  170.                 strcat(str, " sheep_net\n");
  171.                 modified = true;
  172.             } else if (global_found && !modified && strlen(str) > 2 && str[strlen(str) - 2] == ':') {
  173.                 fputs("\tPROTOCOLS = sheep_net\n", fout);
  174.                 modified = true;
  175.             }
  176.             fputs(str, fout);
  177.         }
  178.         if (!modified)
  179.             fputs("\tPROTOCOLS = sheep_net\n", fout);
  180.         fclose(fout);
  181.         fclose(fin);
  182.         remove("/boot/home/config/settings/network.orig");
  183.         rename("/boot/home/config/settings/network", "/boot/home/config/settings/network.orig");
  184.         rename("/boot/home/config/settings/network.2", "/boot/home/config/settings/network");
  185.  
  186.         app_info ai;
  187.         if (be_roster->GetAppInfo("application/x-vnd.Be-NETS", &ai) == B_OK) {
  188.             BMessenger msg(NULL, ai.team);
  189.             if (msg.IsValid()) {
  190.                 while (be_roster->IsRunning("application/x-vnd.Be-NETS")) {
  191.                     msg.SendMessage(B_QUIT_REQUESTED);
  192.                     snooze(500000);
  193.                 }
  194.             }
  195.         }
  196.         BPath path;
  197.         find_directory(B_BEOS_BOOT_DIRECTORY, &path);
  198.         path.Append("Netscript");
  199.         const char *argv[3] = {"/bin/sh", path.Path(), NULL};
  200.         thread_id net_server = load_image(2, argv, (const char **)environ);
  201.         resume_thread(net_server);
  202.         status_t l;
  203.         wait_for_thread(net_server, &l);
  204.         goto i_wanna_try_that_again;
  205.     }
  206.  
  207.     // Set up communications with add-on
  208.     area_id handler_buffer;
  209.     if ((handler_buffer = find_area("packet buffer")) < B_NO_ERROR) {
  210.         WarningAlert(GetString(STR_NET_ADDON_INIT_FAILED));
  211.         return;
  212.     }
  213.     if ((buffer_area = clone_area("local packet buffer", (void **)&net_buffer_ptr, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, handler_buffer)) < B_NO_ERROR) {
  214.         D(bug("EtherInit: couldn't clone packet area\n"));
  215.         WarningAlert(GetString(STR_NET_ADDON_CLONE_FAILED));
  216.         return;
  217.     }
  218.     if ((read_sem = create_sem(0, "ether read")) < B_NO_ERROR) {
  219.         printf("FATAL: can't create Ethernet semaphore\n");
  220.         return;
  221.     }
  222.     net_buffer_ptr->read_sem = read_sem;
  223.     write_sem = net_buffer_ptr->write_sem;
  224.     read_thread = spawn_thread(receive_proc, "Ethernet Receiver", B_URGENT_DISPLAY_PRIORITY, NULL);
  225.     resume_thread(read_thread);
  226.     for (int i=0; i<WRITE_PACKET_COUNT; i++)
  227.         net_buffer_ptr->write[i].cmd = IN_USE | (ACTIVATE_SHEEP_NET << 8);
  228.     rd_pos = wr_pos = 0;
  229.     release_sem(write_sem);
  230.  
  231.     // Get Ethernet address
  232.     memcpy(ether_addr, net_buffer_ptr->ether_addr, 6);
  233.     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]));
  234.  
  235.     // Everything OK
  236.     net_open = true;
  237. }
  238.  
  239.  
  240. /*
  241.  *  Deinitialization
  242.  */
  243.  
  244. void EtherExit(void)
  245. {
  246.     if (net_open) {
  247.  
  248.         // Close communications with add-on
  249.         for (int i=0; i<WRITE_PACKET_COUNT; i++)
  250.             net_buffer_ptr->write[i].cmd = IN_USE | (DEACTIVATE_SHEEP_NET << 8);
  251.         release_sem(write_sem);
  252.  
  253.         // Quit reception thread
  254.         ether_thread_active = false;
  255.         status_t result;
  256.         release_sem(read_sem);
  257.         wait_for_thread(read_thread, &result);
  258.  
  259.         delete_sem(read_sem);
  260.         delete_area(buffer_area);
  261.  
  262.         // Remove all protocols
  263.         remove_all_protocols();
  264.     }
  265. }
  266.  
  267.  
  268. /*
  269.  *  Reset
  270.  */
  271.  
  272. void EtherReset(void)
  273. {
  274.     remove_all_protocols();
  275. }
  276.  
  277.  
  278. /*
  279.  *  Add multicast address
  280.  */
  281.  
  282. int16 ether_add_multicast(uint32 pb)
  283. {
  284.     net_packet *p = &net_buffer_ptr->write[wr_pos];
  285.     if (p->cmd & IN_USE) {
  286.         D(bug("WARNING: Couldn't enable multicast address\n"));
  287.     } else {
  288.         Mac2Host_memcpy(p->data, pb + eMultiAddr, 6);
  289.         p->length = 6;
  290.         p->cmd = IN_USE | (ADD_MULTICAST << 8);
  291.         wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
  292.         release_sem(write_sem);
  293.     }
  294.     return noErr;
  295. }
  296.  
  297.  
  298. /*
  299.  *  Delete multicast address
  300.  */
  301.  
  302. int16 ether_del_multicast(uint32 pb)
  303. {
  304.     net_packet *p = &net_buffer_ptr->write[wr_pos];
  305.     if (p->cmd & IN_USE) {
  306.         D(bug("WARNING: Couldn't enable multicast address\n"));
  307.     } else {
  308.         Mac2Host_memcpy(p->data, pb + eMultiAddr, 6);
  309.         p->length = 6;
  310.         p->cmd = IN_USE | (REMOVE_MULTICAST << 8);
  311.         wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
  312.         release_sem(write_sem);
  313.     }
  314.     return noErr;
  315. }
  316.  
  317.  
  318. /*
  319.  *  Attach protocol handler
  320.  */
  321.  
  322. int16 ether_attach_ph(uint16 type, uint32 handler)
  323. {
  324.     // Already attached?
  325.     NetProtocol *p = find_protocol(type);
  326.     if (p != NULL)
  327.         return lapProtErr;
  328.     else {
  329.         // No, create and attach
  330.         p = new NetProtocol;
  331.         p->type = type;
  332.         p->handler = handler;
  333.         prot_list.AddItem(p);
  334.         return noErr;
  335.     }
  336. }
  337.  
  338.  
  339. /*
  340.  *  Detach protocol handler
  341.  */
  342.  
  343. int16 ether_detach_ph(uint16 type)
  344. {
  345.     NetProtocol *p = find_protocol(type);
  346.     if (p != NULL) {
  347.         prot_list.RemoveItem(p);
  348.         delete p;
  349.         return noErr;
  350.     } else
  351.         return lapProtErr;
  352. }
  353.  
  354.  
  355. /*
  356.  *  Transmit raw ethernet packet
  357.  */
  358.  
  359. int16 ether_write(uint32 wds)
  360. {
  361.     net_packet *p = &net_buffer_ptr->write[wr_pos];
  362.     if (p->cmd & IN_USE) {
  363.         D(bug("WARNING: Couldn't transmit packet (buffer full)\n"));
  364.     } else {
  365.  
  366.         // Copy packet to buffer
  367.         uint8 *start;
  368.         uint8 *bp = start = p->data;
  369.         for (;;) {
  370.             int len = ReadMacInt16(wds);
  371.             if (len == 0)
  372.                 break;
  373.             Mac2Host_memcpy(bp, ReadMacInt32(wds + 2), len);
  374.             bp += len;
  375.             wds += 6;
  376.         }
  377.  
  378.         // Set source address
  379.         memcpy(start + 6, ether_addr, 6);
  380.  
  381. #if MONITOR
  382.         bug("Sending Ethernet packet:\n");
  383.         for (int i=0; i<(uint32)(bp-start); i++) {
  384.             bug("%02x ", start[i]);
  385.         }
  386.         bug("\n");
  387. #endif
  388.  
  389.         // Notify add-on
  390.         p->length = (uint32)(bp - start);
  391.         p->cmd = IN_USE | (SHEEP_PACKET << 8);
  392.         wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
  393.         release_sem(write_sem);
  394.     }
  395.     return noErr;
  396. }
  397.  
  398.  
  399. /*
  400.  *  Packet reception thread
  401.  */
  402.  
  403. static status_t receive_proc(void *data)
  404. {
  405.     while (ether_thread_active) {
  406.         if (net_buffer_ptr->read[rd_pos].cmd & IN_USE) {
  407.             D(bug(" packet received, triggering Ethernet interrupt\n"));
  408.             SetInterruptFlag(INTFLAG_ETHER);
  409.             TriggerInterrupt();
  410.         }
  411.         acquire_sem_etc(read_sem, 1, B_TIMEOUT, 25000);
  412.     }
  413.     return 0;
  414. }
  415.  
  416.  
  417. /*
  418.  *  Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers
  419.  */
  420.  
  421. void EtherInterrupt(void)
  422. {
  423.     D(bug("EtherIRQ\n"));
  424.  
  425.     // Call protocol handler for received packets
  426.     net_packet *p = &net_buffer_ptr->read[rd_pos];
  427.     while (p->cmd & IN_USE) {
  428.         if ((p->cmd >> 8) == SHEEP_PACKET) {
  429. #if MONITOR
  430.             bug("Receiving Ethernet packet:\n");
  431.             for (int i=0; i<p->length; i++) {
  432.                 bug("%02x ", p->data[i]);
  433.             }
  434.             bug("\n");
  435. #endif
  436.             // Get packet type
  437.             uint16 type = ntohs(*(uint16 *)(p->data + 12));
  438.  
  439.             // Look for protocol
  440.             NetProtocol *prot = find_protocol(type);
  441.             if (prot == NULL)
  442.                 goto next;
  443.  
  444.             // No default handler
  445.             if (prot->handler == 0)
  446.                 goto next;
  447.  
  448.             // Copy header to RHA
  449.             Host2Mac_memcpy(ether_data + ed_RHA, p->data, 14);
  450.             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)));
  451.  
  452.             // Call protocol handler
  453.             M68kRegisters r;
  454.             r.d[0] = type;                                    // Packet type
  455.             r.d[1] = p->length - 14;                        // Remaining packet length (without header, for ReadPacket)
  456.             r.a[0] = (uint32)p->data + 14;                    // Pointer to packet (host address, for ReadPacket)
  457.             r.a[3] = ether_data + ed_RHA + 14;                // Pointer behind header in RHA
  458.             r.a[4] = ether_data + ed_ReadPacket;            // Pointer to ReadPacket/ReadRest routines
  459.             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]));
  460.             Execute68k(prot->handler, &r);
  461.         }
  462. next:    p->cmd = 0;    // Free packet
  463.         rd_pos = (rd_pos + 1) % READ_PACKET_COUNT;
  464.         p = &net_buffer_ptr->read[rd_pos];
  465.     }
  466.     D(bug(" EtherIRQ done\n"));
  467. }
  468.