ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/ether.cpp
Revision: 1.10
Committed: 2008-01-01T09:47:38Z (16 years, 4 months ago) by gbeauche
Branch: MAIN
CVS Tags: HEAD
Changes since 1.9: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * ether.cpp - SheepShaver Ethernet Device Driver (DLPI)
3     *
4 gbeauche 1.10 * SheepShaver (C) 1997-2008 Marc Hellwig and Christian Bauer
5 cebix 1.1 *
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     /*
22     * TODO
23     * - 802.2 TEST/XID
24     * - MIB statistics
25     */
26    
27     #include <string.h>
28    
29     #include "sysdeps.h"
30 gbeauche 1.8 #include "cpu_emulation.h"
31 cebix 1.1 #include "ether.h"
32     #include "ether_defs.h"
33     #include "macos_util.h"
34    
35     #define DEBUG 0
36     #include "debug.h"
37    
38     // Packet types
39     enum {
40     kPktDIX = 0,
41     kPkt8022SAP = 1,
42     kPkt8022GroupSAP = 2,
43     kPkt8022SNAP = 3,
44     kPktIPX = 4,
45     kPktUnknown = 5
46     };
47    
48    
49     /*
50     * Stream private data structure
51     */
52    
53     static const int kGroupSAPMapSize = 128/32; // Number of 32-bit values we need for 128 bits
54     static const int kGSshift = 6;
55     static const int kGSmask = 0x1F;
56    
57     struct multicast_node {
58 gbeauche 1.3 nw_multicast_node_p next;
59 cebix 1.1 uint8 addr[kEnetPhysicalAddressLength];
60     };
61    
62     struct DLPIStream {
63     void SetGroupSAP(uint8 sap)
64     {
65     group_sap[sap >> kGSshift] |= (1L << ((sap >> 1) & kGSmask));
66     }
67    
68     void ClearGroupSAP(uint8 sap)
69     {
70     group_sap[sap >> kGSshift] &= ~(1L << ((sap >> 1) & kGSmask));
71     }
72    
73     void ClearAllGroupSAPs(void)
74     {
75     for (int i=0; i<kGroupSAPMapSize; i++)
76     group_sap[i] = 0;
77     }
78    
79     bool TestGroupSAP(uint8 sap)
80     {
81     return group_sap[sap >> kGSshift] & (1L << ((sap >> 1) & kGSmask));
82     }
83    
84     void AddMulticast(uint8 *addr)
85     {
86 gbeauche 1.6 multicast_node *n = (multicast_node *)Mac2HostAddr(Mac_sysalloc(sizeof(multicast_node)));
87 cebix 1.1 memcpy(n->addr, addr, kEnetPhysicalAddressLength);
88     n->next = multicast_list;
89     multicast_list = n;
90     }
91    
92     void RemoveMulticast(uint8 *addr)
93     {
94     multicast_node *p = multicast_list;
95     while (p) {
96     if (memcmp(addr, p->addr, kEnetPhysicalAddressLength) == 0)
97     goto found;
98     p = p->next;
99     }
100     return;
101     found:
102     multicast_node *q = (multicast_node *)&multicast_list;
103     while (q) {
104     if (q->next == p) {
105     q->next = p->next;
106 gbeauche 1.6 Mac_sysfree(Host2MacAddr((uint8 *)p));
107 cebix 1.1 return;
108     }
109     q = q->next;
110     }
111     }
112    
113     uint8 *IsMulticastRegistered(uint8 *addr)
114     {
115     multicast_node *n = multicast_list;
116     while (n) {
117     if (memcmp(addr, n->addr, kEnetPhysicalAddressLength) == 0)
118     return n->addr;
119     n = n->next;
120     }
121     return NULL;
122     }
123    
124 gbeauche 1.3 nw_uint32 minor_num; // Minor device number of this stream
125     nw_uint32 dlpi_state; // DLPI state of this stream
126     nw_uint32 flags; // Flags
127     nw_uint16 dlsap; // SAP bound to this stream
128     nw_bool framing_8022; // Using 802.2 framing? This is only used to report the MAC type for DL_INFO_ACK and can be set with an ioctl() call
129     nw_queue_p rdq; // Read queue for this stream
130     nw_uint32 group_sap[kGroupSAPMapSize]; // Map of bound group SAPs
131     uint8 snap[k8022SNAPLength]; // SNAP bound to this stream
132     nw_multicast_node_p multicast_list; // List of enabled multicast addresses
133     };
134    
135     // Hack to make DLPIStream list initialization early to NULL (do we really need this?)
136     struct DLPIStreamInit {
137     DLPIStreamInit(nw_DLPIStream_p *dlpi_stream_p) { *dlpi_stream_p = NULL; }
138 cebix 1.1 };
139    
140     // Stream flags
141     enum {
142     kSnapStream = 0x00000001,
143     kAcceptMulticasts = 0x00000002,
144     kAcceptAll8022Packets = 0x00000004,
145     kFastPathMode = 0x00000008
146     };
147    
148     // List of opened streams (used internally by OpenTransport)
149 gbeauche 1.3 static nw_DLPIStream_p dlpi_stream_list;
150     static DLPIStreamInit dlpi_stream_init(&dlpi_stream_list);
151 cebix 1.1
152     // Are we open?
153     bool ether_driver_opened = false;
154    
155     // Our ethernet hardware address
156     static uint8 hardware_address[6] = {0, 0, 0, 0, 0, 0};
157    
158     // Statistics
159     int32 num_wput = 0;
160     int32 num_error_acks = 0;
161     int32 num_tx_packets = 0;
162     int32 num_tx_raw_packets = 0;
163     int32 num_tx_normal_packets = 0;
164     int32 num_tx_buffer_full = 0;
165     int32 num_rx_packets = 0;
166     int32 num_ether_irq = 0;
167     int32 num_unitdata_ind = 0;
168     int32 num_rx_fastpath = 0;
169     int32 num_rx_no_mem = 0;
170     int32 num_rx_dropped = 0;
171     int32 num_rx_stream_not_ready = 0;
172     int32 num_rx_no_unitdata_mem = 0;
173    
174    
175     // Function pointers of imported functions
176     typedef mblk_t *(*allocb_ptr)(size_t size, int pri);
177     static uint32 allocb_tvect = 0;
178     mblk_t *allocb(size_t arg1, int arg2)
179     {
180 gbeauche 1.9 return (mblk_t *)Mac2HostAddr((uint32)CallMacOS2(allocb_ptr, allocb_tvect, arg1, arg2));
181 cebix 1.1 }
182     typedef void (*freeb_ptr)(mblk_t *);
183     static uint32 freeb_tvect = 0;
184     static inline void freeb(mblk_t *arg1)
185     {
186     CallMacOS1(freeb_ptr, freeb_tvect, arg1);
187     }
188     typedef int16 (*freemsg_ptr)(mblk_t *);
189     static uint32 freemsg_tvect = 0;
190     static inline int16 freemsg(mblk_t *arg1)
191     {
192     return (int16)CallMacOS1(freemsg_ptr, freemsg_tvect, arg1);
193     }
194     typedef mblk_t *(*copyb_ptr)(mblk_t *);
195     static uint32 copyb_tvect = 0;
196     static inline mblk_t *copyb(mblk_t *arg1)
197     {
198 gbeauche 1.9 return (mblk_t *)Mac2HostAddr((uint32)CallMacOS1(copyb_ptr, copyb_tvect, arg1));
199 cebix 1.1 }
200     typedef mblk_t *(*dupmsg_ptr)(mblk_t *);
201     static uint32 dupmsg_tvect = 0;
202     static inline mblk_t *dupmsg(mblk_t *arg1)
203     {
204 gbeauche 1.9 return (mblk_t *)Mac2HostAddr((uint32)CallMacOS1(dupmsg_ptr, dupmsg_tvect, arg1));
205 cebix 1.1 }
206     typedef mblk_t *(*getq_ptr)(queue_t *);
207     static uint32 getq_tvect = 0;
208     static inline mblk_t *getq(queue_t *arg1)
209     {
210 gbeauche 1.9 return (mblk_t *)Mac2HostAddr((uint32)CallMacOS1(getq_ptr, getq_tvect, arg1));
211 cebix 1.1 }
212     typedef int (*putq_ptr)(queue_t *, mblk_t *);
213     static uint32 putq_tvect = 0;
214     static inline int putq(queue_t *arg1, mblk_t *arg2)
215     {
216     return (int)CallMacOS2(putq_ptr, putq_tvect, arg1, arg2);
217     }
218     typedef int (*putnext_ptr)(queue_t *, mblk_t *);
219     static uint32 putnext_tvect = 0;
220     static inline int putnext(queue_t *arg1, mblk_t *arg2)
221     {
222     return (int)CallMacOS2(putnext_ptr, putnext_tvect, arg1, arg2);
223     }
224     typedef int (*putnextctl1_ptr)(queue_t *, int type, int c);
225     static uint32 putnextctl1_tvect = 0;
226     static inline int putnextctl1(queue_t *arg1, int arg2, int arg3)
227     {
228     return (int)CallMacOS3(putnextctl1_ptr, putnextctl1_tvect, arg1, arg2, arg3);
229     }
230     typedef int (*canputnext_ptr)(queue_t *);
231     static uint32 canputnext_tvect = 0;
232     static inline int canputnext(queue_t *arg1)
233     {
234     return (int)CallMacOS1(canputnext_ptr, canputnext_tvect, arg1);
235     }
236     typedef int (*qreply_ptr)(queue_t *, mblk_t *);
237     static uint32 qreply_tvect = 0;
238     static inline int qreply(queue_t *arg1, mblk_t *arg2)
239     {
240     return (int)CallMacOS2(qreply_ptr, qreply_tvect, arg1, arg2);
241     }
242     typedef void (*flushq_ptr)(queue_t *, int flag);
243     static uint32 flushq_tvect = 0;
244     static inline void flushq(queue_t *arg1, int arg2)
245     {
246     CallMacOS2(flushq_ptr, flushq_tvect, arg1, arg2);
247     }
248     typedef int (*msgdsize_ptr)(const mblk_t *);
249     static uint32 msgdsize_tvect = 0;
250     static inline int msgdsize(const mblk_t *arg1)
251     {
252     return (int)CallMacOS1(msgdsize_ptr, msgdsize_tvect, arg1);
253     }
254     typedef void (*otenterint_ptr)(void);
255     static uint32 otenterint_tvect = 0;
256     void OTEnterInterrupt(void)
257     {
258     CallMacOS(otenterint_ptr, otenterint_tvect);
259     }
260     typedef void (*otleaveint_ptr)(void);
261     static uint32 otleaveint_tvect = 0;
262     void OTLeaveInterrupt(void)
263     {
264     CallMacOS(otleaveint_ptr, otleaveint_tvect);
265     }
266     typedef int (*mi_open_comm_ptr)(DLPIStream **mi_opp_orig, size_t size, queue_t *q, void *dev, int flag, int sflag, void *credp);
267     static uint32 mi_open_comm_tvect = 0;
268     static inline int mi_open_comm(DLPIStream **arg1, size_t arg2, queue_t *arg3, void *arg4, int arg5, int arg6, void *arg7)
269     {
270     return (int)CallMacOS7(mi_open_comm_ptr, mi_open_comm_tvect, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
271     }
272     typedef int (*mi_close_comm_ptr)(DLPIStream **mi_opp_orig, queue_t *q);
273     static uint32 mi_close_comm_tvect = 0;
274     static inline int mi_close_comm(DLPIStream **arg1, queue_t *arg2)
275     {
276     return (int)CallMacOS2(mi_close_comm_ptr, mi_close_comm_tvect, arg1, arg2);
277     }
278     typedef DLPIStream *(*mi_next_ptr_ptr)(DLPIStream *);
279     static uint32 mi_next_ptr_tvect = 0;
280     static inline DLPIStream *mi_next_ptr(DLPIStream *arg1)
281     {
282 gbeauche 1.9 return (DLPIStream *)Mac2HostAddr((uint32)CallMacOS1(mi_next_ptr_ptr, mi_next_ptr_tvect, arg1));
283 cebix 1.1 }
284 gbeauche 1.9 #ifdef USE_ETHER_FULL_DRIVER
285     typedef void (*ether_dispatch_packet_ptr)(uint32 p, uint32 size);
286     static uint32 ether_dispatch_packet_tvect = 0;
287     #endif
288 cebix 1.1
289     // Prototypes
290     static void ether_ioctl(DLPIStream *the_stream, queue_t* q, mblk_t* mp);
291     static void ether_flush(queue_t* q, mblk_t* mp);
292     static mblk_t *build_tx_packet_header(DLPIStream *the_stream, mblk_t *mp, bool fast_path);
293     static void transmit_packet(mblk_t *mp);
294     static void DLPI_error_ack(DLPIStream *the_stream, queue_t *q, mblk_t *ack_mp, uint32 prim, uint32 err, uint32 uerr);
295     static void DLPI_ok_ack(DLPIStream *the_stream, queue_t *q, mblk_t *ack_mp, uint32 prim);
296     static void DLPI_info(DLPIStream *the_stream, queue_t *q, mblk_t *mp);
297     static void DLPI_phys_addr(DLPIStream *the_stream, queue_t *q, mblk_t *mp);
298     static void DLPI_bind(DLPIStream *the_stream, queue_t *q, mblk_t *mp);
299     static void DLPI_unbind(DLPIStream *the_stream, queue_t *q, mblk_t *mp);
300     static void DLPI_subs_bind(DLPIStream *the_stream, queue_t *q, mblk_t *mp);
301     static void DLPI_subs_unbind(DLPIStream *the_stream, queue_t *q, mblk_t *mp);
302     static void DLPI_enable_multi(DLPIStream *the_stream, queue_t *q, mblk_t *mp);
303     static void DLPI_disable_multi(DLPIStream *the_stream, queue_t *q, mblk_t *mp);
304     static void DLPI_unit_data(DLPIStream *the_stream, queue_t *q, mblk_t *mp);
305    
306    
307     /*
308     * Initialize ethernet stream module
309     */
310    
311 gbeauche 1.9 static uint8 InitStreamModuleImpl(void *theID)
312 cebix 1.1 {
313     D(bug("InitStreamModule\n"));
314    
315     // Don't re-open if already open
316     if (ether_driver_opened)
317     return true;
318     ether_driver_opened = false;
319    
320     // Import functions from OTKernelLib
321 gbeauche 1.6 allocb_tvect = FindLibSymbol("\013OTKernelLib", "\006allocb");
322 cebix 1.1 D(bug("allocb TVECT at %08lx\n", allocb_tvect));
323     if (allocb_tvect == 0)
324     return false;
325 gbeauche 1.6 freeb_tvect = FindLibSymbol("\013OTKernelLib", "\005freeb");
326 cebix 1.1 D(bug("freeb TVECT at %08lx\n", freeb_tvect));
327     if (freeb_tvect == 0)
328     return false;
329 gbeauche 1.6 freemsg_tvect = FindLibSymbol("\013OTKernelLib", "\007freemsg");
330 cebix 1.1 D(bug("freemsg TVECT at %08lx\n", freemsg_tvect));
331     if (freemsg_tvect == 0)
332     return false;
333 gbeauche 1.6 copyb_tvect = FindLibSymbol("\013OTKernelLib", "\005copyb");
334 cebix 1.1 D(bug("copyb TVECT at %08lx\n", copyb_tvect));
335     if (copyb_tvect == 0)
336     return false;
337 gbeauche 1.6 dupmsg_tvect = FindLibSymbol("\013OTKernelLib", "\006dupmsg");
338 cebix 1.1 D(bug("dupmsg TVECT at %08lx\n", dupmsg_tvect));
339     if (dupmsg_tvect == 0)
340     return false;
341 gbeauche 1.6 getq_tvect = FindLibSymbol("\013OTKernelLib", "\004getq");
342 cebix 1.1 D(bug("getq TVECT at %08lx\n", getq_tvect));
343     if (getq_tvect == 0)
344     return false;
345 gbeauche 1.6 putq_tvect = FindLibSymbol("\013OTKernelLib", "\004putq");
346 cebix 1.1 D(bug("putq TVECT at %08lx\n", putq_tvect));
347     if (putq_tvect == 0)
348     return false;
349 gbeauche 1.6 putnext_tvect = FindLibSymbol("\013OTKernelLib", "\007putnext");
350 cebix 1.1 D(bug("putnext TVECT at %08lx\n", putnext_tvect));
351     if (putnext_tvect == 0)
352     return false;
353 gbeauche 1.6 putnextctl1_tvect = FindLibSymbol("\013OTKernelLib", "\013putnextctl1");
354 cebix 1.1 D(bug("putnextctl1 TVECT at %08lx\n", putnextctl1_tvect));
355     if (putnextctl1_tvect == 0)
356     return false;
357 gbeauche 1.6 canputnext_tvect = FindLibSymbol("\013OTKernelLib", "\012canputnext");
358 cebix 1.1 D(bug("canputnext TVECT at %08lx\n", canputnext_tvect));
359     if (canputnext_tvect == 0)
360     return false;
361 gbeauche 1.6 qreply_tvect = FindLibSymbol("\013OTKernelLib", "\006qreply");
362 cebix 1.1 D(bug("qreply TVECT at %08lx\n", qreply_tvect));
363     if (qreply_tvect == 0)
364     return false;
365 gbeauche 1.6 flushq_tvect = FindLibSymbol("\013OTKernelLib", "\006flushq");
366 cebix 1.1 D(bug("flushq TVECT at %08lx\n", flushq_tvect));
367     if (flushq_tvect == 0)
368     return false;
369 gbeauche 1.6 msgdsize_tvect = FindLibSymbol("\013OTKernelLib", "\010msgdsize");
370 cebix 1.1 D(bug("msgdsize TVECT at %08lx\n", msgdsize_tvect));
371     if (msgdsize_tvect == 0)
372     return false;
373 gbeauche 1.6 otenterint_tvect = FindLibSymbol("\017OTKernelUtilLib", "\020OTEnterInterrupt");
374 cebix 1.1 D(bug("OTEnterInterrupt TVECT at %08lx\n", otenterint_tvect));
375     if (otenterint_tvect == 0)
376     return false;
377 gbeauche 1.6 otleaveint_tvect = FindLibSymbol("\017OTKernelUtilLib", "\020OTLeaveInterrupt");
378 cebix 1.1 D(bug("OTLeaveInterrupt TVECT at %08lx\n", otleaveint_tvect));
379     if (otleaveint_tvect == 0)
380     return false;
381 gbeauche 1.6 mi_open_comm_tvect = FindLibSymbol("\013OTKernelLib", "\014mi_open_comm");
382 cebix 1.1 D(bug("mi_open_comm TVECT at %08lx\n", mi_open_comm_tvect));
383     if (mi_open_comm_tvect == 0)
384     return false;
385 gbeauche 1.6 mi_close_comm_tvect = FindLibSymbol("\013OTKernelLib", "\015mi_close_comm");
386 cebix 1.1 D(bug("mi_close_comm TVECT at %08lx\n", mi_close_comm_tvect));
387     if (mi_close_comm_tvect == 0)
388     return false;
389 gbeauche 1.6 mi_next_ptr_tvect = FindLibSymbol("\013OTKernelLib", "\013mi_next_ptr");
390 cebix 1.1 D(bug("mi_next_ptr TVECT at %08lx\n", mi_next_ptr_tvect));
391     if (mi_next_ptr_tvect == 0)
392     return false;
393    
394 gbeauche 1.9 #ifndef USE_ETHER_FULL_DRIVER
395 cebix 1.1 // Initialize stream list (which might be leftover)
396     dlpi_stream_list = NULL;
397    
398     // Ask add-on for ethernet hardware address
399 gbeauche 1.8 AO_get_ethernet_address(Host2MacAddr(hardware_address));
400 gbeauche 1.9 #endif
401 cebix 1.1
402     // Yes, we're open
403     ether_driver_opened = true;
404     return true;
405     }
406    
407 gbeauche 1.9 uint8 InitStreamModule(void *theID)
408     {
409     // Common initialization code
410     bool net_open = InitStreamModuleImpl(theID);
411    
412     // Call InitStreamModule() in native side
413     #ifdef BUILD_ETHER_FULL_DRIVER
414     extern bool NativeInitStreamModule(void *);
415     if (!NativeInitStreamModule((void *)ether_dispatch_packet))
416     net_open = false;
417     #endif
418    
419     // Import functions from the Ethernet driver
420     #ifdef USE_ETHER_FULL_DRIVER
421     ether_dispatch_packet_tvect = (uintptr)theID;
422     D(bug("ether_dispatch_packet TVECT at %08lx\n", ether_dispatch_packet_tvect));
423     if (ether_dispatch_packet_tvect == 0)
424     net_open = false;
425     #endif
426    
427     return net_open;
428     }
429    
430 cebix 1.1
431     /*
432     * Terminate ethernet stream module
433     */
434    
435 gbeauche 1.9 static void TerminateStreamModuleImpl(void)
436 cebix 1.1 {
437     D(bug("TerminateStreamModule\n"));
438    
439 gbeauche 1.9 #ifndef USE_ETHER_FULL_DRIVER
440 cebix 1.1 // This happens sometimes. I don't know why.
441     if (dlpi_stream_list != NULL)
442     printf("FATAL: TerminateStreamModule() called, but streams still open\n");
443 gbeauche 1.9 #endif
444 cebix 1.1
445     // Sorry, we're closed
446     ether_driver_opened = false;
447     }
448    
449 gbeauche 1.9 void TerminateStreamModule(void)
450     {
451     // Common termination code
452     TerminateStreamModuleImpl();
453    
454     // Call TerminateStreamModule() in native side
455     #ifdef BUILD_ETHER_FULL_DRIVER
456     extern void NativeTerminateStreamModule(void);
457     NativeTerminateStreamModule();
458     #endif
459     }
460    
461 cebix 1.1
462     /*
463     * Open new stream
464     */
465    
466     int ether_open(queue_t *rdq, void *dev, int flag, int sflag, void *creds)
467     {
468     D(bug("ether_open(%p,%p,%d,%d,%p)\n", rdq, dev, flag, sflag, creds));
469    
470     // Return if driver was closed
471     if (!ether_driver_opened) {
472     printf("FATAL: ether_open(): Ethernet driver not opened\n");
473     return MAC_ENXIO;
474     }
475    
476     // If we're being reopened, just return
477     if (rdq->q_ptr != NULL)
478     return 0;
479    
480     // Allocate DLPIStream structure
481 gbeauche 1.3 int err = mi_open_comm((DLPIStream **)&dlpi_stream_list, sizeof(DLPIStream), rdq, dev, flag, sflag, creds);
482 cebix 1.1 if (err)
483     return err;
484     DLPIStream *the_stream = (DLPIStream *)rdq->q_ptr;
485     the_stream->rdq = rdq;
486     the_stream->dlpi_state = DL_UNBOUND;
487     the_stream->flags = 0;
488     the_stream->dlsap = 0;
489     the_stream->framing_8022 = false;
490     the_stream->multicast_list = NULL;
491     return 0;
492     }
493    
494    
495     /*
496     * Close stream
497     */
498    
499     int ether_close(queue_t *rdq, int flag, void *creds)
500     {
501     D(bug("ether_close(%p,%d,%p)\n", rdq, flag, creds));
502    
503     // Return if driver was closed
504     if (!ether_driver_opened) {
505     printf("FATAL: ether_close(): Ethernet driver not opened\n");
506     return MAC_ENXIO;
507     }
508    
509     // Get stream
510     DLPIStream *the_stream = (DLPIStream *)rdq->q_ptr;
511    
512     // Don't close if never opened
513     if (the_stream == NULL)
514     return 0;
515    
516     // Disable all registered multicast addresses
517     while (the_stream->multicast_list) {
518 gbeauche 1.8 AO_disable_multicast(Host2MacAddr(the_stream->multicast_list->addr));
519 cebix 1.1 the_stream->RemoveMulticast(the_stream->multicast_list->addr);
520     }
521     the_stream->multicast_list = NULL;
522    
523     // Delete the DLPIStream
524 gbeauche 1.3 return mi_close_comm((DLPIStream **)&dlpi_stream_list, rdq);
525 cebix 1.1 }
526    
527    
528     /*
529     * Put something on the write queue
530     */
531    
532     int ether_wput(queue_t *q, mblk_t *mp)
533     {
534     D(bug("ether_wput(%p,%p)\n", q, mp));
535    
536     // Return if driver was closed
537     if (!ether_driver_opened) {
538     printf("FATAL: ether_wput(): Ethernet driver not opened\n");
539     return MAC_ENXIO;
540     }
541    
542     // Get stream
543     DLPIStream *the_stream = (DLPIStream *)q->q_ptr;
544     if (the_stream == NULL)
545     return MAC_ENXIO;
546    
547 gbeauche 1.3 D(bug(" db_type %d\n", (int)mp->b_datap->db_type));
548 cebix 1.1 switch (mp->b_datap->db_type) {
549    
550     case M_DATA:
551     // Transmit raw packet
552     D(bug(" raw packet\n"));
553     num_tx_raw_packets++;
554     transmit_packet(mp);
555     break;
556    
557     case M_PROTO:
558     case M_PCPROTO: {
559 gbeauche 1.3 union DL_primitives *dlp = (union DL_primitives *)(void *)mp->b_rptr;
560 cebix 1.1 uint32 prim = dlp->dl_primitive;
561     D(bug(" dl_primitive %d\n", prim));
562     switch (prim) {
563     case DL_UNITDATA_REQ:
564     // Transmit normal packet
565     num_tx_normal_packets++;
566     DLPI_unit_data(the_stream, q, mp);
567     break;
568    
569     case DL_INFO_REQ:
570     DLPI_info(the_stream, q, mp);
571     break;
572    
573     case DL_PHYS_ADDR_REQ:
574     DLPI_phys_addr(the_stream, q, mp);
575     break;
576    
577     case DL_BIND_REQ:
578     DLPI_bind(the_stream, q, mp);
579     break;
580    
581     case DL_UNBIND_REQ:
582     DLPI_unbind(the_stream, q, mp);
583     break;
584    
585     case DL_SUBS_BIND_REQ:
586     DLPI_subs_bind(the_stream, q, mp);
587     break;
588    
589     case DL_SUBS_UNBIND_REQ:
590     DLPI_subs_unbind(the_stream, q, mp);
591     break;
592    
593     case DL_ENABMULTI_REQ:
594     DLPI_enable_multi(the_stream, q, mp);
595     break;
596    
597     case DL_DISABMULTI_REQ:
598     DLPI_disable_multi(the_stream, q, mp);
599     break;
600    
601     default:
602     D(bug("WARNING: ether_wsrv(): Unknown primitive\n"));
603     DLPI_error_ack(the_stream, q, mp, prim, DL_NOTSUPPORTED, 0);
604     break;
605     }
606     break;
607     }
608    
609     case M_IOCTL:
610     ether_ioctl(the_stream, q, mp);
611     break;
612    
613     case M_FLUSH:
614     ether_flush(q, mp);
615     break;
616    
617     default:
618     D(bug("WARNING: ether_wput(): Unknown message type\n"));
619     freemsg(mp);
620     break;
621     }
622     num_wput++;
623     return 0;
624     }
625    
626    
627     /*
628     * Dequeue and process messages from the read queue
629     */
630    
631     int ether_rsrv(queue_t *q)
632     {
633     mblk_t *mp;
634     while ((mp = getq(q)) != NULL) {
635     if (canputnext(q))
636     putnext(q, mp);
637     else {
638     freemsg(mp);
639     flushq(q, FLUSHDATA);
640     break;
641     }
642     }
643     return 0;
644     }
645    
646    
647     /*
648     * Handle ioctl calls
649     */
650    
651     static void ether_ioctl(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
652     {
653 gbeauche 1.3 struct iocblk *ioc = (struct iocblk *)(void *)mp->b_rptr;
654     D(bug(" ether_ioctl(%p,%p) cmd %d\n", q, mp, (int)ioc->ioc_cmd));
655 cebix 1.1
656     switch (ioc->ioc_cmd) {
657    
658     case I_OTSetFramingType: { // Toggles what the general info primitive returns for dl_mac_type in dl_info_ack_t structure
659     mblk_t *info_mp = mp->b_cont;
660     if (info_mp == NULL || ((info_mp->b_wptr - info_mp->b_rptr) != sizeof(uint32))) {
661     ioc->ioc_error = MAC_EINVAL;
662     goto ioctl_error;
663     }
664 gbeauche 1.3 uint32 framing_type = ntohl(*(uint32 *)(void *)info_mp->b_rptr);
665 cebix 1.1 D(bug(" I_OTSetFramingType type %d\n", framing_type));
666     if (framing_type != kOTGetFramingValue)
667     the_stream->framing_8022 = (framing_type == kOTFraming8022);
668     mp->b_cont = NULL;
669     freemsg(info_mp);
670     if (the_stream->framing_8022)
671     ioc->ioc_rval = kOTFraming8022;
672     else
673     ioc->ioc_rval = kOTFramingEthernet;
674     goto ioctl_ok;
675     }
676    
677     case DL_IOC_HDR_INFO: { // Special Mentat call, for fast transmits
678     D(bug(" DL_IOC_HDR_INFO\n"));
679     mblk_t *info_mp = mp->b_cont;
680    
681     // Copy DL_UNITDATA_REQ block
682     mblk_t *unitdata_mp = copyb(info_mp);
683     if (unitdata_mp == NULL) {
684     ioc->ioc_error = MAC_ENOMEM;
685     goto ioctl_error;
686     }
687     unitdata_mp->b_datap->db_type = M_PROTO;
688    
689     // Construct header (converts DL_UNITDATA_REQ -> M_DATA)
690     mblk_t *header_mp = build_tx_packet_header(the_stream, unitdata_mp, true);
691    
692     if (header_mp == NULL) {
693     // Could not allocate a message block large enough
694     ioc->ioc_error = MAC_ENOMEM;
695     goto ioctl_error;
696     }
697    
698     // Attach header block at the end
699     mp->b_cont->b_cont = header_mp;
700     the_stream->flags |= kFastPathMode;
701     goto ioctl_ok;
702     }
703    
704     case I_OTSetRawMode: {
705     mblk_t *info_mp = mp->b_cont;
706     dl_recv_control_t *dlrc;
707     if (info_mp == NULL || ((info_mp->b_wptr - info_mp->b_rptr) != sizeof(dlrc->dl_primitive))) {
708     ioc->ioc_error = MAC_EINVAL;
709     goto ioctl_error;
710     }
711 gbeauche 1.3 dlrc = (dl_recv_control_t *)(void *)info_mp->b_rptr;
712     D(bug(" I_OTSetRawMode primitive %d\n", (int)dlrc->dl_primitive));
713 cebix 1.1 ioc->ioc_error = MAC_EINVAL;
714     goto ioctl_error;
715     }
716    
717     default:
718     D(bug("WARNING: Unknown ether_ioctl() call\n"));
719     ioc->ioc_error = MAC_EINVAL;
720     goto ioctl_error;
721     }
722    
723     ioctl_ok:
724     ioc->ioc_count = 0;
725     for (mblk_t *mp1 = mp; (mp1 = mp1->b_cont) != NULL;)
726     ioc->ioc_count += mp1->b_wptr - mp1->b_rptr;
727     ioc->ioc_error = 0;
728     mp->b_datap->db_type = M_IOCACK;
729     qreply(q, mp);
730     return;
731    
732     ioctl_error:
733     mp->b_datap->db_type = M_IOCNAK;
734     qreply(q, mp);
735     return;
736     }
737    
738    
739     /*
740     * Flush call, send it up to the read side of the stream
741     */
742    
743     static void ether_flush(queue_t* q, mblk_t* mp)
744     {
745     D(bug(" ether_flush(%p,%p)\n", q, mp));
746    
747     uint8 *rptr = mp->b_rptr;
748     if (*rptr & FLUSHW)
749     flushq(q, FLUSHALL);
750     if (*rptr & FLUSHR) {
751     flushq(RD(q), FLUSHALL);
752     *rptr &= ~FLUSHW;
753     qreply(q, mp);
754     } else
755     freemsg(mp);
756     }
757    
758    
759     /*
760     * Classify packet into the different types of protocols
761     */
762    
763     static uint16 classify_packet_type(uint16 primarySAP, uint16 secondarySAP)
764     {
765     if (primarySAP >= kMinDIXSAP)
766     return kPktDIX;
767    
768     if ((primarySAP == kIPXSAP) && (secondarySAP == kIPXSAP))
769     return kPktIPX;
770    
771     if (primarySAP == kSNAPSAP)
772     return kPkt8022SNAP;
773    
774     if (primarySAP <= k8022GlobalSAP)
775     return kPkt8022SAP;
776    
777     return kPktUnknown;
778     }
779    
780    
781     /*
782     * Check if the address is a multicast, broadcast or standard address
783     */
784    
785     static int32 get_address_type(uint8 *addr)
786     {
787     if (addr[0] & 1) { // Multicast/broadcast flag
788     if (OTIs48BitBroadcastAddress(addr))
789     return keaBroadcast;
790     else
791     return keaMulticast;
792     } else
793     return keaStandardAddress;
794     }
795    
796    
797     /*
798     * Reuse a message block, make room for more data
799     */
800    
801     static mblk_t *reuse_message_block(mblk_t *mp, uint16 needed_size)
802     {
803     mblk_t *nmp;
804    
805     if ((mp->b_datap->db_ref == 1) && ((mp->b_datap->db_lim - mp->b_datap->db_base) >= needed_size)) {
806     mp->b_datap->db_type = M_DATA;
807     mp->b_rptr = mp->b_datap->db_base;
808     mp->b_wptr = mp->b_datap->db_base + needed_size;
809     } else {
810     nmp = mp->b_cont; // Grab the M_DATA blocks
811     mp->b_cont = NULL; // Detach the M_(PC)PROTO
812     freemsg(mp); // Free the M_(PC)PROTO
813     mp = nmp; // Point to the M_DATA blocks
814    
815     // Try to get space on the first M_DATA block
816     if (mp && (mp->b_datap->db_ref == 1) && ((mp->b_rptr - mp->b_datap->db_base) >= needed_size))
817     mp->b_rptr -= needed_size;
818     else {
819     // Try to allocate a new message
820     if ((nmp = allocb(needed_size, BPRI_HI)) == NULL) {
821     // Could not get a new message block so lets forget about the message altogether
822     freemsg(mp); // Free the original M_DATA portion of the message
823     mp = NULL; // Indicates the reuse failed
824     } else {
825     nmp->b_cont = mp; // Attach the new message block as the head
826     nmp->b_wptr += needed_size;
827     mp = nmp;
828     }
829     }
830     }
831    
832     return mp;
833     }
834    
835    
836     /*
837     * Built header for packet to be transmitted (convert DL_UNITDATA_REQ -> M_DATA)
838     * The passed-in message has the header info in the first message block and the data
839     * in the following blocks
840     */
841    
842     static mblk_t *build_tx_packet_header(DLPIStream *the_stream, mblk_t *mp, bool fast_path)
843     {
844     // Only handle unit_data requests
845 gbeauche 1.3 dl_unitdata_req_t *req = (dl_unitdata_req_t *)(void *)mp->b_rptr;
846 cebix 1.1 if (req->dl_primitive != DL_UNITDATA_REQ) {
847     freemsg(mp);
848     return NULL;
849     }
850    
851     // Extract destination address and its length
852     uint8 *destAddrOrig = ((uint8 *)req) + req->dl_dest_addr_offset;
853     uint32 destAddrLen = req->dl_dest_addr_length;
854     uint8 ctrl = 0x03;
855    
856     // Extract DLSAP
857     uint16 dlsap;
858     switch (destAddrLen) {
859     case kEnetPhysicalAddressLength:
860     dlsap = the_stream->dlsap;
861     break;
862     case kEnetAndSAPAddressLength:
863 gbeauche 1.3 dlsap = ntohs(*(uint16 *)(destAddrOrig + kEnetPhysicalAddressLength));
864 cebix 1.1 break;
865     case kEnetPhysicalAddressLength + k8022DLSAPLength + k8022SNAPLength: // SNAP SAP
866 gbeauche 1.3 dlsap = ntohs(*(uint16 *)(destAddrOrig + kEnetPhysicalAddressLength));
867 cebix 1.1 break;
868     default:
869     dlsap = the_stream->dlsap;
870     break;
871     }
872    
873     // Extract data size (excluding header info) and packet type
874     uint16 datasize = msgdsize(mp);
875     uint16 packetType = classify_packet_type(the_stream->dlsap, dlsap);
876    
877     // Calculate header size and protocol type/size field
878     uint16 hdrsize, proto;
879     switch (packetType) {
880     case kPktDIX:
881     hdrsize = kEnetPacketHeaderLength;
882     proto = dlsap;
883     break;
884     case kPkt8022SAP:
885     hdrsize = kEnetPacketHeaderLength + k8022BasicHeaderLength;
886     if (fast_path)
887     proto = 0;
888     else
889     proto = datasize + k8022BasicHeaderLength;
890     break;
891     case kPkt8022SNAP:
892     hdrsize = kEnetPacketHeaderLength + k8022SNAPHeaderLength;
893     if (fast_path)
894     proto = 0;
895     else
896     proto = datasize + k8022SNAPHeaderLength;
897     break;
898     case kPktIPX:
899     hdrsize = kEnetPacketHeaderLength;
900     if (fast_path)
901     proto = 0;
902     else
903     proto = datasize;
904     break;
905     default:
906     hdrsize = kEnetPacketHeaderLength;
907     proto = dlsap;
908     break;
909     }
910    
911     // We need to copy the dest address info in the message before we can reuse it
912     uint8 destAddrCopy[kMaxBoundAddrLength];
913     memcpy(destAddrCopy, destAddrOrig, destAddrLen);
914    
915     // Resize header info in message block
916     if ((mp = reuse_message_block(mp, hdrsize)) == NULL)
917     return NULL;
918 gbeauche 1.3 struct T8022FullPacketHeader *packetHeader = (struct T8022FullPacketHeader *)(void *)mp->b_rptr;
919 cebix 1.1
920     // Set protocol type/size field
921     packetHeader->fEnetPart.fProto = proto;
922    
923     // Set destination ethernet address
924     OTCopy48BitAddress(destAddrCopy, packetHeader->fEnetPart.fDestAddr);
925    
926     // Set other header fields
927     switch (packetType) {
928     case kPkt8022SAP:
929     packetHeader->f8022Part.fDSAP = (uint8)dlsap;
930     packetHeader->f8022Part.fSSAP = (uint8)the_stream->dlsap;
931     packetHeader->f8022Part.fCtrl = ctrl;
932     break;
933     case kPkt8022SNAP: {
934     uint8 *snapStart;
935     packetHeader->f8022Part.fDSAP = (uint8)dlsap;
936     packetHeader->f8022Part.fSSAP = (uint8)the_stream->dlsap;
937     packetHeader->f8022Part.fCtrl = ctrl;
938     if (destAddrLen >= kEnetAndSAPAddressLength + k8022SNAPLength)
939     snapStart = destAddrCopy + kEnetAndSAPAddressLength;
940     else
941     snapStart = the_stream->snap;
942     OTCopy8022SNAP(snapStart, packetHeader->f8022Part.fSNAP);
943     break;
944     }
945     }
946    
947     // Return updated message
948     return mp;
949     }
950    
951    
952     /*
953     * Transmit packet
954     */
955    
956     static void transmit_packet(mblk_t *mp)
957     {
958 gbeauche 1.3 EnetPacketHeader *enetHeader = (EnetPacketHeader *)(void *)mp->b_rptr;
959 cebix 1.1
960     // Fill in length in 802.3 packets
961     if (enetHeader->fProto == 0)
962     enetHeader->fProto = msgdsize(mp) - sizeof(EnetPacketHeader);
963    
964     // Fill in ethernet source address
965     OTCopy48BitAddress(hardware_address, enetHeader->fSourceAddr);
966    
967     // Tell add-on to transmit packet
968 gbeauche 1.8 AO_transmit_packet(Host2MacAddr((uint8 *)mp));
969 cebix 1.1 freemsg(mp);
970     }
971    
972    
973     /*
974     * Handle incoming packet (one stream), construct DL_UNITDATA_IND message
975     */
976    
977     static void handle_received_packet(DLPIStream *the_stream, mblk_t *mp, uint16 packet_type, int32 dest_addr_type)
978     {
979     // Find address and header length
980     uint32 addr_len;
981     uint32 header_len;
982     switch (packet_type) {
983     case kPkt8022SAP:
984     addr_len = kEnetAndSAPAddressLength;
985     header_len = kEnetPacketHeaderLength + k8022BasicHeaderLength;
986     break;
987     case kPkt8022SNAP:
988     addr_len = kEnetAndSAPAddressLength + k8022SNAPLength;
989     header_len = kEnetPacketHeaderLength + k8022SNAPHeaderLength;
990     break;
991     default: // DIX and IPX
992     addr_len = kEnetAndSAPAddressLength;
993     header_len = kEnetPacketHeaderLength;
994     break;
995     }
996    
997     // In Fast Path mode, don't send DL_UNITDATA_IND messages for unicast packets
998     if ((the_stream->flags & kFastPathMode) && dest_addr_type == keaStandardAddress) {
999     mp->b_rptr += header_len;
1000     num_rx_fastpath++;
1001     putq(the_stream->rdq, mp);
1002     return;
1003     }
1004    
1005     // Allocate the dl_unitdata_ind_t message
1006     mblk_t *nmp;
1007     if ((nmp = allocb(sizeof(dl_unitdata_ind_t) + 2*addr_len, BPRI_HI)) == NULL) {
1008     freemsg(mp);
1009     num_rx_no_unitdata_mem++;
1010     return;
1011     }
1012    
1013     // Set message type
1014     nmp->b_datap->db_type = M_PROTO;
1015 gbeauche 1.3 dl_unitdata_ind_t *ind = (dl_unitdata_ind_t*)(void *)nmp->b_rptr;
1016 cebix 1.1 ind->dl_primitive = DL_UNITDATA_IND;
1017     nmp->b_wptr += (sizeof(dl_unitdata_ind_t) + 2*addr_len);
1018    
1019     // Link M_DATA block
1020     nmp->b_cont = mp;
1021    
1022     // Set address fields
1023     ind->dl_dest_addr_length = addr_len;
1024     ind->dl_dest_addr_offset = sizeof(dl_unitdata_ind_t);
1025     ind->dl_src_addr_length = addr_len;
1026     ind->dl_src_addr_offset = sizeof(dl_unitdata_ind_t) + addr_len;
1027    
1028     // Set address type
1029     ind->dl_group_address = dest_addr_type;
1030    
1031     // Set address fields
1032 gbeauche 1.3 T8022FullPacketHeader *packetHeader = (T8022FullPacketHeader *)(void *)mp->b_rptr;
1033 cebix 1.1 T8022AddressStruct *destAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_dest_addr_offset));
1034     T8022AddressStruct *srcAddr = ((T8022AddressStruct*)(nmp->b_rptr + ind->dl_src_addr_offset));
1035    
1036     OTCopy48BitAddress(packetHeader->fEnetPart.fDestAddr, destAddr->fHWAddr);
1037     OTCopy48BitAddress(packetHeader->fEnetPart.fSourceAddr, srcAddr->fHWAddr);
1038    
1039     destAddr->fSAP = packetHeader->f8022Part.fDSAP;
1040     srcAddr->fSAP = packetHeader->f8022Part.fSSAP;
1041    
1042     if (packet_type == kPkt8022SNAP) {
1043     OTCopy8022SNAP(packetHeader->f8022Part.fSNAP, destAddr->fSNAP);
1044     OTCopy8022SNAP(packetHeader->f8022Part.fSNAP, srcAddr->fSNAP);
1045     }
1046    
1047     // "Hide" the ethernet and protocol header(s)
1048     mp->b_rptr += header_len;
1049    
1050     // Pass message up the stream
1051     num_unitdata_ind++;
1052     putq(the_stream->rdq, nmp);
1053     return;
1054     }
1055    
1056    
1057     /*
1058     * Packet received, distribute it to the streams that want it
1059     */
1060    
1061     void ether_packet_received(mblk_t *mp)
1062     {
1063     // Extract address and types
1064 gbeauche 1.3 EnetPacketHeader *pkt = (EnetPacketHeader *)(void *)mp->b_rptr;
1065 cebix 1.1 T8022FullPacketHeader *fullpkt = (T8022FullPacketHeader *)pkt;
1066     uint16 sourceSAP, destSAP;
1067     destSAP = fullpkt->fEnetPart.fProto;
1068     if (destSAP >= kMinDIXSAP) {
1069     // Classic ethernet
1070     sourceSAP = destSAP;
1071     } else {
1072     destSAP = fullpkt->f8022Part.fDSAP;
1073     sourceSAP = fullpkt->f8022Part.fSSAP;
1074     }
1075     uint16 packetType = classify_packet_type(sourceSAP, destSAP);
1076     int32 destAddressType = get_address_type(pkt->fDestAddr);
1077    
1078     // Look which streams want it
1079     DLPIStream *the_stream, *found_stream = NULL;
1080     uint16 found_packetType = 0;
1081     int32 found_destAddressType = 0;
1082     for (the_stream = dlpi_stream_list; the_stream != NULL; the_stream = mi_next_ptr(the_stream)) {
1083    
1084     // Don't send to unbound streams
1085     if (the_stream->dlpi_state == DL_UNBOUND)
1086     continue;
1087    
1088     // Does this stream want all 802.2 packets?
1089     if ((the_stream->flags & kAcceptAll8022Packets) && (destSAP <= 0xff))
1090     goto type_found;
1091    
1092     // No, check SAP/SNAP
1093     if (destSAP == the_stream->dlsap) {
1094     if (the_stream->flags & kSnapStream) {
1095     // Check SNAPs if necessary
1096     uint8 sum = fullpkt->f8022Part.fSNAP[0] ^ the_stream->snap[0];
1097     sum |= fullpkt->f8022Part.fSNAP[1] ^ the_stream->snap[1];
1098     sum |= fullpkt->f8022Part.fSNAP[2] ^ the_stream->snap[2];
1099     sum |= fullpkt->f8022Part.fSNAP[3] ^ the_stream->snap[3];
1100     sum |= fullpkt->f8022Part.fSNAP[4] ^ the_stream->snap[4];
1101     if (sum == 0)
1102     goto type_found;
1103     } else {
1104     // No SNAP, found a match since saps match
1105     goto type_found;
1106     }
1107     } else {
1108     // Check for an 802.3 Group/Global (odd)
1109     if (((packetType == kPkt8022SAP) || (packetType == kPkt8022SNAP)) && (destSAP & 1) && the_stream->TestGroupSAP(destSAP))
1110     goto type_found;
1111     }
1112    
1113     // No stream for this SAP/SNAP found
1114     continue;
1115    
1116     type_found:
1117     // If it's a multicast packet, it must be in the stream's multicast list
1118     if ((destAddressType == keaMulticast) && (the_stream->flags & kAcceptMulticasts) && (!the_stream->IsMulticastRegistered(pkt->fDestAddr)))
1119     continue;
1120    
1121     // Send packet to stream
1122     // found_stream keeps a pointer to the previously found stream, so that only the last
1123     // stream gets the original message, the other ones get duplicates
1124     if (found_stream)
1125     handle_received_packet(found_stream, dupmsg(mp), found_packetType, found_destAddressType);
1126     found_stream = the_stream;
1127     found_packetType = packetType;
1128     found_destAddressType = destAddressType;
1129     }
1130    
1131     // Send original message to last found stream
1132     if (found_stream)
1133     handle_received_packet(found_stream, mp, found_packetType, found_destAddressType);
1134     else {
1135     freemsg(mp); // Nobody wants it *snief*
1136     num_rx_dropped++;
1137     }
1138     }
1139    
1140 gbeauche 1.8 void ether_dispatch_packet(uint32 p, uint32 size)
1141     {
1142 gbeauche 1.9 #ifdef USE_ETHER_FULL_DRIVER
1143     // Call handler from the Ethernet driver
1144     D(bug("ether_dispatch_packet\n"));
1145     D(bug(" packet data at %p, %d bytes\n", p, size));
1146     CallMacOS2(ether_dispatch_packet_ptr, ether_dispatch_packet_tvect, p, size);
1147     #else
1148 gbeauche 1.8 // Wrap packet in message block
1149     num_rx_packets++;
1150     mblk_t *mp;
1151     if ((mp = allocb(size, 0)) != NULL) {
1152     D(bug(" packet data at %p\n", (void *)mp->b_rptr));
1153     Mac2Host_memcpy(mp->b_rptr, p, size);
1154     mp->b_wptr += size;
1155     ether_packet_received(mp);
1156     } else {
1157     D(bug("WARNING: Cannot allocate mblk for received packet\n"));
1158     num_rx_no_mem++;
1159     }
1160 gbeauche 1.9 #endif
1161 gbeauche 1.8 }
1162    
1163 cebix 1.1
1164     /*
1165     * Build and send an error acknowledge
1166     */
1167    
1168     static void DLPI_error_ack(DLPIStream *the_stream, queue_t *q, mblk_t *ack_mp, uint32 prim, uint32 err, uint32 uerr)
1169     {
1170     D(bug(" DLPI_error_ack(%p,%p) prim %d, err %d, uerr %d\n", the_stream, ack_mp, prim, err, uerr));
1171     num_error_acks++;
1172    
1173     if (ack_mp != NULL)
1174     freemsg(ack_mp);
1175     if ((ack_mp = allocb(sizeof(dl_error_ack_t), BPRI_HI)) == NULL)
1176     return;
1177    
1178     ack_mp->b_datap->db_type = M_PCPROTO;
1179 gbeauche 1.3 dl_error_ack_t *errp = (dl_error_ack_t *)(void *)ack_mp->b_wptr;
1180 cebix 1.1 errp->dl_primitive = DL_ERROR_ACK;
1181     errp->dl_error_primitive = prim;
1182     errp->dl_errno = err;
1183     errp->dl_unix_errno = uerr;
1184     ack_mp->b_wptr += sizeof(dl_error_ack_t);
1185     qreply(q, ack_mp);
1186     }
1187    
1188    
1189     /*
1190     * Build and send an OK acknowledge
1191     */
1192    
1193     static void DLPI_ok_ack(DLPIStream *the_stream, queue_t *q, mblk_t *ack_mp, uint32 prim)
1194     {
1195     if (ack_mp->b_datap->db_ref != 1) {
1196     // Message already in use, create a new one
1197     freemsg(ack_mp);
1198     if ((ack_mp = allocb(sizeof(dl_error_ack_t), BPRI_HI)) == NULL)
1199     return;
1200     } else {
1201     // Message free
1202     if (ack_mp->b_cont != NULL) {
1203     freemsg(ack_mp->b_cont);
1204     ack_mp->b_cont = NULL;
1205     }
1206     }
1207    
1208     ack_mp->b_datap->db_type = M_PCPROTO;
1209 gbeauche 1.3 dl_ok_ack_t *ackp = (dl_ok_ack_t *)(void *)ack_mp->b_rptr;
1210 cebix 1.1 ackp->dl_primitive = DL_OK_ACK;
1211     ackp->dl_correct_primitive = prim;
1212     ack_mp->b_wptr = ack_mp->b_rptr + sizeof(dl_ok_ack_t);
1213     qreply(q, ack_mp);
1214     }
1215    
1216    
1217     /*
1218     * Handle DL_INFO_REQ (report general information)
1219     */
1220    
1221     static void DLPI_info(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
1222     {
1223     D(bug(" DLPI_info(%p)\n", the_stream));
1224     uint32 saplen = 0;
1225     uint32 addrlen = kEnetPhysicalAddressLength;
1226     uint32 bcastlen = kEnetPhysicalAddressLength;
1227     uint32 hdrlen = kEnetPacketHeaderLength;
1228    
1229     // Calculate header length
1230     if (the_stream->dlpi_state != DL_UNBOUND) {
1231     saplen = (the_stream->flags & kSnapStream) ? k8022DLSAPLength+k8022SNAPLength : k8022DLSAPLength;
1232     if (the_stream->dlsap == kSNAPSAP)
1233     hdrlen = kEnetPacketHeaderLength + k8022SNAPHeaderLength; // SNAP address
1234     else if ((the_stream->dlsap <= kMax8022SAP) || (the_stream->dlsap == kIPXSAP))
1235     hdrlen = kEnetPacketHeaderLength + k8022BasicHeaderLength; // SAP or IPX
1236     else
1237     hdrlen = kEnetPacketHeaderLength; // Basic Ethernet
1238     }
1239    
1240     // Allocate message block for reply
1241     mblk_t *ack_mp;
1242     if ((ack_mp = allocb(sizeof(dl_info_ack_t) + addrlen + saplen + bcastlen, BPRI_LO)) == NULL) {
1243     DLPI_error_ack(the_stream, q, mp, DL_INFO_REQ, DL_SYSERR, MAC_ENOMEM);
1244     return;
1245     }
1246    
1247     // Set up message type
1248     ack_mp->b_datap->db_type = M_PCPROTO;
1249 gbeauche 1.3 dl_info_ack_t *ackp = (dl_info_ack_t *)(void *)ack_mp->b_rptr;
1250 cebix 1.1 ackp->dl_primitive = DL_INFO_ACK;
1251    
1252     // Info/version fields
1253     ackp->dl_service_mode = DL_CLDLS;
1254     ackp->dl_provider_style = DL_STYLE1;
1255     ackp->dl_version = DL_VERSION_2;
1256     ackp->dl_current_state = the_stream->dlpi_state;
1257     ackp->dl_mac_type = the_stream->framing_8022 ? DL_CSMACD : DL_ETHER;
1258     ackp->dl_reserved = 0;
1259     ackp->dl_qos_length = 0;
1260     ackp->dl_qos_offset = (uint32)DL_UNKNOWN;
1261     ackp->dl_qos_range_length = 0;
1262     ackp->dl_qos_range_offset = (uint32)DL_UNKNOWN;
1263     ackp->dl_growth = 0;
1264     ackp->dl_min_sdu = 1;
1265     ackp->dl_max_sdu = kEnetTSDU - hdrlen;
1266    
1267     // Address fields
1268     ackp->dl_sap_length = -saplen; // Negative to indicate sap follows physical address
1269     ackp->dl_addr_length = addrlen + saplen;
1270     ackp->dl_addr_offset = sizeof(dl_info_ack_t);
1271     T8022AddressStruct *boundAddr = ((T8022AddressStruct *)(ack_mp->b_rptr + ackp->dl_addr_offset));
1272     OTCopy48BitAddress(hardware_address, boundAddr->fHWAddr);
1273     if (saplen) {
1274     boundAddr->fSAP = the_stream->dlsap;
1275     if (the_stream->flags & kSnapStream)
1276     OTCopy8022SNAP(the_stream->snap, boundAddr->fSNAP);
1277     }
1278     ackp->dl_brdcst_addr_length = bcastlen;
1279     ackp->dl_brdcst_addr_offset = sizeof(dl_info_ack_t) + addrlen + saplen;
1280     OTSet48BitBroadcastAddress(ack_mp->b_rptr + ackp->dl_brdcst_addr_offset);
1281    
1282     // Advance write pointer
1283     ack_mp->b_wptr += sizeof(dl_info_ack_t) + addrlen + saplen + bcastlen;
1284    
1285     // Free request
1286     freemsg(mp);
1287    
1288     // Send reply
1289     qreply(q, ack_mp);
1290     return;
1291     }
1292    
1293    
1294     /*
1295     * Handle DL_PHYS_ADDR_REQ (report physical address)
1296     */
1297    
1298     static void DLPI_phys_addr(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
1299     {
1300     D(bug(" DLPI_phys_addr(%p,%p)\n", the_stream, mp));
1301 gbeauche 1.3 dl_phys_addr_req_t *req = (dl_phys_addr_req_t *)(void *)mp->b_rptr;
1302 cebix 1.1
1303     // Allocate message block for reply
1304     mblk_t *ack_mp;
1305     if ((ack_mp = allocb(sizeof(dl_phys_addr_ack_t) + kEnetPhysicalAddressLength, BPRI_HI)) == NULL) {
1306     DLPI_error_ack(the_stream, q, mp, DL_PHYS_ADDR_REQ, DL_SYSERR, MAC_ENOMEM);
1307     return;
1308     }
1309    
1310     // Set up message type
1311     ack_mp->b_datap->db_type = M_PCPROTO;
1312 gbeauche 1.3 dl_phys_addr_ack_t *ackp = (dl_phys_addr_ack_t *)(void *)ack_mp->b_wptr;
1313 cebix 1.1 ackp->dl_primitive = DL_PHYS_ADDR_ACK;
1314    
1315     // Fill in address
1316     ackp->dl_addr_length = kEnetPhysicalAddressLength;
1317     ackp->dl_addr_offset = sizeof(dl_phys_addr_ack_t);
1318     ack_mp->b_wptr += sizeof(dl_phys_addr_ack_t) + kEnetPhysicalAddressLength;
1319     if (req->dl_addr_type == DL_CURR_PHYS_ADDR || req->dl_addr_type == DL_FACT_PHYS_ADDR)
1320     OTCopy48BitAddress(hardware_address, ack_mp->b_rptr + ackp->dl_addr_offset);
1321     else {
1322     DLPI_error_ack(the_stream, q, mp, DL_PHYS_ADDR_REQ, DL_BADPRIM, 0);
1323     return;
1324     }
1325    
1326     // Free request
1327     freemsg(mp);
1328    
1329     // Send reply
1330     qreply(q, ack_mp);
1331     return;
1332     }
1333    
1334    
1335     /*
1336     * Handle DL_BIND_REQ (bind a stream)
1337     */
1338    
1339     static void DLPI_bind(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
1340     {
1341 gbeauche 1.3 dl_bind_req_t *req = (dl_bind_req_t *)(void *)mp->b_rptr;
1342 cebix 1.1 uint32 sap = req->dl_sap;
1343     D(bug(" DLPI_bind(%p,%p) SAP %04x\n", the_stream, mp, sap));
1344    
1345     // Stream must be unbound
1346     if (the_stream->dlpi_state != DL_UNBOUND) {
1347     DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_OUTSTATE, 0);
1348     return;
1349     }
1350    
1351     // We only support connectionless data link services
1352     if (req->dl_service_mode != DL_CLDLS || req->dl_max_conind != 0) {
1353     DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_UNSUPPORTED, 0);
1354     return;
1355     }
1356    
1357     // Don't bind to 802.2 group saps, can't check 802.2 global sap (0xFF)
1358     // because it looks like IPX
1359     if ((sap <= kMax8022SAP) && (sap & 1)) {
1360     DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_BADADDR, 0);
1361     return;
1362     }
1363    
1364     if (classify_packet_type(sap, sap) == kPktUnknown) {
1365     DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_BADADDR, 0);
1366     return;
1367     }
1368    
1369     // Allocate message block for reply
1370     mblk_t *ack_mp;
1371     if ((ack_mp = allocb(sizeof(dl_bind_ack_t) + kEnetAndSAPAddressLength, BPRI_HI)) == NULL) {
1372     DLPI_error_ack(the_stream, q, mp, DL_BIND_REQ, DL_SYSERR, MAC_ENOMEM);
1373     return;
1374     }
1375    
1376     // Set up message type
1377     ack_mp->b_datap->db_type = M_PCPROTO;
1378 gbeauche 1.3 dl_bind_ack_t *ackp = (dl_bind_ack_t *)(void *)ack_mp->b_rptr;
1379 cebix 1.1 ackp->dl_primitive = DL_BIND_ACK;
1380    
1381     // Fill in other fields
1382     ackp->dl_sap = sap;
1383     ackp->dl_addr_length = kEnetAndSAPAddressLength;
1384     ackp->dl_addr_offset = sizeof(dl_bind_ack_t);
1385     ackp->dl_max_conind = 0;
1386     ackp->dl_xidtest_flg = 0;
1387    
1388     T8022AddressStruct *addrInfo = (T8022AddressStruct *)(ack_mp->b_rptr + sizeof(dl_bind_ack_t));
1389     OTCopy48BitAddress(hardware_address, addrInfo->fHWAddr);
1390     addrInfo->fSAP = sap;
1391    
1392     // Must move b_wptr past the address info data
1393     ack_mp->b_wptr = ack_mp->b_rptr + sizeof(dl_bind_ack_t) + kEnetAndSAPAddressLength;
1394    
1395     // Set group SAP if necessary
1396     the_stream->ClearAllGroupSAPs();
1397     if (sap <= kMax8022SAP)
1398     the_stream->SetGroupSAP(k8022GlobalSAP);
1399    
1400     // The stream is now bound and idle
1401     the_stream->dlpi_state = DL_IDLE;
1402     the_stream->dlsap = sap;
1403     the_stream->flags &= ~kSnapStream;
1404    
1405     // Free request
1406     freemsg(mp);
1407    
1408     // Send reply
1409     qreply(q, ack_mp);
1410     return;
1411     }
1412    
1413    
1414     /*
1415     * Handle DL_UNBIND_REQ (unbind a stream)
1416     */
1417    
1418     static void DLPI_unbind(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
1419     {
1420     D(bug(" DLPI_unbind(%p,%p)\n", the_stream, mp));
1421    
1422     // Stream must be bound and idle
1423     if (the_stream->dlpi_state != DL_IDLE) {
1424     DLPI_error_ack(the_stream, q, mp, DL_UNBIND_REQ, DL_OUTSTATE, 0);
1425     return;
1426     }
1427    
1428     // Stream is now unbound
1429     the_stream->dlpi_state = DL_UNBOUND;
1430     the_stream->dlsap = 0;
1431    
1432     // Flush all pending outbound messages
1433     flushq(q, FLUSHDATA);
1434    
1435     // Flush all inbound messages pending on the stream
1436     flushq(RD(q), FLUSHDATA);
1437     putnextctl1(RD(q), M_FLUSH, FLUSHRW);
1438    
1439     // Send reply
1440     DLPI_ok_ack(the_stream, q, mp, DL_UNBIND_REQ);
1441     return;
1442     }
1443    
1444    
1445     /*
1446     * Handle DL_SUBS_BIND_REQ (register 802.2 SAP group addresses and SNAPs)
1447     */
1448    
1449     static void DLPI_subs_bind(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
1450     {
1451 gbeauche 1.3 dl_subs_bind_req_t *req = (dl_subs_bind_req_t *)(void *)mp->b_rptr;
1452 cebix 1.1 uint8 *sap = ((uint8 *)req) + req->dl_subs_sap_offset;
1453     int32 length = req->dl_subs_sap_length;
1454 gbeauche 1.3 uint16 theSap = ntohs(*((uint16 *)sap));
1455 cebix 1.1 int32 error = 0;
1456     D(bug(" DLPI_subs_bind(%p,%p) SAP %02x%02x%02x%02x%02x\n", the_stream, mp, sap[0], sap[1], sap[2], sap[3], sap[4]));
1457    
1458     // Stream must be idle
1459     if (the_stream->dlpi_state != DL_IDLE) {
1460     DLPI_error_ack(the_stream, q, mp, DL_SUBS_BIND_REQ, DL_OUTSTATE, 0);
1461     return;
1462     }
1463    
1464     // Check if address is valid
1465     switch (req->dl_subs_bind_class) {
1466     case DL_PEER_BIND: // Bind a group address
1467     if (the_stream->dlsap <= kMax8022SAP) {
1468     if ((theSap & 1) && (length == sizeof(theSap)))
1469     the_stream->SetGroupSAP(theSap);
1470     else
1471     if (theSap == 0x0000) // special case to receive all 802.2 packets
1472     the_stream->flags |= kAcceptAll8022Packets;
1473     else
1474     error = DL_BADADDR;
1475     } else
1476     error = DL_UNSUPPORTED;
1477     break;
1478    
1479     case DL_HIERARCHICAL_BIND: // Bind an additional SNAP
1480     if (the_stream->dlsap == kSNAPSAP) {
1481     if (the_stream->flags & kSnapStream)
1482     error = DL_TOOMANY; // only one SNAP binding allowed
1483     else {
1484     OTCopy8022SNAP(sap, the_stream->snap);
1485     the_stream->flags |= kSnapStream;
1486     }
1487     } else
1488     error = DL_BADADDR;
1489     break;
1490    
1491     default:
1492     error = DL_UNSUPPORTED;
1493     break;
1494     }
1495     if (error) {
1496     DLPI_error_ack(the_stream, q, mp, DL_SUBS_BIND_REQ, error, 0);
1497     return;
1498     }
1499    
1500     // Allocate message block for reply
1501     mblk_t *ack_mp;
1502     if ((ack_mp = allocb(sizeof(dl_subs_bind_ack_t) + length, BPRI_HI)) == NULL) {
1503     DLPI_error_ack(the_stream, q, mp, DL_SUBS_BIND_REQ, DL_SYSERR, MAC_ENOMEM);
1504     return;
1505     }
1506    
1507     // Set up message type
1508     ack_mp->b_datap->db_type = M_PCPROTO;
1509 gbeauche 1.3 dl_subs_bind_ack_t *ackp = (dl_subs_bind_ack_t *)(void *)ack_mp->b_wptr;
1510 cebix 1.1 memset(ackp, 0, sizeof(dl_subs_bind_ack_t) + length);
1511     ackp->dl_primitive = DL_SUBS_BIND_ACK;
1512    
1513     // Fill in other fields
1514     ackp->dl_subs_sap_length = length;
1515     ackp->dl_subs_sap_offset = length ? sizeof(dl_subs_bind_ack_t) : 0;
1516     ack_mp->b_wptr += sizeof(dl_subs_bind_ack_t);
1517     if (length)
1518     memcpy(ack_mp->b_wptr, sap, length);
1519     ack_mp->b_wptr += length;
1520    
1521     // Free request
1522     freemsg(mp);
1523    
1524     // Send reply
1525     qreply(q, ack_mp);
1526     return;
1527     }
1528    
1529    
1530     /*
1531     * Handle DL_SUBS_UNBIND_REQ (unregister 802.2 SAP group addresses and snaps)
1532     */
1533    
1534     static void DLPI_subs_unbind(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
1535     {
1536 gbeauche 1.3 dl_subs_unbind_req_t *req = (dl_subs_unbind_req_t *)(void *)mp->b_rptr;
1537 cebix 1.1 uint8 *sap = ((uint8 *)req) + req->dl_subs_sap_offset;
1538     int32 length = req->dl_subs_sap_length;
1539     int32 error = 0;
1540     D(bug(" DLPI_subs_unbind(%p,%p) SAP %02x%02x%02x%02x%02x\n", the_stream, mp, sap[0], sap[1], sap[2], sap[3], sap[4]));
1541    
1542     // Stream must be idle
1543     if (the_stream->dlpi_state != DL_IDLE) {
1544     DLPI_error_ack(the_stream, q, mp, DL_SUBS_UNBIND_REQ, DL_OUTSTATE, 0);
1545     return;
1546     }
1547    
1548     // Check if we are unbinding from an address we are bound to
1549     if (length == k8022SAPLength) {
1550     if ((*sap & 1) && (*sap != kIPXSAP)) {
1551     if (the_stream->dlsap <= kMax8022SAP)
1552     the_stream->ClearGroupSAP(*sap);
1553     else
1554     error = DL_UNSUPPORTED;
1555     } else
1556     error = DL_BADADDR;
1557     } else if (length == k8022SNAPLength) {
1558     if (the_stream->dlsap == kSNAPSAP) {
1559     if (the_stream->flags & kSnapStream) {
1560     if (memcmp(the_stream->snap, sap, length) != 0)
1561     error = DL_BADADDR;
1562     } else
1563     error = DL_BADADDR;
1564     } else
1565     error = DL_UNSUPPORTED;
1566     }
1567     if (error) {
1568     DLPI_error_ack(the_stream, q, mp, DL_SUBS_UNBIND_REQ, error, 0);
1569     return;
1570     }
1571    
1572     // Stream is no longer bound to SNAP
1573     the_stream->flags &= ~kSnapStream;
1574    
1575     // Send reply
1576     DLPI_ok_ack(the_stream, q, mp, DL_SUBS_UNBIND_REQ);
1577     return;
1578     }
1579    
1580    
1581     /*
1582     * Handles DL_ENABMULTI_REQ (enable multicast address)
1583     */
1584    
1585     static void DLPI_enable_multi(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
1586     {
1587 gbeauche 1.3 dl_enabmulti_req_t* req = (dl_enabmulti_req_t*)(void *)mp->b_rptr;
1588 cebix 1.1 uint8 *reqaddr = (uint8 *)(mp->b_rptr + req->dl_addr_offset);
1589     D(bug(" DLPI_enable_multi(%p,%p) addr %02x%02x%02x%02x%02x%02x\n", the_stream, mp, reqaddr[0], reqaddr[1], reqaddr[2], reqaddr[3], reqaddr[4], reqaddr[5]));
1590    
1591     // Address must be a multicast address
1592     if (get_address_type(reqaddr) != keaMulticast) {
1593     DLPI_error_ack(the_stream, q, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0);
1594     return;
1595     }
1596    
1597     // Address already in multicast list?
1598     if (the_stream->IsMulticastRegistered(reqaddr)) {
1599     DLPI_error_ack(the_stream, q, mp, DL_ENABMULTI_REQ, DL_BADADDR, 0);
1600     return;
1601     }
1602    
1603     // Tell add-on to enable multicast address
1604 gbeauche 1.8 AO_enable_multicast(Host2MacAddr((uint8 *)reqaddr));
1605 cebix 1.1
1606     // Add new address to multicast list
1607 gbeauche 1.6 uint8 *addr = Mac2HostAddr(Mac_sysalloc(kEnetPhysicalAddressLength));
1608 cebix 1.1 OTCopy48BitAddress(reqaddr, addr);
1609     the_stream->AddMulticast(addr);
1610    
1611     // On receive now check multicast packets
1612     the_stream->flags |= kAcceptMulticasts;
1613    
1614     // Send reply
1615     DLPI_ok_ack(the_stream, q, mp, DL_ENABMULTI_REQ);
1616     return;
1617     }
1618    
1619    
1620     /*
1621     * Handles DL_DISABMULTI_REQ (disable multicast address)
1622     */
1623    
1624     static void DLPI_disable_multi(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
1625     {
1626 gbeauche 1.3 dl_disabmulti_req_t *req = (dl_disabmulti_req_t*)(void *)mp->b_rptr;
1627 cebix 1.1 uint8 *reqaddr = (uint8 *)(mp->b_rptr + req->dl_addr_offset);
1628     D(bug(" DLPI_disable_multi(%p,%p) addr %02x%02x%02x%02x%02x%02x\n", the_stream, mp, reqaddr[0], reqaddr[1], reqaddr[2], reqaddr[3], reqaddr[4], reqaddr[5]));
1629    
1630     // Address must be a multicast address
1631     if (get_address_type(reqaddr) != keaMulticast) {
1632     DLPI_error_ack(the_stream, q, mp, DL_DISABMULTI_REQ, DL_BADADDR, 0);
1633     return;
1634     }
1635    
1636     // Find address in multicast list
1637     uint8 *addr = the_stream->IsMulticastRegistered(reqaddr);
1638     if (addr == NULL) {
1639     DLPI_error_ack(the_stream, q, mp, DL_DISABMULTI_REQ, DL_BADADDR, 0);
1640     return;
1641     }
1642    
1643     // Found, then remove
1644     the_stream->RemoveMulticast(addr);
1645 gbeauche 1.6 Mac_sysfree(Host2MacAddr(addr));
1646 cebix 1.1
1647     // Tell add-on to disable multicast address
1648 gbeauche 1.8 AO_disable_multicast(Host2MacAddr((uint8 *)reqaddr));
1649 cebix 1.1
1650     // No longer check multicast packets if no multicast addresses are registered
1651     if (the_stream->multicast_list == NULL)
1652     the_stream->flags &= ~kAcceptMulticasts;
1653    
1654     // Send reply
1655     DLPI_ok_ack(the_stream, q, mp, DL_DISABMULTI_REQ);
1656     return;
1657     }
1658    
1659    
1660     /*
1661     * Handle DL_UNITDATA_REQ (transmit packet)
1662     */
1663    
1664     static void DLPI_unit_data(DLPIStream *the_stream, queue_t *q, mblk_t *mp)
1665     {
1666     D(bug(" DLPI_unit_data(%p,%p)\n", the_stream, mp));
1667 gbeauche 1.3 dl_unitdata_req_t *req = (dl_unitdata_req_t *)(void *)mp->b_rptr;
1668 cebix 1.1
1669     // Stream must be idle
1670     if (the_stream->dlpi_state != DL_IDLE) {
1671    
1672     // Not idle, send error response
1673     dl_uderror_ind_t *errp;
1674     mblk_t *bp;
1675    
1676     int i = sizeof(dl_uderror_ind_t) + req->dl_dest_addr_length;
1677     if ((bp = allocb(i, BPRI_HI)) == NULL) {
1678     freemsg(mp);
1679     return;
1680     }
1681     bp->b_datap->db_type = M_PROTO;
1682 gbeauche 1.3 errp = (dl_uderror_ind_t *)(void *)bp->b_wptr;
1683 cebix 1.1 errp->dl_primitive = DL_UDERROR_IND;
1684     errp->dl_errno = DL_OUTSTATE;
1685     errp->dl_unix_errno = 0;
1686     errp->dl_dest_addr_length = req->dl_dest_addr_length;
1687     errp->dl_dest_addr_offset = sizeof(dl_uderror_ind_t);
1688     bp->b_wptr += sizeof(dl_uderror_ind_t);
1689     memcpy((uint8 *)bp->b_wptr, ((uint8 *)req) + req->dl_dest_addr_offset, req->dl_dest_addr_length);
1690     bp->b_wptr += req->dl_dest_addr_length;
1691     qreply(q, bp);
1692    
1693     freemsg(mp);
1694     return;
1695     }
1696    
1697     // Build packet header and transmit packet
1698     if ((mp = build_tx_packet_header(the_stream, mp, false)) != NULL)
1699     transmit_packet(mp);
1700     }
1701 gbeauche 1.8
1702    
1703     /*
1704     * Ethernet packet allocator
1705     */
1706    
1707     #if SIZEOF_VOID_P != 4 || REAL_ADDRESSING == 0
1708     static uint32 ether_packet = 0; // Ethernet packet (cached allocation)
1709     static uint32 n_ether_packets = 0; // Number of ethernet packets allocated so far (should be at most 1)
1710    
1711     EthernetPacket::EthernetPacket()
1712     {
1713     ++n_ether_packets;
1714     if (ether_packet && n_ether_packets == 1)
1715     packet = ether_packet;
1716     else {
1717     packet = Mac_sysalloc(1516);
1718     assert(packet != 0);
1719     Mac_memset(packet, 0, 1516);
1720     if (ether_packet == 0)
1721     ether_packet = packet;
1722     }
1723     }
1724    
1725     EthernetPacket::~EthernetPacket()
1726     {
1727     --n_ether_packets;
1728     if (packet != ether_packet)
1729     Mac_sysfree(packet);
1730     if (n_ether_packets > 0) {
1731     bug("WARNING: Nested allocation of ethernet packets!\n");
1732     }
1733     }
1734     #endif