ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/BeOS/ether_beos.cpp
Revision: 1.1
Committed: 1999-10-03T14:16:25Z (24 years, 9 months ago) by cebix
Branch: MAIN
Branch point for: cebix
Log Message:
Initial revision

File Contents

# User Rev Content
1 cebix 1.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     * Initialization
94     */
95    
96     void EtherInit(void)
97     {
98     // Do nothing if no Ethernet device specified
99     if (PrefsFindString("ether") == NULL)
100     return;
101    
102     // Find net_server team
103     i_wanna_try_that_again:
104     bool found_add_on = false;
105     team_info t_info;
106     int32 t_cookie = 0;
107     image_info i_info;
108     int32 i_cookie = 0;
109     while (get_next_team_info(&t_cookie, &t_info) == B_NO_ERROR) {
110     if (strstr(t_info.args,"net_server")!=NULL) {
111    
112     // Check if sheep_net add-on is loaded
113     while (get_next_image_info(t_info.team, &i_cookie, &i_info) == B_NO_ERROR) {
114     if (strstr(i_info.name, "sheep_net") != NULL) {
115     found_add_on = true;
116     break;
117     }
118     }
119     }
120     if (found_add_on) break;
121     }
122     if (!found_add_on) {
123    
124     // Search for sheep_net in network config file
125     char str[1024];
126     bool sheep_net_found = false;
127     FILE *fin = fopen("/boot/home/config/settings/network", "r");
128     while (!feof(fin)) {
129     fgets(str, 1024, fin);
130     if (strstr(str, "PROTOCOLS"))
131     if (strstr(str, "sheep_net"))
132     sheep_net_found = true;
133     }
134     fclose(fin);
135    
136     // It was found, so something else must be wrong
137     if (sheep_net_found) {
138     WarningAlert(GetString(STR_NO_NET_ADDON_WARN));
139     return;
140     }
141    
142     // Not found, inform the user
143     if (!ChoiceAlert(GetString(STR_NET_CONFIG_MODIFY_WARN), GetString(STR_OK_BUTTON), GetString(STR_CANCEL_BUTTON)))
144     return;
145    
146     // Change the network config file and restart the network
147     fin = fopen("/boot/home/config/settings/network", "r");
148     FILE *fout = fopen("/boot/home/config/settings/network.2", "w");
149     bool global_found = false;
150     bool modified = false;
151     while (!feof(fin)) {
152     str[0] = 0;
153     fgets(str, 1024, fin);
154     if (!global_found && strstr(str, "GLOBAL:")) {
155     global_found = true;
156     } else if (global_found && !modified && strstr(str, "PROTOCOLS")) {
157     str[strlen(str)-1] = 0;
158     strcat(str, " sheep_net\n");
159     modified = true;
160     } else if (global_found && !modified && strlen(str) > 2 && str[strlen(str) - 2] == ':') {
161     fputs("\tPROTOCOLS = sheep_net\n", fout);
162     modified = true;
163     }
164     fputs(str, fout);
165     }
166     if (!modified)
167     fputs("\tPROTOCOLS = sheep_net\n", fout);
168     fclose(fout);
169     fclose(fin);
170     remove("/boot/home/config/settings/network.orig");
171     rename("/boot/home/config/settings/network", "/boot/home/config/settings/network.orig");
172     rename("/boot/home/config/settings/network.2", "/boot/home/config/settings/network");
173    
174     app_info ai;
175     if (be_roster->GetAppInfo("application/x-vnd.Be-NETS", &ai) == B_OK) {
176     BMessenger msg(NULL, ai.team);
177     if (msg.IsValid()) {
178     while (be_roster->IsRunning("application/x-vnd.Be-NETS")) {
179     msg.SendMessage(B_QUIT_REQUESTED);
180     snooze(500000);
181     }
182     }
183     }
184     BPath path;
185     find_directory(B_BEOS_BOOT_DIRECTORY, &path);
186     path.Append("Netscript");
187     const char *argv[3] = {"/bin/sh", path.Path(), NULL};
188     thread_id net_server = load_image(2, argv, (const char **)environ);
189     resume_thread(net_server);
190     status_t l;
191     wait_for_thread(net_server, &l);
192     goto i_wanna_try_that_again;
193     }
194    
195     // Set up communications with add-on
196     area_id handler_buffer;
197     if ((handler_buffer = find_area("packet buffer")) < B_NO_ERROR) {
198     WarningAlert(GetString(STR_NET_ADDON_INIT_FAILED));
199     return;
200     }
201     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) {
202     D(bug("EtherInit: couldn't clone packet area\n"));
203     WarningAlert(GetString(STR_NET_ADDON_CLONE_FAILED));
204     return;
205     }
206     if ((read_sem = create_sem(0, "ether read")) < B_NO_ERROR) {
207     printf("FATAL: can't create Ethernet semaphore\n");
208     return;
209     }
210     net_buffer_ptr->read_sem = read_sem;
211     write_sem = net_buffer_ptr->write_sem;
212     read_thread = spawn_thread(receive_proc, "Ethernet Receiver", B_URGENT_DISPLAY_PRIORITY, NULL);
213     resume_thread(read_thread);
214     for (int i=0; i<WRITE_PACKET_COUNT; i++)
215     net_buffer_ptr->write[i].cmd = IN_USE | (ACTIVATE_SHEEP_NET << 8);
216     rd_pos = wr_pos = 0;
217     release_sem(write_sem);
218    
219     // Get Ethernet address
220     memcpy(ether_addr, net_buffer_ptr->ether_addr, 6);
221     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]));
222    
223     // Everything OK
224     net_open = true;
225     }
226    
227    
228     /*
229     * Deinitialization
230     */
231    
232     void EtherExit(void)
233     {
234     if (net_open) {
235    
236     // Close communications with add-on
237     for (int i=0; i<WRITE_PACKET_COUNT; i++)
238     net_buffer_ptr->write[i].cmd = IN_USE | (DEACTIVATE_SHEEP_NET << 8);
239     release_sem(write_sem);
240    
241     // Quit reception thread
242     ether_thread_active = false;
243     status_t result;
244     release_sem(read_sem);
245     wait_for_thread(read_thread, &result);
246    
247     delete_sem(read_sem);
248     delete_area(buffer_area);
249    
250     // Remove all protocols
251     NetProtocol *p;
252     while ((p = (NetProtocol *)prot_list.RemoveItem((long)0)) != NULL)
253     delete p;
254     }
255     }
256    
257    
258     /*
259     * Reset
260     */
261    
262     void EtherReset(void)
263     {
264     // Remove all protocols
265     NetProtocol *p;
266     while ((p = (NetProtocol *)prot_list.RemoveItem((long)0)) != NULL)
267     delete p;
268     }
269    
270    
271     /*
272     * Add multicast address
273     */
274    
275     int16 ether_add_multicast(uint32 pb)
276     {
277     uint8 *addr = Mac2HostAddr(pb + eMultiAddr);
278     net_packet *p = &net_buffer_ptr->write[wr_pos];
279     if (p->cmd & IN_USE) {
280     D(bug("WARNING: Couldn't enable multicast address\n"));
281     } else {
282     memcpy(p->data, addr, 6);
283     p->length = 6;
284     p->cmd = IN_USE | (ADD_MULTICAST << 8);
285     wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
286     release_sem(write_sem);
287     }
288     return noErr;
289     }
290    
291    
292     /*
293     * Delete multicast address
294     */
295    
296     int16 ether_del_multicast(uint32 pb)
297     {
298     uint8 *addr = Mac2HostAddr(pb + eMultiAddr);
299     net_packet *p = &net_buffer_ptr->write[wr_pos];
300     if (p->cmd & IN_USE) {
301     D(bug("WARNING: Couldn't enable multicast address\n"));
302     } else {
303     memcpy(p->data, addr, 6);
304     p->length = 6;
305     p->cmd = IN_USE | (REMOVE_MULTICAST << 8);
306     wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
307     release_sem(write_sem);
308     }
309     return noErr;
310     }
311    
312    
313     /*
314     * Attach protocol handler
315     */
316    
317     int16 ether_attach_ph(uint16 type, uint32 handler)
318     {
319     // Already attached?
320     NetProtocol *p = find_protocol(type);
321     if (p != NULL)
322     return lapProtErr;
323     else {
324     // No, create and attach
325     p = new NetProtocol;
326     p->type = type;
327     p->handler = handler;
328     prot_list.AddItem(p);
329     return noErr;
330     }
331     }
332    
333    
334     /*
335     * Detach protocol handler
336     */
337    
338     int16 ether_detach_ph(uint16 type)
339     {
340     NetProtocol *p = find_protocol(type);
341     if (p != NULL) {
342     prot_list.RemoveItem(p);
343     delete p;
344     return noErr;
345     } else
346     return lapProtErr;
347     }
348    
349    
350     /*
351     * Transmit raw ethernet packet
352     */
353    
354     int16 ether_write(uint32 wds)
355     {
356     net_packet *p = &net_buffer_ptr->write[wr_pos];
357     if (p->cmd & IN_USE) {
358     D(bug("WARNING: Couldn't transmit packet (buffer full)\n"));
359     } else {
360    
361     // Copy packet to buffer
362     uint8 *start;
363     uint8 *bp = start = p->data;
364     for (;;) {
365     int len = ReadMacInt16(wds);
366     if (len == 0)
367     break;
368     memcpy(bp, Mac2HostAddr(ReadMacInt32(wds + 2)), len);
369     bp += len;
370     wds += 6;
371     }
372    
373     // Set source address
374     memcpy(start + 6, ether_addr, 6);
375    
376     #if MONITOR
377     bug("Sending Ethernet packet:\n");
378     for (int i=0; i<(uint32)(bp-start); i++) {
379     bug("%02x ", start[i]);
380     }
381     bug("\n");
382     #endif
383    
384     // Notify add-on
385     p->length = (uint32)(bp - start);
386     p->cmd = IN_USE | (SHEEP_PACKET << 8);
387     wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
388     release_sem(write_sem);
389     }
390     return noErr;
391     }
392    
393    
394     /*
395     * Packet reception thread
396     */
397    
398     static status_t receive_proc(void *data)
399     {
400     while (ether_thread_active) {
401     if (net_buffer_ptr->read[rd_pos].cmd & IN_USE) {
402     D(bug(" packet received, triggering Ethernet interrupt\n"));
403     SetInterruptFlag(INTFLAG_ETHER);
404     TriggerInterrupt();
405     }
406     acquire_sem_etc(read_sem, 1, B_TIMEOUT, 25000);
407     }
408     return 0;
409     }
410    
411    
412     /*
413     * Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers
414     */
415    
416     void EtherInterrupt(void)
417     {
418     D(bug("EtherIRQ\n"));
419    
420     // Call protocol handler for received packets
421     net_packet *p = &net_buffer_ptr->read[rd_pos];
422     while (p->cmd & IN_USE) {
423     if ((p->cmd >> 8) == SHEEP_PACKET) {
424     #if MONITOR
425     bug("Receiving Ethernet packet:\n");
426     for (int i=0; i<p->length; i++) {
427     bug("%02x ", p->data[i]);
428     }
429     bug("\n");
430     #endif
431     // Get packet type
432     uint16 type = ntohs(*(uint16 *)(p->data + 12));
433    
434     // Look for protocol
435     NetProtocol *prot = find_protocol(type);
436     if (prot == NULL)
437     goto next;
438    
439     // No default handler
440     if (prot->handler == 0)
441     goto next;
442    
443     // Copy header to RHA
444     memcpy(Mac2HostAddr(ether_data + ed_RHA), p->data, 14);
445     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)));
446    
447     // Call protocol handler
448     M68kRegisters r;
449     r.d[0] = type; // Packet type
450     r.d[1] = p->length - 14; // Remaining packet length (without header, for ReadPacket)
451     r.a[0] = (uint32)p->data + 14; // Pointer to packet (host address, for ReadPacket)
452     r.a[3] = ether_data + ed_RHA + 14; // Pointer behind header in RHA
453     r.a[4] = ether_data + ed_ReadPacket; // Pointer to ReadPacket/ReadRest routines
454     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]));
455     Execute68k(prot->handler, &r);
456     }
457     next: p->cmd = 0; // Free packet
458     rd_pos = (rd_pos + 1) % READ_PACKET_COUNT;
459     p = &net_buffer_ptr->read[rd_pos];
460     }
461     D(bug(" EtherIRQ done\n"));
462     }