ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/BeOS/ether_beos.cpp
Revision: 1.8
Committed: 2001-07-13T18:49:28Z (22 years, 10 months ago) by cebix
Branch: MAIN
Changes since 1.7: +0 -3 lines
Log Message:
- outgoing packet source address is set in ether.cpp
- UDP tunnelling sends packets to Ethernet broadcast address as IP broadcasts

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 cebix 1.7 void ether_reset(void)
270 cebix 1.1 {
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     #if MONITOR
367     bug("Sending Ethernet packet:\n");
368 cebix 1.6 for (int i=0; i<len; i++) {
369     bug("%02x ", p->data[i]);
370 cebix 1.1 }
371     bug("\n");
372     #endif
373    
374     // Notify add-on
375 cebix 1.6 p->length = len;
376 cebix 1.1 p->cmd = IN_USE | (SHEEP_PACKET << 8);
377     wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
378     release_sem(write_sem);
379     }
380     return noErr;
381     }
382    
383    
384     /*
385     * Packet reception thread
386     */
387    
388     static status_t receive_proc(void *data)
389     {
390     while (ether_thread_active) {
391     if (net_buffer_ptr->read[rd_pos].cmd & IN_USE) {
392     D(bug(" packet received, triggering Ethernet interrupt\n"));
393     SetInterruptFlag(INTFLAG_ETHER);
394     TriggerInterrupt();
395     }
396     acquire_sem_etc(read_sem, 1, B_TIMEOUT, 25000);
397     }
398     return 0;
399     }
400    
401    
402     /*
403     * Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers
404     */
405    
406     void EtherInterrupt(void)
407     {
408     D(bug("EtherIRQ\n"));
409    
410     // Call protocol handler for received packets
411     net_packet *p = &net_buffer_ptr->read[rd_pos];
412     while (p->cmd & IN_USE) {
413     if ((p->cmd >> 8) == SHEEP_PACKET) {
414     #if MONITOR
415     bug("Receiving Ethernet packet:\n");
416     for (int i=0; i<p->length; i++) {
417     bug("%02x ", p->data[i]);
418     }
419     bug("\n");
420     #endif
421     // Get packet type
422     uint16 type = ntohs(*(uint16 *)(p->data + 12));
423    
424     // Look for protocol
425     NetProtocol *prot = find_protocol(type);
426     if (prot == NULL)
427     goto next;
428    
429     // No default handler
430     if (prot->handler == 0)
431     goto next;
432    
433     // Copy header to RHA
434 cebix 1.3 Host2Mac_memcpy(ether_data + ed_RHA, p->data, 14);
435 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)));
436    
437     // Call protocol handler
438     M68kRegisters r;
439     r.d[0] = type; // Packet type
440     r.d[1] = p->length - 14; // Remaining packet length (without header, for ReadPacket)
441     r.a[0] = (uint32)p->data + 14; // Pointer to packet (host address, for ReadPacket)
442     r.a[3] = ether_data + ed_RHA + 14; // Pointer behind header in RHA
443     r.a[4] = ether_data + ed_ReadPacket; // Pointer to ReadPacket/ReadRest routines
444     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]));
445     Execute68k(prot->handler, &r);
446     }
447     next: p->cmd = 0; // Free packet
448     rd_pos = (rd_pos + 1) % READ_PACKET_COUNT;
449     p = &net_buffer_ptr->read[rd_pos];
450     }
451     D(bug(" EtherIRQ done\n"));
452     }