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

# Content
1 /*
2 * ether.cpp - SheepShaver Ethernet Device Driver (DLPI)
3 *
4 * SheepShaver (C) 1997-2008 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 /*
22 * TODO
23 * - 802.2 TEST/XID
24 * - MIB statistics
25 */
26
27 #include <string.h>
28
29 #include "sysdeps.h"
30 #include "cpu_emulation.h"
31 #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 nw_multicast_node_p next;
59 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 multicast_node *n = (multicast_node *)Mac2HostAddr(Mac_sysalloc(sizeof(multicast_node)));
87 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 Mac_sysfree(Host2MacAddr((uint8 *)p));
107 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 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 };
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 static nw_DLPIStream_p dlpi_stream_list;
150 static DLPIStreamInit dlpi_stream_init(&dlpi_stream_list);
151
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 return (mblk_t *)Mac2HostAddr((uint32)CallMacOS2(allocb_ptr, allocb_tvect, arg1, arg2));
181 }
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 return (mblk_t *)Mac2HostAddr((uint32)CallMacOS1(copyb_ptr, copyb_tvect, arg1));
199 }
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 return (mblk_t *)Mac2HostAddr((uint32)CallMacOS1(dupmsg_ptr, dupmsg_tvect, arg1));
205 }
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 return (mblk_t *)Mac2HostAddr((uint32)CallMacOS1(getq_ptr, getq_tvect, arg1));
211 }
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 return (DLPIStream *)Mac2HostAddr((uint32)CallMacOS1(mi_next_ptr_ptr, mi_next_ptr_tvect, arg1));
283 }
284 #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
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 static uint8 InitStreamModuleImpl(void *theID)
312 {
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 allocb_tvect = FindLibSymbol("\013OTKernelLib", "\006allocb");
322 D(bug("allocb TVECT at %08lx\n", allocb_tvect));
323 if (allocb_tvect == 0)
324 return false;
325 freeb_tvect = FindLibSymbol("\013OTKernelLib", "\005freeb");
326 D(bug("freeb TVECT at %08lx\n", freeb_tvect));
327 if (freeb_tvect == 0)
328 return false;
329 freemsg_tvect = FindLibSymbol("\013OTKernelLib", "\007freemsg");
330 D(bug("freemsg TVECT at %08lx\n", freemsg_tvect));
331 if (freemsg_tvect == 0)
332 return false;
333 copyb_tvect = FindLibSymbol("\013OTKernelLib", "\005copyb");
334 D(bug("copyb TVECT at %08lx\n", copyb_tvect));
335 if (copyb_tvect == 0)
336 return false;
337 dupmsg_tvect = FindLibSymbol("\013OTKernelLib", "\006dupmsg");
338 D(bug("dupmsg TVECT at %08lx\n", dupmsg_tvect));
339 if (dupmsg_tvect == 0)
340 return false;
341 getq_tvect = FindLibSymbol("\013OTKernelLib", "\004getq");
342 D(bug("getq TVECT at %08lx\n", getq_tvect));
343 if (getq_tvect == 0)
344 return false;
345 putq_tvect = FindLibSymbol("\013OTKernelLib", "\004putq");
346 D(bug("putq TVECT at %08lx\n", putq_tvect));
347 if (putq_tvect == 0)
348 return false;
349 putnext_tvect = FindLibSymbol("\013OTKernelLib", "\007putnext");
350 D(bug("putnext TVECT at %08lx\n", putnext_tvect));
351 if (putnext_tvect == 0)
352 return false;
353 putnextctl1_tvect = FindLibSymbol("\013OTKernelLib", "\013putnextctl1");
354 D(bug("putnextctl1 TVECT at %08lx\n", putnextctl1_tvect));
355 if (putnextctl1_tvect == 0)
356 return false;
357 canputnext_tvect = FindLibSymbol("\013OTKernelLib", "\012canputnext");
358 D(bug("canputnext TVECT at %08lx\n", canputnext_tvect));
359 if (canputnext_tvect == 0)
360 return false;
361 qreply_tvect = FindLibSymbol("\013OTKernelLib", "\006qreply");
362 D(bug("qreply TVECT at %08lx\n", qreply_tvect));
363 if (qreply_tvect == 0)
364 return false;
365 flushq_tvect = FindLibSymbol("\013OTKernelLib", "\006flushq");
366 D(bug("flushq TVECT at %08lx\n", flushq_tvect));
367 if (flushq_tvect == 0)
368 return false;
369 msgdsize_tvect = FindLibSymbol("\013OTKernelLib", "\010msgdsize");
370 D(bug("msgdsize TVECT at %08lx\n", msgdsize_tvect));
371 if (msgdsize_tvect == 0)
372 return false;
373 otenterint_tvect = FindLibSymbol("\017OTKernelUtilLib", "\020OTEnterInterrupt");
374 D(bug("OTEnterInterrupt TVECT at %08lx\n", otenterint_tvect));
375 if (otenterint_tvect == 0)
376 return false;
377 otleaveint_tvect = FindLibSymbol("\017OTKernelUtilLib", "\020OTLeaveInterrupt");
378 D(bug("OTLeaveInterrupt TVECT at %08lx\n", otleaveint_tvect));
379 if (otleaveint_tvect == 0)
380 return false;
381 mi_open_comm_tvect = FindLibSymbol("\013OTKernelLib", "\014mi_open_comm");
382 D(bug("mi_open_comm TVECT at %08lx\n", mi_open_comm_tvect));
383 if (mi_open_comm_tvect == 0)
384 return false;
385 mi_close_comm_tvect = FindLibSymbol("\013OTKernelLib", "\015mi_close_comm");
386 D(bug("mi_close_comm TVECT at %08lx\n", mi_close_comm_tvect));
387 if (mi_close_comm_tvect == 0)
388 return false;
389 mi_next_ptr_tvect = FindLibSymbol("\013OTKernelLib", "\013mi_next_ptr");
390 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 #ifndef USE_ETHER_FULL_DRIVER
395 // Initialize stream list (which might be leftover)
396 dlpi_stream_list = NULL;
397
398 // Ask add-on for ethernet hardware address
399 AO_get_ethernet_address(Host2MacAddr(hardware_address));
400 #endif
401
402 // Yes, we're open
403 ether_driver_opened = true;
404 return true;
405 }
406
407 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
431 /*
432 * Terminate ethernet stream module
433 */
434
435 static void TerminateStreamModuleImpl(void)
436 {
437 D(bug("TerminateStreamModule\n"));
438
439 #ifndef USE_ETHER_FULL_DRIVER
440 // 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 #endif
444
445 // Sorry, we're closed
446 ether_driver_opened = false;
447 }
448
449 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
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 int err = mi_open_comm((DLPIStream **)&dlpi_stream_list, sizeof(DLPIStream), rdq, dev, flag, sflag, creds);
482 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 AO_disable_multicast(Host2MacAddr(the_stream->multicast_list->addr));
519 the_stream->RemoveMulticast(the_stream->multicast_list->addr);
520 }
521 the_stream->multicast_list = NULL;
522
523 // Delete the DLPIStream
524 return mi_close_comm((DLPIStream **)&dlpi_stream_list, rdq);
525 }
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 D(bug(" db_type %d\n", (int)mp->b_datap->db_type));
548 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 union DL_primitives *dlp = (union DL_primitives *)(void *)mp->b_rptr;
560 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 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
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 uint32 framing_type = ntohl(*(uint32 *)(void *)info_mp->b_rptr);
665 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 dlrc = (dl_recv_control_t *)(void *)info_mp->b_rptr;
712 D(bug(" I_OTSetRawMode primitive %d\n", (int)dlrc->dl_primitive));
713 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 dl_unitdata_req_t *req = (dl_unitdata_req_t *)(void *)mp->b_rptr;
846 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 dlsap = ntohs(*(uint16 *)(destAddrOrig + kEnetPhysicalAddressLength));
864 break;
865 case kEnetPhysicalAddressLength + k8022DLSAPLength + k8022SNAPLength: // SNAP SAP
866 dlsap = ntohs(*(uint16 *)(destAddrOrig + kEnetPhysicalAddressLength));
867 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 struct T8022FullPacketHeader *packetHeader = (struct T8022FullPacketHeader *)(void *)mp->b_rptr;
919
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 EnetPacketHeader *enetHeader = (EnetPacketHeader *)(void *)mp->b_rptr;
959
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 AO_transmit_packet(Host2MacAddr((uint8 *)mp));
969 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 dl_unitdata_ind_t *ind = (dl_unitdata_ind_t*)(void *)nmp->b_rptr;
1016 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 T8022FullPacketHeader *packetHeader = (T8022FullPacketHeader *)(void *)mp->b_rptr;
1033 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 EnetPacketHeader *pkt = (EnetPacketHeader *)(void *)mp->b_rptr;
1065 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 void ether_dispatch_packet(uint32 p, uint32 size)
1141 {
1142 #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 // 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 #endif
1161 }
1162
1163
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 dl_error_ack_t *errp = (dl_error_ack_t *)(void *)ack_mp->b_wptr;
1180 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 dl_ok_ack_t *ackp = (dl_ok_ack_t *)(void *)ack_mp->b_rptr;
1210 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 dl_info_ack_t *ackp = (dl_info_ack_t *)(void *)ack_mp->b_rptr;
1250 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 dl_phys_addr_req_t *req = (dl_phys_addr_req_t *)(void *)mp->b_rptr;
1302
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 dl_phys_addr_ack_t *ackp = (dl_phys_addr_ack_t *)(void *)ack_mp->b_wptr;
1313 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 dl_bind_req_t *req = (dl_bind_req_t *)(void *)mp->b_rptr;
1342 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 dl_bind_ack_t *ackp = (dl_bind_ack_t *)(void *)ack_mp->b_rptr;
1379 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 dl_subs_bind_req_t *req = (dl_subs_bind_req_t *)(void *)mp->b_rptr;
1452 uint8 *sap = ((uint8 *)req) + req->dl_subs_sap_offset;
1453 int32 length = req->dl_subs_sap_length;
1454 uint16 theSap = ntohs(*((uint16 *)sap));
1455 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 dl_subs_bind_ack_t *ackp = (dl_subs_bind_ack_t *)(void *)ack_mp->b_wptr;
1510 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 dl_subs_unbind_req_t *req = (dl_subs_unbind_req_t *)(void *)mp->b_rptr;
1537 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 dl_enabmulti_req_t* req = (dl_enabmulti_req_t*)(void *)mp->b_rptr;
1588 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 AO_enable_multicast(Host2MacAddr((uint8 *)reqaddr));
1605
1606 // Add new address to multicast list
1607 uint8 *addr = Mac2HostAddr(Mac_sysalloc(kEnetPhysicalAddressLength));
1608 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 dl_disabmulti_req_t *req = (dl_disabmulti_req_t*)(void *)mp->b_rptr;
1627 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 Mac_sysfree(Host2MacAddr(addr));
1646
1647 // Tell add-on to disable multicast address
1648 AO_disable_multicast(Host2MacAddr((uint8 *)reqaddr));
1649
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 dl_unitdata_req_t *req = (dl_unitdata_req_t *)(void *)mp->b_rptr;
1668
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 errp = (dl_uderror_ind_t *)(void *)bp->b_wptr;
1683 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
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