ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/ether_beos.cpp
Revision: 1.1
Committed: 2002-02-04T16:58:13Z (22 years, 5 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 - SheepShaver Ethernet Device Driver (DLPI), BeOS specific stuff
3     *
4     * SheepShaver (C) 1997-2002 Marc Hellwig and Christian Bauer
5     *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include "sysdeps.h"
22     #include "ether.h"
23     #include "ether_defs.h"
24     #include "prefs.h"
25     #include "xlowmem.h"
26     #include "main.h"
27     #include "user_strings.h"
28     #include "sheep_net.h"
29    
30     #define DEBUG 0
31     #include "debug.h"
32    
33     #define STATISTICS 0
34     #define MONITOR 0
35    
36    
37     // Global variables
38     static thread_id read_thread; // Packet receiver thread
39     static bool ether_thread_active = true; // Flag for quitting the receiver thread
40    
41     static area_id buffer_area; // Packet buffer area
42     static net_buffer *net_buffer_ptr; // Pointer to packet buffer
43     static sem_id read_sem, write_sem; // Semaphores to trigger packet reading/writing
44     static uint32 rd_pos; // Current read position in packet buffer
45     static uint32 wr_pos; // Current write position in packet buffer
46    
47     static bool net_open = false; // Flag: initialization succeeded, network device open
48    
49    
50     // Prototypes
51     static status_t AO_receive_thread(void *data);
52    
53    
54     /*
55     * Initialize ethernet
56     */
57    
58     void EtherInit(void)
59     {
60     // Do nothing if the user disabled the network
61     if (PrefsFindBool("nonet"))
62     return;
63    
64     // find net-server team
65     i_wanna_try_that_again:
66     bool found_add_on = false;
67     team_info t_info;
68     int32 t_cookie = 0;
69     image_info i_info;
70     int32 i_cookie = 0;
71     while (get_next_team_info(&t_cookie, &t_info) == B_NO_ERROR) {
72     if (strstr(t_info.args,"net_server")!=NULL) {
73     // check if sheep_net add-on is loaded
74     while (get_next_image_info(t_info.team,&i_cookie,&i_info) == B_NO_ERROR) {
75     if (strstr(i_info.name,"sheep_net")!=NULL) {
76     found_add_on = true;
77     break;
78     }
79     }
80     }
81     if (found_add_on) break;
82     }
83     if (!found_add_on) {
84    
85     // Search for sheep_net in network config file
86     char str[1024];
87     bool sheep_net_found = false;
88     FILE *fin = fopen("/boot/home/config/settings/network", "r");
89     while (!feof(fin)) {
90     fgets(str, 1024, fin);
91     if (strstr(str, "PROTOCOLS"))
92     if (strstr(str, "sheep_net"))
93     sheep_net_found = true;
94     }
95     fclose(fin);
96    
97     // It was found, so something else must be wrong
98     if (sheep_net_found) {
99     WarningAlert(GetString(STR_NO_NET_ADDON_WARN));
100     return;
101     }
102    
103     // Not found, inform the user
104     if (!ChoiceAlert(GetString(STR_NET_CONFIG_MODIFY_WARN), GetString(STR_OK_BUTTON), GetString(STR_CANCEL_BUTTON)))
105     return;
106    
107     // Change the network config file and restart the network
108     fin = fopen("/boot/home/config/settings/network", "r");
109     FILE *fout = fopen("/boot/home/config/settings/network.2", "w");
110     bool global_found = false;
111     bool modified = false;
112     while (!feof(fin)) {
113     str[0] = 0;
114     fgets(str, 1024, fin);
115     if (!global_found && strstr(str, "GLOBAL:")) {
116     global_found = true;
117     } else if (global_found && !modified && strstr(str, "PROTOCOLS")) {
118     str[strlen(str)-1] = 0;
119     strcat(str, " sheep_net\n");
120     modified = true;
121     } else if (global_found && !modified && strlen(str) > 2 && str[strlen(str) - 2] == ':') {
122     fputs("\tPROTOCOLS = sheep_net\n", fout);
123     modified = true;
124     }
125     fputs(str, fout);
126     }
127     if (!modified)
128     fputs("\tPROTOCOLS = sheep_net\n", fout);
129     fclose(fout);
130     fclose(fin);
131     remove("/boot/home/config/settings/network.orig");
132     rename("/boot/home/config/settings/network", "/boot/home/config/settings/network.orig");
133     rename("/boot/home/config/settings/network.2", "/boot/home/config/settings/network");
134    
135     app_info ai;
136     if (be_roster->GetAppInfo("application/x-vnd.Be-NETS", &ai) == B_OK) {
137     BMessenger msg(NULL, ai.team);
138     if (msg.IsValid()) {
139     while (be_roster->IsRunning("application/x-vnd.Be-NETS")) {
140     msg.SendMessage(B_QUIT_REQUESTED);
141     snooze(500000);
142     }
143     }
144     }
145     BPath path;
146     find_directory(B_BEOS_BOOT_DIRECTORY, &path);
147     path.Append("Netscript");
148     char *argv[3] = {"/bin/sh", (char *)path.Path(), NULL};
149     thread_id net_server = load_image(2, argv, environ);
150     resume_thread(net_server);
151     status_t l;
152     wait_for_thread(net_server, &l);
153     goto i_wanna_try_that_again;
154     }
155    
156     // Set up communications with add-on
157     area_id handler_buffer;
158     if ((handler_buffer = find_area("packet buffer")) < B_NO_ERROR) {
159     WarningAlert(GetString(STR_NET_ADDON_INIT_FAILED));
160     return;
161     }
162     if ((buffer_area = clone_area("local packet buffer", &net_buffer_ptr, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, handler_buffer)) < B_NO_ERROR) {
163     D(bug("EtherInit: couldn't clone packet area\n"));
164     WarningAlert(GetString(STR_NET_ADDON_CLONE_FAILED));
165     return;
166     }
167     if ((read_sem = create_sem(0, "ether read")) < B_NO_ERROR) {
168     printf("FATAL: can't create Ethernet semaphore\n");
169     return;
170     }
171     net_buffer_ptr->read_sem = read_sem;
172     write_sem = net_buffer_ptr->write_sem;
173     read_thread = spawn_thread(AO_receive_thread, "ether read", B_URGENT_DISPLAY_PRIORITY, NULL);
174     resume_thread(read_thread);
175     for (int i=0; i<WRITE_PACKET_COUNT; i++)
176     net_buffer_ptr->write[i].cmd = IN_USE | (ACTIVATE_SHEEP_NET << 8);
177     rd_pos = wr_pos = 0;
178     release_sem(write_sem);
179    
180     // Everything OK
181     net_open = true;
182     }
183    
184    
185     /*
186     * Exit ethernet
187     */
188    
189     void EtherExit(void)
190     {
191     if (net_open) {
192    
193     // Close communications with add-on
194     for (int i=0; i<WRITE_PACKET_COUNT; i++)
195     net_buffer_ptr->write[i].cmd = IN_USE | (DEACTIVATE_SHEEP_NET << 8);
196     release_sem(write_sem);
197    
198     // Quit receiver thread
199     ether_thread_active = false;
200     status_t result;
201     release_sem(read_sem);
202     while (wait_for_thread(read_thread, &result) == B_INTERRUPTED) ;
203    
204     delete_sem(read_sem);
205     delete_area(buffer_area);
206     }
207    
208     #if STATISTICS
209     // Show statistics
210     printf("%ld messages put on write queue\n", num_wput);
211     printf("%ld error acks\n", num_error_acks);
212     printf("%ld packets transmitted (%ld raw, %ld normal)\n", num_tx_packets, num_tx_raw_packets, num_tx_normal_packets);
213     printf("%ld tx packets dropped because buffer full\n", num_tx_buffer_full);
214     printf("%ld packets received\n", num_rx_packets);
215     printf("%ld packets passed upstream (%ld Fast Path, %ld normal)\n", num_rx_fastpath + num_unitdata_ind, num_rx_fastpath, num_unitdata_ind);
216     printf("EtherIRQ called %ld times\n", num_ether_irq);
217     printf("%ld rx packets dropped due to low memory\n", num_rx_no_mem);
218     printf("%ld rx packets dropped because no stream found\n", num_rx_dropped);
219     printf("%ld rx packets dropped because stream not ready\n", num_rx_stream_not_ready);
220     printf("%ld rx packets dropped because no memory for unitdata_ind\n", num_rx_no_unitdata_mem);
221     #endif
222     }
223    
224    
225     /*
226     * Ask add-on for ethernet hardware address
227     */
228    
229     void AO_get_ethernet_address(uint8 *addr)
230     {
231     if (net_open) {
232     OTCopy48BitAddress(net_buffer_ptr->ether_addr, addr);
233     } else {
234     addr[0] = 0x12;
235     addr[1] = 0x34;
236     addr[2] = 0x56;
237     addr[3] = 0x78;
238     addr[4] = 0x9a;
239     addr[5] = 0xbc;
240     }
241     D(bug("AO_get_ethernet_address: got address %02x%02x%02x%02x%02x%02x\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]));
242     }
243    
244    
245     /*
246     * Tell add-on to enable multicast address
247     */
248    
249     void AO_enable_multicast(uint8 *addr)
250     {
251     D(bug("AO_enable_multicast\n"));
252     if (net_open) {
253     net_packet *p = &net_buffer_ptr->write[wr_pos];
254     if (p->cmd & IN_USE) {
255     D(bug("WARNING: couldn't enable multicast address\n"));
256     } else {
257     memcpy(p->data, addr, 6);
258     p->length = 6;
259     p->cmd = IN_USE | (ADD_MULTICAST << 8);
260     wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
261     release_sem(write_sem);
262     }
263     }
264     }
265    
266    
267     /*
268     * Tell add-on to disable multicast address
269     */
270    
271     void AO_disable_multicast(uint8 *addr)
272     {
273     D(bug("AO_disable_multicast\n"));
274     if (net_open) {
275     net_packet *p = &net_buffer_ptr->write[wr_pos];
276     if (p->cmd & IN_USE) {
277     D(bug("WARNING: couldn't enable multicast address\n"));
278     } else {
279     memcpy(p->data, addr, 6);
280     p->length = 6;
281     p->cmd = IN_USE | (REMOVE_MULTICAST << 8);
282     wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
283     release_sem(write_sem);
284     }
285     D(bug("WARNING: couldn't disable multicast address\n"));
286     }
287     }
288    
289    
290     /*
291     * Tell add-on to transmit one packet
292     */
293    
294     void AO_transmit_packet(mblk_t *mp)
295     {
296     D(bug("AO_transmit_packet\n"));
297     if (net_open) {
298     net_packet *p = &net_buffer_ptr->write[wr_pos];
299     if (p->cmd & IN_USE) {
300     D(bug("WARNING: couldn't transmit packet (buffer full)\n"));
301     num_tx_buffer_full++;
302     } else {
303     D(bug(" write packet pos %d\n", i));
304     num_tx_packets++;
305    
306     // Copy packet to buffer
307     uint8 *start;
308     uint8 *bp = start = p->data;
309     while (mp) {
310     uint32 size = mp->b_wptr - mp->b_rptr;
311     memcpy(bp, mp->b_rptr, size);
312     bp += size;
313     mp = mp->b_cont;
314     }
315    
316     #if MONITOR
317     bug("Sending Ethernet packet:\n");
318     for (int i=0; i<(uint32)(bp - start); i++) {
319     bug("%02lx ", start[i]);
320     }
321     bug("\n");
322     #endif
323    
324     // Notify add-on
325     p->length = (uint32)(bp - start);
326     p->cmd = IN_USE | (SHEEP_PACKET << 8);
327     wr_pos = (wr_pos + 1) % WRITE_PACKET_COUNT;
328     release_sem(write_sem);
329     }
330     }
331     }
332    
333    
334     /*
335     * Packet reception thread
336     */
337    
338     static status_t AO_receive_thread(void *data)
339     {
340     while (ether_thread_active) {
341     if (net_buffer_ptr->read[rd_pos].cmd & IN_USE) {
342     if (ether_driver_opened) {
343     D(bug(" packet received, triggering Ethernet interrupt\n"));
344     SetInterruptFlag(INTFLAG_ETHER);
345     TriggerInterrupt();
346     }
347     }
348     acquire_sem_etc(read_sem, 1, B_TIMEOUT, 25000);
349     }
350     return 0;
351     }
352    
353    
354     /*
355     * Ethernet interrupt
356     */
357    
358     void EtherIRQ(void)
359     {
360     D(bug("EtherIRQ\n"));
361     num_ether_irq++;
362     OTEnterInterrupt();
363    
364     // Send received packets to OpenTransport
365     net_packet *p = &net_buffer_ptr->read[rd_pos];
366     while (p->cmd & IN_USE) {
367     if ((p->cmd >> 8) == SHEEP_PACKET) {
368     num_rx_packets++;
369     D(bug(" read packet pos %d\n", i));
370     uint32 size = p->length;
371    
372     #if MONITOR
373     bug("Receiving Ethernet packet:\n");
374     for (int i=0; i<size; i++) {
375     bug("%02lx ", p->data[i]);
376     }
377     bug("\n");
378     #endif
379    
380     // Wrap packet in message block
381     //!! maybe use esballoc()
382     mblk_t *mp;
383     if ((mp = allocb(size, 0)) != NULL) {
384     D(bug(" packet data at %p\n", mp->b_rptr));
385     memcpy(mp->b_rptr, p->data, size);
386     mp->b_wptr += size;
387     ether_packet_received(mp);
388     } else {
389     D(bug("WARNING: Cannot allocate mblk for received packet\n"));
390     num_rx_no_mem++;
391     }
392     }
393     p->cmd = 0; // Free packet
394     rd_pos = (rd_pos + 1) % READ_PACKET_COUNT;
395     p = &net_buffer_ptr->read[rd_pos];
396     }
397     OTLeaveInterrupt();
398     }