add option for classic magicmenu "mixed" menu style (pull donw on screen title, pop...
[AROS.git] / rom / usb / classes / rndis / rndis.class.c
blob382481343e45528d2b281adc0affcea05346a02f
1 /*
2 * $Id$
3 */
5 #include "debug.h"
7 #include "rndis.class.h"
9 /* /// "Lib Stuff" */
10 static const STRPTR libname = MOD_NAME_STRING;
12 static
13 const APTR DevFuncTable[] =
15 &AROS_SLIB_ENTRY(devOpen, dev, 1),
16 &AROS_SLIB_ENTRY(devClose, dev, 2),
17 &AROS_SLIB_ENTRY(devExpunge, dev, 3),
18 &AROS_SLIB_ENTRY(devReserved, dev, 4),
19 &AROS_SLIB_ENTRY(devBeginIO, dev, 5),
20 &AROS_SLIB_ENTRY(devAbortIO, dev, 6),
21 (APTR) -1,
24 static int libInit(LIBBASETYPEPTR nh)
26 struct NepClassEth *ncp;
27 struct NepEthBase *ret = NULL;
29 KPRINTF(10, ("libInit nh: 0x%08lx SysBase: 0x%08lx\n", nh, SysBase));
31 nh->nh_UtilityBase = OpenLibrary("utility.library", 39);
33 #define UtilityBase nh->nh_UtilityBase
35 if(UtilityBase)
37 NewList(&nh->nh_Units);
39 if((nh->nh_DevBase = (struct NepEthDevBase *) MakeLibrary((APTR) DevFuncTable, NULL, (APTR) devInit,
40 sizeof(struct NepEthDevBase), NULL)))
42 ncp = &nh->nh_DummyNCP;
43 ncp->ncp_ClsBase = nh;
44 ncp->ncp_Interface = NULL;
45 ncp->ncp_CDC = AllocVec(sizeof(struct ClsDevCfg), MEMF_PUBLIC|MEMF_CLEAR);
46 if(ncp->ncp_CDC)
48 nh->nh_DevBase->np_ClsBase = nh;
49 Forbid();
50 AddDevice((struct Device *) nh->nh_DevBase);
51 nh->nh_DevBase->np_Library.lib_OpenCnt++;
52 Permit();
53 ret = nh;
55 } else {
56 KPRINTF(20, ("failed to create usbrndis.device\n"));
58 if(!ret)
60 CloseLibrary(UtilityBase);
62 } else {
63 KPRINTF(20, ("libInit: OpenLibrary(\"utility.library\", 39) failed!\n"));
66 KPRINTF(10, ("libInit: Ok\n"));
67 return(ret ? TRUE : FALSE);
71 static int libExpunge(LIBBASETYPEPTR nh)
73 struct NepClassEth *ncp;
75 KPRINTF(10, ("libExpunge nh: 0x%08lx\n", nh));
77 if(nh->nh_DevBase->np_Library.lib_OpenCnt == 1)
79 KPRINTF(1, ("libExpunge: closelibrary utilitybase 0x%08lx\n",
80 UtilityBase));
81 CloseLibrary((struct Library *) UtilityBase);
83 ncp = (struct NepClassEth *) nh->nh_Units.lh_Head;
84 while(ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ)
86 Remove((struct Node *) ncp);
87 FreeVec(ncp->ncp_CDC);
88 FreeVec(ncp);
89 ncp = (struct NepClassEth *) nh->nh_Units.lh_Head;
92 nh->nh_DevBase->np_Library.lib_OpenCnt--;
93 RemDevice((struct Device *) nh->nh_DevBase);
95 KPRINTF(5, ("libExpunge: Unloading done! rndis.class expunged!\n\n"));
96 } else {
97 KPRINTF(5, ("libExpunge: Could not expunge, LIBF_DELEXP set!\n"));
98 return(FALSE);
101 return(TRUE);
104 ADD2INITLIB(libInit, 0)
105 ADD2EXPUNGELIB(libExpunge, 0)
106 /* \\\ */
110 * ***********************************************************************
111 * * Library functions *
112 * ***********************************************************************
115 struct AutoBindData
117 UWORD abd_VendID;
118 UWORD abd_ProdID;
122 struct AutoBindData ClassBinds[] =
124 { 0x0bb4, 0x0ffe }, // HTC , Android phone
125 //{ 0x12d1, 0x1039 }, // Huawei u8800
126 { 0, 0 }
129 /* /// "usbAttemptDeviceBinding()" */
130 struct NepClassEth * usbAttemptDeviceBinding(struct NepEthBase *nh, struct PsdDevice *pd)
132 struct Library *ps;
133 struct AutoBindData *abd = ClassBinds;
134 struct PsdInterface *pif;
135 IPTR prodid;
136 IPTR vendid;
137 IPTR ifclass;
138 IPTR subclass;
139 IPTR proto;
141 KPRINTF(1, ("nepEthAttemptDeviceBinding(%08lx)\n", pd));
143 if((ps = OpenLibrary("poseidon.library", 4)))
145 psdGetAttrs(PGA_DEVICE, pd,
146 DA_VendorID, &vendid,
147 DA_ProductID, &prodid,
148 TAG_END);
150 if( (pif = psdFindInterface(pd, NULL,TAG_END)) ){
151 psdGetAttrs(PGA_INTERFACE, pif,
152 IFA_Class, &ifclass,
153 IFA_SubClass, &subclass,
154 IFA_Protocol, &proto,
155 TAG_DONE);
157 if (ifclass == 224 && // WIRELESS
158 subclass == 1 && // RF
159 proto == 3) // RNDIS
161 CloseLibrary(ps);
162 return(usbForceDeviceBinding(nh, pd));
166 while(abd->abd_VendID)
168 if((vendid == abd->abd_VendID) && (prodid == abd->abd_ProdID))
170 CloseLibrary(ps);
171 return(usbForceDeviceBinding(nh, pd));
173 abd++;
177 return(NULL);
179 /* \\\ */
181 /* /// "usbForceDeviceBinding()" */
182 struct NepClassEth * usbForceDeviceBinding(struct NepEthBase *nh, struct PsdDevice *pd)
184 struct Library *ps;
185 struct NepClassEth *ncp;
186 struct NepClassEth *tmpncp;
187 struct ClsDevCfg *cdc;
188 STRPTR devname;
189 STRPTR devidstr;
190 IPTR prodid;
191 IPTR vendid;
192 ULONG unitno;
193 BOOL unitfound;
194 UBYTE buf[64];
196 KPRINTF(1, ("nepEthForceDeviceBinding(%08lx)\n", pd));
198 if((ps = OpenLibrary("poseidon.library", 4)))
200 psdGetAttrs(PGA_DEVICE, pd,
201 DA_ProductID, &prodid,
202 DA_VendorID, &vendid,
203 DA_ProductName, &devname,
204 DA_IDString, &devidstr,
205 TAG_END);
206 Forbid();
208 unitfound = FALSE;
209 unitno = (ULONG) -1;
210 ncp = (struct NepClassEth *) nh->nh_Units.lh_Head;
211 while(ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ)
213 if(!strcmp(ncp->ncp_DevIDString, devidstr))
215 unitno = ncp->ncp_UnitNo;
216 unitfound = TRUE;
217 break;
219 ncp = (struct NepClassEth *) ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ;
221 if(!unitfound)
223 /* as units are freed in the expunge-vector, the memory is
224 outside the scope of the poseidon library */
225 if(!(ncp = AllocVec(sizeof(struct NepClassEth), MEMF_PUBLIC|MEMF_CLEAR)))
227 Permit();
228 CloseLibrary(ps);
229 return(NULL);
231 ncp->ncp_CDC = cdc = AllocVec(sizeof(struct ClsDevCfg), MEMF_PUBLIC|MEMF_CLEAR);
232 if(!cdc)
234 Permit();
235 FreeVec(ncp);
236 CloseLibrary(ps);
237 return(NULL);
239 /* IORequests may be queued even if the task is gone. */
240 ncp->ncp_UnitNo = (ULONG) -1;
241 NewList(&ncp->ncp_Unit.unit_MsgPort.mp_MsgList);
242 NewList(&ncp->ncp_OrphanQueue);
243 NewList(&ncp->ncp_WriteQueue);
244 NewList(&ncp->ncp_BufManList);
245 NewList(&ncp->ncp_EventList);
246 NewList(&ncp->ncp_TrackList);
247 NewList(&ncp->ncp_Multicasts);
248 strncpy(ncp->ncp_DevIDString, devidstr, 127);
249 AddTail(&nh->nh_Units, &ncp->ncp_Unit.unit_MsgPort.mp_Node);
251 ncp->ncp_ClsBase = nh;
252 ncp->ncp_Device = pd;
253 ncp->ncp_UnitProdID = prodid;
254 ncp->ncp_UnitVendorID = vendid;
256 //nLoadBindingConfig(ncp);
258 /* Find next free unit number */
259 if(unitno == (ULONG) -1)
261 unitno = ncp->ncp_CDC->cdc_DefaultUnit;
262 tmpncp = (struct NepClassEth *) nh->nh_Units.lh_Head;
263 while(tmpncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ)
265 if(tmpncp->ncp_UnitNo == unitno)
267 unitno++;
268 tmpncp = (struct NepClassEth *) nh->nh_Units.lh_Head;
269 } else {
270 tmpncp = (struct NepClassEth *) tmpncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Succ;
274 ncp->ncp_UnitNo = unitno;
275 Permit();
277 psdSafeRawDoFmt(buf, 64, "rndis.class<%08lx>", ncp);
278 ncp->ncp_ReadySignal = SIGB_SINGLE;
279 ncp->ncp_ReadySigTask = FindTask(NULL);
280 SetSignal(0, SIGF_SINGLE);
281 if(psdSpawnSubTask(buf, nEthTask, ncp))
283 Wait(1L<<ncp->ncp_ReadySignal);
284 if(ncp->ncp_Task)
286 ncp->ncp_ReadySigTask = NULL;
287 //FreeSignal(ncp->ncp_ReadySignal);
288 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
289 "Mr. Data linked '%s' to %s unit %ld!",
290 devname, nh->nh_DevBase->np_Library.lib_Node.ln_Name,
291 ncp->ncp_UnitNo);
293 CloseLibrary(ps);
294 return(ncp);
297 ncp->ncp_ReadySigTask = NULL;
298 //FreeSignal(ncp->ncp_ReadySignal);
299 /* Get rid of unit structure */
300 /*Forbid();
301 Remove((struct Node *) ncp);
302 FreeVec(ncp->ncp_CDC);
303 FreeVec(ncp);
304 Permit();*/
305 CloseLibrary(ps);
307 return(NULL);
309 /* \\\ */
311 /* /// "usbReleaseDeviceBinding()" */
312 void usbReleaseDeviceBinding(struct NepEthBase *nh, struct NepClassEth *ncp)
314 struct Library *ps;
315 STRPTR devname;
316 KPRINTF(1, ("nepEthReleaseDeviceBinding(%08lx)\n", ncp));
318 if((ps = OpenLibrary("poseidon.library", 4)))
320 Forbid();
321 ncp->ncp_ReadySignal = SIGB_SINGLE;
322 ncp->ncp_ReadySigTask = FindTask(NULL);
323 if(ncp->ncp_Task)
325 Signal(ncp->ncp_Task, SIGBREAKF_CTRL_C);
327 Permit();
328 while(ncp->ncp_Task)
330 Wait(1L<<ncp->ncp_ReadySignal);
332 //FreeSignal(ncp->ncp_ReadySignal);
333 psdGetAttrs(PGA_DEVICE, ncp->ncp_Device, DA_ProductName, &devname, TAG_END);
334 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
335 "Shrinkwrapped and wasted '%s'.",
336 devname);
337 /*psdFreeVec(ncp);*/
338 CloseLibrary(ps);
341 /* \\\ */
343 /* /// "usbGetAttrsA()" */
344 AROS_LH3(LONG, usbGetAttrsA,
345 AROS_LHA(ULONG, type, D0),
346 AROS_LHA(APTR, usbstruct, A0),
347 AROS_LHA(struct TagItem *, tags, A1),
348 LIBBASETYPEPTR, nh, 5, nep)
350 AROS_LIBFUNC_INIT
352 struct TagItem *ti;
353 LONG count = 0;
355 KPRINTF(1, ("nepEthGetAttrsA(%ld, %08lx, %08lx)\n", type, usbstruct, tags));
356 switch(type)
358 case UGA_CLASS:
359 if((ti = FindTagItem(UCCA_Priority, tags)))
361 *((SIPTR *) ti->ti_Data) = -100;
362 count++;
364 if((ti = FindTagItem(UCCA_Description, tags)))
366 *((STRPTR *) ti->ti_Data) = "Ethernet SANA wrapper for RNDIS devices via usbrndis.device";
367 count++;
369 if((ti = FindTagItem(UCCA_HasClassCfgGUI, tags)))
371 *((IPTR *) ti->ti_Data) = TRUE;
372 count++;
374 if((ti = FindTagItem(UCCA_HasBindingCfgGUI, tags)))
376 *((IPTR *) ti->ti_Data) = TRUE;
377 count++;
379 if((ti = FindTagItem(UCCA_AfterDOSRestart, tags)))
381 *((IPTR *) ti->ti_Data) = FALSE;
382 count++;
384 if((ti = FindTagItem(UCCA_UsingDefaultCfg, tags)))
386 *((IPTR *) ti->ti_Data) = nh->nh_DummyNCP.ncp_UsingDefaultCfg;
387 count++;
389 break;
391 case UGA_BINDING:
392 if((ti = FindTagItem(UCBA_UsingDefaultCfg, tags)))
394 *((IPTR *) ti->ti_Data) = ((struct NepClassEth *) usbstruct)->ncp_UsingDefaultCfg;
395 count++;
397 break;
399 return(count);
400 AROS_LIBFUNC_EXIT
402 /* \\\ */
404 /* /// "usbSetAttrsA()" */
405 AROS_LH3(LONG, usbSetAttrsA,
406 AROS_LHA(ULONG, type, D0),
407 AROS_LHA(APTR, usbstruct, A0),
408 AROS_LHA(struct TagItem *, tags, A1),
409 LIBBASETYPEPTR, nh, 6, nep)
411 AROS_LIBFUNC_INIT
412 return(0);
413 AROS_LIBFUNC_EXIT
415 /* \\\ */
417 /* /// "usbDoMethodA()" */
418 AROS_LH2(IPTR, usbDoMethodA,
419 AROS_LHA(ULONG, methodid, D0),
420 AROS_LHA(IPTR *, methoddata, A1),
421 LIBBASETYPEPTR, nh, 7, nep)
423 AROS_LIBFUNC_INIT
424 KPRINTF(10, ("Do Method %ld\n", methodid));
425 switch(methodid)
427 case UCM_AttemptDeviceBinding:
428 return((IPTR) usbAttemptDeviceBinding(nh, (struct PsdDevice *) methoddata[0]));
430 case UCM_ForceDeviceBinding:
431 return((IPTR) usbForceDeviceBinding(nh, (struct PsdDevice *) methoddata[0]));
433 case UCM_ReleaseDeviceBinding:
434 usbReleaseDeviceBinding(nh, (struct NepClassEth *) methoddata[0]);
435 return(TRUE);
437 default:
438 break;
440 return(0);
441 AROS_LIBFUNC_EXIT
443 /* \\\ */
445 /**************************************************************************/
447 #undef ps
448 #define ps ncp->ncp_Base
450 /* /// "nEthTask()" */
451 AROS_UFH0(void, nEthTask)
453 AROS_USERFUNC_INIT
455 struct NepClassEth *ncp;
456 struct PsdPipe *pp;
457 ULONG sigmask;
458 ULONG sigs;
459 LONG ioerr;
460 UBYTE *pktptr;
461 ULONG pktlen;
462 UWORD cnt;
463 LONG lastioerr = 0;
464 ULONG errcount = 0;
466 struct IOSana2Req *ioreq;
468 if((ncp = nAllocEth()))
471 urndis_attach(ncp);
473 Forbid();
474 if(ncp->ncp_ReadySigTask)
476 Signal(ncp->ncp_ReadySigTask, 1L<<ncp->ncp_ReadySignal);
478 Permit();
481 /* Record start time_of_day */
482 //GetSysTime(&ncp->ncp_DeviceStats.LastStart);
483 /* Now online */
484 ncp->ncp_StateFlags |= DDF_ONLINE;
485 ncp->ncp_StateFlags &= ~DDF_OFFLINE;
486 /* Trigger any ONLINE events */
487 nDoEvent(ncp, S2EVENT_ONLINE);
490 /* Main task */
491 sigmask = (1L<<ncp->ncp_Unit.unit_MsgPort.mp_SigBit)|(1L<<ncp->ncp_TaskMsgPort->mp_SigBit)|SIGBREAKF_CTRL_C;
494 // start transmitting read request if online...
495 if((ncp->ncp_StateFlags & DDF_ONLINE) && (ncp->ncp_ReadPending == NULL))
497 ncp->ncp_ReadPending = ncp->ncp_ReadBuffer[ncp->ncp_ReadBufNum];
498 psdSendPipe(ncp->ncp_EPInPipe, ncp->ncp_ReadPending, RNDIS_BUFSZ );
499 ncp->ncp_ReadBufNum ^= 1;
501 while((pp = (struct PsdPipe *) GetMsg(ncp->ncp_TaskMsgPort)))
503 KPRINTF(1, ("Pipe back %08lx\n", pp));
504 for(cnt = 0; cnt < 2; cnt++)
506 if(pp == ncp->ncp_EPOutPipe[cnt])
508 if((ioreq = ncp->ncp_WritePending[cnt]))
510 ioerr = psdGetPipeError(pp);
511 if(ioerr)
513 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
514 "Eth transmit failed: %s (%ld)",
515 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
517 /* Trigger any tx or generic error events */
518 nDoEvent(ncp, S2EVENT_ERROR|S2EVENT_TX);
520 /* Set error code and terminate the iorequest.
521 NOTE: Can't use RC_* or deverror() this is not
522 called from devBeginIO()!
524 ioreq->ios2_DataLength = 0;
525 ioreq->ios2_Req.io_Error = S2ERR_TX_FAILURE;
526 ioreq->ios2_WireError = S2WERR_GENERIC_ERROR;
527 psdDelayMS(50);
529 ReplyMsg((struct Message *) ioreq);
530 ncp->ncp_WritePending[cnt] = NULL;
532 break;
536 if(pp == ncp->ncp_EPInPipe)
538 if((pktptr = ncp->ncp_ReadPending))
540 ioerr = psdGetPipeError(pp);
541 pktlen = psdGetPipeActual(pp);
542 KPRINTF(1, ("ReadBack with %ld bytes.\n", pktlen));
543 // interleave next packet reading ASAP.
544 if(ncp->ncp_StateFlags & DDF_ONLINE)
546 ncp->ncp_ReadPending = ncp->ncp_ReadBuffer[ncp->ncp_ReadBufNum];
547 psdSendPipe(ncp->ncp_EPInPipe, ncp->ncp_ReadPending, RNDIS_BUFSZ );
548 ncp->ncp_ReadBufNum ^= 1;
549 } else {
550 ncp->ncp_ReadPending = NULL;
552 if(ioerr)
554 if(lastioerr != ioerr)
556 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
557 "Eth receive failed: %s (%ld)",
558 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
559 errcount = 0;
560 } else {
561 errcount++;
562 if(errcount > 20)
564 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname,
565 "That's it, that device pissed me off long enough!");
566 Signal(ncp->ncp_Task, SIGBREAKF_CTRL_C);
569 lastioerr = ioerr;
570 psdDelayMS(50);
571 break;
572 } else {
573 KPRINTF(1, ("Pkt %ld received\n", pktlen));
574 urndis_decap(ncp, pktptr, pktlen);
580 Forbid();
581 while((!ncp->ncp_WritePending[ncp->ncp_WriteBufNum]) && ncp->ncp_WriteQueue.lh_Head->ln_Succ)
583 ioreq = (struct IOSana2Req *) RemHead(&ncp->ncp_WriteQueue);
584 Permit();
585 nWritePacket(ncp, ioreq);
586 Forbid();
588 Permit();
590 sigs = Wait(sigmask);
592 } while(!(sigs & SIGBREAKF_CTRL_C));
594 Forbid();
595 /* Now remove all requests still pending *anywhere* */
596 //ncp->ncp_DenyRequests = TRUE;
597 /* Current transfers */
598 for(cnt = 0; cnt < 2; cnt++)
600 if((ioreq = ncp->ncp_WritePending[cnt]))
602 KPRINTF(1, ("Aborting pending write...\n"));
603 psdAbortPipe(ncp->ncp_EPOutPipe[cnt]);
604 psdWaitPipe(ncp->ncp_EPOutPipe[cnt]);
605 ioreq->ios2_Req.io_Error = IOERR_ABORTED;
606 ReplyMsg((struct Message *) ioreq);
607 ncp->ncp_WritePending[cnt] = NULL;
610 if(ncp->ncp_ReadPending)
612 KPRINTF(1, ("Aborting pending read...\n"));
613 psdAbortPipe(ncp->ncp_EPInPipe);
614 psdWaitPipe(ncp->ncp_EPInPipe);
615 ncp->ncp_ReadPending = NULL;
617 Permit();
619 nDoEvent(ncp, S2EVENT_OFFLINE);
621 KPRINTF(20, ("Going down the river!\n"));
622 nFreeEth(ncp);
625 AROS_USERFUNC_EXIT
627 /* \\\ */
629 /* /// "nAllocEth()" */
630 struct NepClassEth * nAllocEth(void)
632 struct Task *thistask;
633 struct NepClassEth *ncp;
635 thistask = FindTask(NULL);
638 ncp = thistask->tc_UserData;
639 if(!(ncp->ncp_Base = OpenLibrary("poseidon.library", 4)))
641 Alert(AG_OpenLib);
642 break;
645 ncp->ncp_Interface = NULL;
648 ncp->ncp_Interface = psdFindInterface(ncp->ncp_Device, ncp->ncp_Interface,
649 TAG_END);
650 if(!ncp->ncp_Interface)
652 break;
654 ncp->ncp_EPIn = psdFindEndpoint(ncp->ncp_Interface, NULL,
655 EA_IsIn, TRUE,
656 EA_TransferType, USEAF_BULK,
657 TAG_END);
658 ncp->ncp_EPOut = psdFindEndpoint(ncp->ncp_Interface, NULL,
659 EA_IsIn, FALSE,
660 EA_TransferType, USEAF_BULK,
661 TAG_END);
663 } while(!(ncp->ncp_EPOut && ncp->ncp_EPIn));
666 if(!ncp->ncp_Interface)
668 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, "No interface?");
669 break;
672 if(!(ncp->ncp_EPIn && ncp->ncp_EPOut))
674 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, "IN or OUT endpoint missing!");
675 break;
678 ncp->ncp_ReadPending = NULL;
679 ncp->ncp_WritePending[0] = NULL;
680 ncp->ncp_WritePending[1] = NULL;
681 if(!(ncp->ncp_ReadBuffer[0] = AllocVec(ETHER_MAX_LEN * 4, MEMF_PUBLIC|MEMF_CLEAR)))
683 KPRINTF(1, ("Out of memory for read buffer\n"));
684 break;
686 ncp->ncp_ReadBuffer[1] = ncp->ncp_ReadBuffer[0] + ETHER_MAX_LEN;
687 ncp->ncp_WriteBuffer[0] = ncp->ncp_ReadBuffer[1] + ETHER_MAX_LEN;
688 ncp->ncp_WriteBuffer[1] = ncp->ncp_WriteBuffer[0] + ETHER_MAX_LEN;
689 ncp->ncp_Unit.unit_MsgPort.mp_SigBit = AllocSignal(-1);
690 ncp->ncp_Unit.unit_MsgPort.mp_SigTask = thistask;
691 ncp->ncp_Unit.unit_MsgPort.mp_Node.ln_Type = NT_MSGPORT;
692 ncp->ncp_Unit.unit_MsgPort.mp_Flags = PA_SIGNAL;
694 if((ncp->ncp_TaskMsgPort = CreateMsgPort()))
696 if((ncp->ncp_EP0Pipe = psdAllocPipe(ncp->ncp_Device, ncp->ncp_TaskMsgPort, NULL)))
698 if((ncp->ncp_EPOutPipe[0] = psdAllocPipe(ncp->ncp_Device, ncp->ncp_TaskMsgPort, ncp->ncp_EPOut)))
700 /* Turn off short packets */
701 psdSetAttrs(PGA_PIPE, ncp->ncp_EPOutPipe[0],
702 PPA_NoShortPackets, FALSE,
703 PPA_NakTimeout, TRUE,
704 PPA_NakTimeoutTime, 5000,
705 TAG_END);
706 if((ncp->ncp_EPOutPipe[1] = psdAllocPipe(ncp->ncp_Device, ncp->ncp_TaskMsgPort, ncp->ncp_EPOut)))
708 /* Turn off short packets */
709 psdSetAttrs(PGA_PIPE, ncp->ncp_EPOutPipe[1],
710 PPA_NoShortPackets, FALSE,
711 PPA_NakTimeout, TRUE,
712 PPA_NakTimeoutTime, 5000,
713 TAG_END);
714 if((ncp->ncp_EPInPipe = psdAllocPipe(ncp->ncp_Device, ncp->ncp_TaskMsgPort, ncp->ncp_EPIn)))
716 /* Turn off short packets */
717 psdSetAttrs(PGA_PIPE, ncp->ncp_EPInPipe,
718 PPA_NakTimeout, FALSE,
719 PPA_NakTimeoutTime, 5000,
720 PPA_AllowRuntPackets, TRUE,
721 TAG_END);
722 ncp->ncp_Task = thistask;
724 return(ncp);
726 psdFreePipe(ncp->ncp_EPOutPipe[1]);
728 psdFreePipe(ncp->ncp_EPOutPipe[0]);
730 psdFreePipe(ncp->ncp_EP0Pipe);
732 DeleteMsgPort(ncp->ncp_TaskMsgPort);
734 FreeSignal((LONG) ncp->ncp_Unit.unit_MsgPort.mp_SigBit);
735 } while(FALSE);
736 if(ncp->ncp_ReadBuffer[0])
738 FreeVec(ncp->ncp_ReadBuffer[0]);
739 ncp->ncp_ReadBuffer[0] = NULL;
741 CloseLibrary(ncp->ncp_Base);
742 Forbid();
743 ncp->ncp_Task = NULL;
744 if(ncp->ncp_ReadySigTask)
746 Signal(ncp->ncp_ReadySigTask, 1L<<ncp->ncp_ReadySignal);
748 return(NULL);
750 /* \\\ */
752 /* /// "nFreeEth()" */
753 void nFreeEth(struct NepClassEth *ncp)
755 struct IOSana2Req *ioreq;
756 Forbid();
757 /* Disable the message port, messages may still be queued */
758 ncp->ncp_Unit.unit_MsgPort.mp_SigTask = NULL;
759 ncp->ncp_Unit.unit_MsgPort.mp_Flags = PA_IGNORE;
760 FreeSignal((LONG) ncp->ncp_Unit.unit_MsgPort.mp_SigBit);
761 // get rid of all messages that still have appeared here
762 while((ioreq = (struct IOSana2Req *) GetMsg(&ncp->ncp_Unit.unit_MsgPort)))
764 ioreq->ios2_Req.io_Error = IOERR_ABORTED;
765 ReplyMsg((struct Message *) ioreq);
767 Permit();
769 psdFreePipe(ncp->ncp_EPInPipe);
770 psdFreePipe(ncp->ncp_EPOutPipe[0]);
771 psdFreePipe(ncp->ncp_EPOutPipe[1]);
772 psdFreePipe(ncp->ncp_EP0Pipe);
774 if(ncp->ncp_ReadBuffer[0])
776 FreeVec(ncp->ncp_ReadBuffer[0]);
777 ncp->ncp_ReadBuffer[0] = NULL;
780 DeleteMsgPort(ncp->ncp_TaskMsgPort);
781 CloseLibrary(ncp->ncp_Base);
782 Forbid();
783 ncp->ncp_Task = NULL;
784 if(ncp->ncp_ReadySigTask)
786 Signal(ncp->ncp_ReadySigTask, 1L<<ncp->ncp_ReadySignal);
789 /* \\\ */
791 /* /// "nDoEvent()" */
792 void nDoEvent(struct NepClassEth *ncp, ULONG events)
794 struct IOSana2Req *worknode, *nextnode;
796 KPRINTF(1, ("DoEvent events: 0x%08lx\n", events));
798 Forbid();
799 /* Process pending S2_ONEVENT requests */
800 worknode = (struct IOSana2Req *) ncp->ncp_EventList.lh_Head;
801 while((nextnode = (struct IOSana2Req *) (((struct Node *) worknode)->ln_Succ)))
803 if(worknode->ios2_WireError & events)
805 Remove(&worknode->ios2_Req.io_Message.mn_Node);
806 worknode->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
807 KPRINTF(1, ("DoEvent: returned eventreq 0x%08lx\n", worknode));
808 ReplyMsg(&worknode->ios2_Req.io_Message);
810 worknode = nextnode;
812 Permit();
814 /* \\\ */
816 /* /// "support routines" */
817 static
818 inline void *callcopy(void *routine,
819 void *from,
820 void *to,
821 ULONG len)
823 void * (*call) (APTR, APTR, ULONG) = routine;
825 return (*call) (from, to, len);
828 #define callfilter CallHookPkt
829 /* \\\ */
831 /* /// "nWritePacket()" */
832 BOOL nWritePacket(struct NepClassEth *ncp, struct IOSana2Req *ioreq)
834 ULONG packettype;
835 struct EtherPacketHeader *eph;
836 // UBYTE *packetdata;
837 UBYTE *copydest;
838 UWORD writelen;
839 struct BufMan *bufman;
840 struct Sana2PacketTypeStats *stats;
841 UBYTE *buf = ncp->ncp_WriteBuffer[ncp->ncp_WriteBufNum];
842 LONG encaplen;
844 packettype = ioreq->ios2_PacketType;
845 copydest = buf;
846 writelen = ioreq->ios2_DataLength;
847 bufman = ioreq->ios2_BufferManagement;
849 // remove RNDIS header
850 encaplen = urndis_encap(ncp, buf ,writelen +
851 (!(ioreq->ios2_Req.io_Flags & SANA2IOF_RAW) ? sizeof(struct EtherPacketHeader) : 0)
853 copydest += encaplen;
854 writelen += encaplen;
855 eph = (struct EtherPacketHeader *)copydest;
857 /* Not a raw packet? */
858 if(!(ioreq->ios2_Req.io_Flags & SANA2IOF_RAW))
860 UWORD cnt;
861 KPRINTF(10, ("RAW WRITE!\n"));
862 /* The ethernet header isn't included in the data */
863 /* Build ethernet packet header */
864 for(cnt = 0; cnt < ETHER_ADDR_SIZE; cnt++)
866 eph->eph_Dest[cnt] = ioreq->ios2_DstAddr[cnt];
867 eph->eph_Src[cnt] = ncp->ncp_MacAddress[cnt];
869 eph->eph_Type = AROS_BE2WORD(packettype);
871 /* Packet data is at txbuffer */
872 copydest += sizeof(struct EtherPacketHeader);
873 writelen += sizeof(struct EtherPacketHeader);
877 /* Dma not available, fallback to regular copy */
878 if(callcopy(bufman->bm_CopyFromBuf, copydest, ioreq->ios2_Data, ioreq->ios2_DataLength) == NULL)
880 KPRINTF(10, ("writepacket: copyfrom returned failure!\n"));
882 /* Trigger any tx, buff or generic error events */
883 nDoEvent(ncp, S2EVENT_ERROR|S2EVENT_TX|S2EVENT_BUFF);
885 /* Set error code and terminate the iorequest.
886 NOTE: Can't use RC_* or deverror() this is not
887 called from devBeginIO()! */
888 ioreq->ios2_DataLength = 0;
889 ioreq->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
890 ioreq->ios2_WireError = S2WERR_BUFF_ERROR;
891 return FALSE;
894 //bug("out %d\n",writelen);
895 KPRINTF(20, ("PktOut[%ld] %ld\n", ncp->ncp_WriteBufNum, writelen));
896 //dumpmem(buf, writelen);
898 ncp->ncp_WritePending[ncp->ncp_WriteBufNum] = ioreq;
899 psdSendPipe(ncp->ncp_EPOutPipe[ncp->ncp_WriteBufNum], buf, (ULONG) writelen);
900 ncp->ncp_WriteBufNum ^= 1;
903 if(AROS_BE2WORD(eph->eph_Type) < 1500)
905 KPRINTF(5, ("writepacket: %04lx%08lx > %04lx%08lx (IEEE802.3) len %lu, %lu bytes\n",
906 *((UWORD *) eph->eph_Src), *((ULONG *) (eph->eph_Src + 2)),
907 *((UWORD *) eph->eph_Dest), *((ULONG *) (eph->eph_Dest + 2)),
908 AROS_BE2WORD(eph->eph_Type), writelen));
909 } else {
910 KPRINTF(5, ("writepacket: %04lx%08lx > %04lx%08lx type %lu, %lu bytes\n",
911 *((UWORD *) eph->eph_Src), *((ULONG *) (eph->eph_Src + 2)),
912 *((UWORD *) eph->eph_Dest), *((ULONG *) (eph->eph_Dest + 2)),
913 AROS_BE2WORD(eph->eph_Type), writelen));
915 //dumpmem(buf, (ULONG) writelen);
918 /* Update statistics */
919 stats = FindPacketTypeStats(ncp, packettype);
920 if(stats)
922 stats->PacketsSent++;
923 stats->BytesSent += writelen;
925 ncp->ncp_DeviceStats.PacketsSent++;
927 return TRUE;
929 /* \\\ */
931 /* /// "nReadIOReq()" */
932 UWORD nReadIOReq(struct NepClassEth *ncp, struct EtherPacketHeader *eph, UWORD datasize, struct IOSana2Req *ioreq, UWORD flags)
934 LIBBASETYPEPTR nh = ncp->ncp_ClsBase;
935 UBYTE *copyfrom;
936 UWORD cnt;
938 /* Handle RAW read */
939 if(ioreq->ios2_Req.io_Flags & SANA2IOF_RAW)
941 /* ShapeShifter won't work with `sizeof(struct etherpacket_hdr)'
942 here. This is most likely because it want the RAW ethernet
943 packet checksum size (4) added to the packet size. */
944 copyfrom = (UBYTE *) eph;
945 datasize += sizeof(struct EtherPacketHeader) + 4;
946 } else {
947 copyfrom = (UBYTE *) (eph + 1);
950 /* Build up the ios2 structure enough so we can call the packet filter. */
951 ioreq->ios2_PacketType = AROS_BE2WORD(eph->eph_Type);
952 for(cnt = 0; cnt < ETHER_ADDR_SIZE; cnt++)
954 ioreq->ios2_SrcAddr[cnt] = eph->eph_Src[cnt];
955 ioreq->ios2_DstAddr[cnt] = eph->eph_Dest[cnt];
957 ioreq->ios2_DataLength = datasize;
958 /* Call the packet filter, if available. */
959 if((flags & PACKETFILTER) &&
960 (((struct BufMan *) ioreq->ios2_BufferManagement)->bm_PacketFilter) &&
961 (!callfilter(((struct BufMan *) ioreq->ios2_BufferManagement)->bm_PacketFilter,
962 ioreq, copyfrom)))
964 /* This packet got dropped! */
965 KPRINTF(7, ("readioreq: packet type %lu for ioreq 0x%08lx dropped\n",
966 AROS_BE2WORD(eph->eph_Type), ioreq));
967 return flags;
971 /* Ok, the packet didn't get dropped, set the BCAST and MCAST
972 flags according to dstaddr. */
974 /* Address == Multicast? */
975 if(ioreq->ios2_DstAddr[0] & 1)
977 /* Address == Broadcast? */
978 static const UBYTE bcast[ETHER_ADDR_SIZE] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
979 if(memcmp(bcast, ioreq->ios2_DstAddr, ETHER_ADDR_SIZE)==0)
981 ioreq->ios2_Req.io_Flags |= SANA2IOF_BCAST;
982 } else {
983 ioreq->ios2_Req.io_Flags |= SANA2IOF_MCAST;
987 /* Finally copy the packet data! */
988 if(callcopy(((struct BufMan *) ioreq->ios2_BufferManagement)->bm_CopyToBuf,
989 ioreq->ios2_Data, copyfrom, ioreq->ios2_DataLength))
992 KPRINTF(5, ("readioreq: copytobuffed packet ior 0x%08lx, %04lx%08lx < %04lx%08lx, type %lu, %lu bytes, %s%s%s\n",
993 ioreq,
994 *((UWORD *) ioreq->ios2_DstAddr), *((ULONG *) (ioreq->ios2_DstAddr + 2)),
995 *((UWORD *) ioreq->ios2_SrcAddr), *((ULONG *) (ioreq->ios2_SrcAddr + 2)),
996 ioreq->ios2_PacketType, ioreq->ios2_DataLength,
997 (ioreq->ios2_Req.io_Flags & SANA2IOF_RAW) ? "RAW " : "",
998 (ioreq->ios2_Req.io_Flags & SANA2IOF_BCAST) ? "BCAST " : "",
999 (ioreq->ios2_Req.io_Flags & SANA2IOF_MCAST) ? "MCAST " : ""));
1000 //dumpmem(copyfrom, ioreq->ios2_DataLength);
1003 /* Clear the dropped flag */
1004 flags &= ~DROPPED;
1005 } else {
1006 KPRINTF(10, ("readioreq: copyto returned failure!\n"));
1008 /* Trigger any rx, buff or generic error events */
1009 nDoEvent(ncp, S2EVENT_ERROR|S2EVENT_RX|S2EVENT_BUFF);
1011 /* Set error code.
1012 NOTE: Can't use RC_* or deverror() this is not called from devBeginIO()!
1014 ioreq->ios2_DataLength = 0;
1015 ioreq->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
1016 ioreq->ios2_WireError = S2WERR_BUFF_ERROR;
1019 /* Pull the ioreq off the list & terminate it */
1020 Forbid();
1021 Remove((struct Node *) ioreq);
1022 Permit();
1023 ReplyMsg((struct Message *) ioreq);
1024 return flags;
1026 /* \\\ */
1028 /* /// "nReadPacket()" */
1029 BOOL nReadPacket(struct NepClassEth *ncp, UBYTE *pktptr, ULONG pktlen)
1031 struct EtherPacketHeader *eph;
1032 struct BufMan *bufman;
1033 struct IOSana2Req *worknode, *nextnode;
1034 struct Sana2PacketTypeStats *stats;
1035 UWORD flags;
1036 UWORD datasize;
1038 KPRINTF(20, ("PktIn [%ld] %ld\n", ncp->ncp_ReadBufNum, pktlen));
1039 //bug("in %d\n",pktlen);
1041 if(pktlen < 14)
1043 ncp->ncp_DeviceStats.BadData++;
1044 return FALSE;
1047 ncp->ncp_DeviceStats.PacketsReceived++;
1049 eph = (struct EtherPacketHeader *) pktptr;
1050 stats = FindPacketTypeStats(ncp, (ULONG) AROS_BE2WORD(eph->eph_Type));
1051 flags = DROPPED|PACKETFILTER;
1053 /* Calculate size of the actual data */
1054 datasize = pktlen - sizeof(struct EtherPacketHeader);
1056 /* Is the packet datasize valid? */
1057 if(pktlen <= ETHER_MAX_LEN)
1059 /* Update the packet statistics */
1060 if(stats)
1062 stats->PacketsReceived++;
1063 stats->BytesReceived += datasize; /* NOTE: don't include headers */
1066 /* For each device user (bufman)
1067 NOTE: We absolutely *MUST* try to offer the packet to *all*
1068 different device users (SANA-II V2 spec requirement). */
1069 Forbid();
1070 bufman = (struct BufMan *) ncp->ncp_BufManList.lh_Head;
1071 while(((struct Node *) bufman)->ln_Succ)
1073 /* For each queued read request (ioreq) */
1074 worknode = (struct IOSana2Req *) bufman->bm_RXQueue.lh_Head;
1075 while((nextnode = (struct IOSana2Req *) (((struct Node *) worknode)->ln_Succ)))
1077 /* Check the packet type. Also handles 802.3 packets. */
1078 if((worknode->ios2_PacketType == AROS_BE2WORD(eph->eph_Type)) ||
1079 ((AROS_BE2WORD(eph->eph_Type) < 1500) && (worknode->ios2_PacketType < 1500)))
1081 flags = nReadIOReq(ncp, eph, datasize, worknode, flags);
1082 /* Break out - let other callers get the packet too */
1083 break;
1085 worknode = nextnode;
1087 bufman = (struct BufMan *) (((struct Node *) bufman)->ln_Succ);
1089 Permit();
1090 /* Now we've tried to give the packet to every CMD_READ caller.
1091 If DROPPED is set at this point no-one wanted this packet. */
1092 if(flags & DROPPED)
1094 /* So there were no outstanding CMD_READs or the packet wasn't
1095 accepted by any of them. Okay, check if we have any pending
1096 S2_READORPHAN ioreq in list and if we have return this packet
1097 with it. Note that packet filter must not be used for this
1098 time!
1100 NOTE: orphanlist is global, ie. only one caller will get the
1101 packet if multiple users have pending S2_READORPHANs.
1104 /* Process pending orphanread iorequs */
1105 Forbid();
1106 worknode = (struct IOSana2Req *) ncp->ncp_OrphanQueue.lh_Head;
1107 while((nextnode = (struct IOSana2Req *) (((struct Node *) worknode)->ln_Succ)))
1109 nReadIOReq(ncp, eph, datasize, worknode, 0);
1110 worknode = nextnode;
1112 Permit();
1113 } else {
1114 /* Packet not dropped - return ok */
1115 return TRUE;
1117 } else {
1118 KPRINTF(20, ("Pktlen %ld invalid!\n", pktlen));
1119 ncp->ncp_DeviceStats.BadData++;
1121 /* Update global dropped packet counter. */
1122 ncp->ncp_DeviceStats.UnknownTypesReceived++;
1124 /* Update dropped packet statistics. */
1125 if(stats)
1127 stats->PacketsDropped++;
1129 KPRINTF(9, ("readpacket: packet type %lu dropped\n", AROS_BE2WORD(eph->eph_Type)));
1131 /* Trigger any rx or generic error events */
1132 nDoEvent(ncp, S2EVENT_ERROR|S2EVENT_RX);
1133 return FALSE;
1135 /* \\\ */
1137 /**************************************************************************/