ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/BeOS/ether_beos.cpp
Revision: 1.6
Committed: 2001-07-12T19:48:27Z (22 years, 10 months ago) by cebix
Branch: MAIN
Changes since 1.5: +27 -39 lines
Log Message:
- Implemented AppleTalk-over-UDP tunnelling, activated by setting "udptunnel"
  to "true". This uses the BSD socket API, so it's fairly portable (currently
  only imeplemented under Unix, though). This works by sending raw Ethernet
  packets as UDP packets to a fixed port number ("udpport", default is 6066),
  using IP broadcasts to simulate Ethernet broad- and multicasts. Currently
  only tested with AppleTalk.

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * ether_beos.cpp - Ethernet device driver, BeOS specific stuff
3     *
4 cebix 1.5 * Basilisk II (C) 1997-2001 Christian Bauer
5 cebix 1.1 * 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 cebix 1.2 * 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 cebix 1.1 * Initialization
106     */
107    
108 cebix 1.6 bool ether_init(void)
109 cebix 1.1 {
110     // Do nothing if no Ethernet device specified
111     if (PrefsFindString("ether") == NULL)
112 cebix 1.6 return false;
113 cebix 1.1
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 cebix 1.6 return false;
152 cebix 1.1 }
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 cebix 1.6 return false;
157 cebix 1.1
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 cebix 1.6 return false;
212 cebix 1.1 }
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 cebix 1.6 return false;
217 cebix 1.1 }
218     if ((read_sem = create_sem(0, "ether read")) < B_NO_ERROR) {
219     printf("FATAL: can't create Ethernet semaphore\n");
220 cebix 1.6 return false;
221 cebix 1.1 }
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 cebix 1.6 return true;
237 cebix 1.1 }
238    
239    
240     /*
241     * Deinitialization
242     */
243    
244 cebix 1.6 void ether_exit(void)
245 cebix 1.1 {
246 cebix 1.6 // Close communications with add-on
247     for (int i=0; i<WRITE_PACKET_COUNT; i++)
248     net_buffer_ptr->write[i].cmd = IN_USE | (DEACTIVATE_SHEEP_NET << 8);
249     release_sem(write_sem);
250 cebix 1.1
251 cebix 1.6 // Quit reception thread
252     ether_thread_active = false;
253     status_t result;
254     release_sem(read_sem);
255     wait_for_thread(read_thread, &result);
256 cebix 1.1
257 cebix 1.6 delete_sem(read_sem);
258     delete_area(buffer_area);
259 cebix 1.1
260 cebix 1.6 // Remove all protocols
261     remove_all_protocols();
262 cebix 1.1 }
263    
264    
265     /*
266     * Reset
267     */
268    
269     void EtherReset(void)
270     {
271 cebix 1.2 remove_all_protocols();
272 cebix 1.1 }
273    
274    
275     /*
276     * Add multicast address
277     */
278    
279     int16 ether_add_multicast(uint32 pb)
280     {
281     net_packet *p = &net_buffer_ptr->write[wr_pos];
282     if (p->cmd & IN_USE) {
283     D(bug("WARNING: Couldn't enable multicast address\n"));
284     } else {
285 cebix 1.3 Mac2Host_memcpy(p->data, pb + eMultiAddr, 6);
286 cebix 1.1 p->length = 6;
287     p->cmd = IN_USE | (ADD_MULTICAST << 8);
288     wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
289     release_sem(write_sem);
290     }
291     return noErr;
292     }
293    
294    
295     /*
296     * Delete multicast address
297     */
298    
299     int16 ether_del_multicast(uint32 pb)
300     {
301     net_packet *p = &net_buffer_ptr->write[wr_pos];
302     if (p->cmd & IN_USE) {
303     D(bug("WARNING: Couldn't enable multicast address\n"));
304     } else {
305 cebix 1.3 Mac2Host_memcpy(p->data, pb + eMultiAddr, 6);
306 cebix 1.1 p->length = 6;
307     p->cmd = IN_USE | (REMOVE_MULTICAST << 8);
308     wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
309     release_sem(write_sem);
310     }
311     return noErr;
312     }
313    
314    
315     /*
316     * Attach protocol handler
317     */
318    
319     int16 ether_attach_ph(uint16 type, uint32 handler)
320     {
321     // Already attached?
322     NetProtocol *p = find_protocol(type);
323     if (p != NULL)
324     return lapProtErr;
325     else {
326     // No, create and attach
327     p = new NetProtocol;
328     p->type = type;
329     p->handler = handler;
330     prot_list.AddItem(p);
331     return noErr;
332     }
333     }
334    
335    
336     /*
337     * Detach protocol handler
338     */
339    
340     int16 ether_detach_ph(uint16 type)
341     {
342     NetProtocol *p = find_protocol(type);
343     if (p != NULL) {
344     prot_list.RemoveItem(p);
345     delete p;
346     return noErr;
347     } else
348     return lapProtErr;
349     }
350    
351    
352     /*
353     * Transmit raw ethernet packet
354     */
355    
356     int16 ether_write(uint32 wds)
357     {
358     net_packet *p = &net_buffer_ptr->write[wr_pos];
359     if (p->cmd & IN_USE) {
360     D(bug("WARNING: Couldn't transmit packet (buffer full)\n"));
361     } else {
362    
363     // Copy packet to buffer
364 cebix 1.6 int len = ether_wds_to_buffer(wds, p->data);
365 cebix 1.1
366     // Set source address
367 cebix 1.6 memcpy(p->data + 6, ether_addr, 6);
368 cebix 1.1
369     #if MONITOR
370     bug("Sending Ethernet packet:\n");
371 cebix 1.6 for (int i=0; i<len; i++) {
372     bug("%02x ", p->data[i]);
373 cebix 1.1 }
374     bug("\n");
375     #endif
376    
377     // Notify add-on
378 cebix 1.6 p->length = len;
379 cebix 1.1 p->cmd = IN_USE | (SHEEP_PACKET << 8);
380     wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
381     release_sem(write_sem);
382     }
383     return noErr;
384     }
385    
386    
387     /*
388     * Packet reception thread
389     */
390    
391     static status_t receive_proc(void *data)
392     {
393     while (ether_thread_active) {
394     if (net_buffer_ptr->read[rd_pos].cmd & IN_USE) {
395     D(bug(" packet received, triggering Ethernet interrupt\n"));
396     SetInterruptFlag(INTFLAG_ETHER);
397     TriggerInterrupt();
398     }
399     acquire_sem_etc(read_sem, 1, B_TIMEOUT, 25000);
400     }
401     return 0;
402     }
403    
404    
405     /*
406     * Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers
407     */
408    
409     void EtherInterrupt(void)
410     {
411     D(bug("EtherIRQ\n"));
412    
413     // Call protocol handler for received packets
414     net_packet *p = &net_buffer_ptr->read[rd_pos];
415     while (p->cmd & IN_USE) {
416     if ((p->cmd >> 8) == SHEEP_PACKET) {
417     #if MONITOR
418     bug("Receiving Ethernet packet:\n");
419     for (int i=0; i<p->length; i++) {
420     bug("%02x ", p->data[i]);
421     }
422     bug("\n");
423     #endif
424     // Get packet type
425     uint16 type = ntohs(*(uint16 *)(p->data + 12));
426    
427     // Look for protocol
428     NetProtocol *prot = find_protocol(type);
429     if (prot == NULL)
430     goto next;
431    
432     // No default handler
433     if (prot->handler == 0)
434     goto next;
435    
436     // Copy header to RHA
437 cebix 1.3 Host2Mac_memcpy(ether_data + ed_RHA, p->data, 14);
438 cebix 1.1 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)));
439    
440     // Call protocol handler
441     M68kRegisters r;
442     r.d[0] = type; // Packet type
443     r.d[1] = p->length - 14; // Remaining packet length (without header, for ReadPacket)
444     r.a[0] = (uint32)p->data + 14; // Pointer to packet (host address, for ReadPacket)
445     r.a[3] = ether_data + ed_RHA + 14; // Pointer behind header in RHA
446     r.a[4] = ether_data + ed_ReadPacket; // Pointer to ReadPacket/ReadRest routines
447     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]));
448     Execute68k(prot->handler, &r);
449     }
450     next: p->cmd = 0; // Free packet
451     rd_pos = (rd_pos + 1) % READ_PACKET_COUNT;
452     p = &net_buffer_ptr->read[rd_pos];
453     }
454     D(bug(" EtherIRQ done\n"));
455     }