ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/BeOS/ether_beos.cpp
Revision: 1.12
Committed: 2005-01-30T21:42:13Z (19 years, 3 months ago) by gbeauche
Branch: MAIN
Changes since 1.11: +1 -1 lines
Log Message:
Happy New Year!

File Contents

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