Documented GVF_SAVE_VAR alongside other flags, and removed a query/doubt
[AROS.git] / rom / usb / classes / rndis / if_urndis.c
blobaea737e147bc65839b68e7c463fe1041861301c4
1 /*
2 * $Id$
3 */
5 //#define DEBUG 1
6 #include "debug.h"
7 #include "rndis.class.h"
9 #define htole32(x) AROS_LONG2LE(x)
10 #define letoh32(x) AROS_LE2LONG(x)
12 #undef ps
13 #define ps ncp->ncp_Base
16 uint32_t urndis_ctrl_msg(struct NepClassEth *ncp, uint8_t rt, uint8_t r,
17 uint16_t index, uint16_t value, void *buf, size_t buflen)
20 LONG err=-1;
21 struct PsdPipe *pp;
22 struct MsgPort *mp;
24 if((mp = CreateMsgPort()))
26 if((pp = psdAllocPipe(ncp->ncp_Device, mp, NULL)))
29 psdSetAttrs(PGA_PIPE, pp,
30 PPA_NakTimeout, FALSE,
31 PPA_NakTimeoutTime, 5000,
32 PPA_AllowRuntPackets, TRUE,
33 TAG_END);
35 // bug("urndis_ctrl_msg:pipesetup( %d,%d,%d,%d,%d )\n",pp, rt, r, value, index);
36 psdPipeSetup(pp, rt, r, value, index);
37 // bug("urndis_ctrl_msg:psdDoPipe(%d,%d,%d)\n",pp, buf, buflen);
38 err = psdDoPipe(pp, buf, buflen);
39 if(err!=0){
40 bug("urndis_ctrl_msg:error %d,%s\n",err,psdNumToStr(NTS_IOERR, err, "unknown"));
42 psdFreePipe(pp);
44 DeleteMsgPort(mp);
47 return err;
51 uint32_t urndis_ctrl_send(struct NepClassEth *ncp, void *buf, size_t len)
53 LONG err;
54 LONG sc_ifaceno_ctl=0;
56 bug("urndis_ctrl_send:\n");
57 //dumpmem(buf,len);
59 err = urndis_ctrl_msg(ncp, UT_WRITE_CLASS_INTERFACE, UR_GET_STATUS, sc_ifaceno_ctl, 0, buf, len);
61 if (err != 0){
62 bug("%s:urndis_ctrl_send error %d\n",DEVNAME,err);
65 return err;
69 #define RNDIS_RESPONSE_LEN 0x400
71 struct urndis_comp_hdr *
72 urndis_ctrl_recv(struct NepClassEth *ncp)
75 struct urndis_comp_hdr *hdr;
76 char *buf;
77 LONG err;
78 LONG sc_ifaceno_ctl=0;
81 buf = psdAllocVec(RNDIS_RESPONSE_LEN);
82 if (buf == NULL) {
83 bug("%s: out of memory\n", DEVNAME);
84 return NULL;
87 err = urndis_ctrl_msg(ncp, UT_READ_CLASS_INTERFACE, UR_CLEAR_FEATURE,
88 sc_ifaceno_ctl, 0, buf, RNDIS_RESPONSE_LEN);
90 if (err != 0) {
91 bug("%s: urndis_comp_hdr error\n", DEVNAME);
92 psdFreeVec(buf);
93 return NULL;
96 hdr = (struct urndis_comp_hdr *)buf;
97 bug("%s: urndis_ctrl_recv: type 0x%x len %u\n",
98 DEVNAME,
99 hdr->rm_type,
100 letoh32(hdr->rm_len));
102 //dumpmem(buf,hdr->rm_len);
104 if (letoh32(hdr->rm_len) > RNDIS_RESPONSE_LEN) {
105 bug("%s: ctrl message error: wrong size %u > %u\n",
106 DEVNAME,
107 letoh32(hdr->rm_len),
108 RNDIS_RESPONSE_LEN);
109 psdFreeVec(buf);
110 return NULL;
113 return hdr;
117 uint32_t
118 urndis_ctrl_handle_init(struct NepClassEth *ncp,
119 const struct urndis_comp_hdr *hdr)
121 const struct urndis_init_comp *msg;
123 msg = (struct urndis_init_comp *) hdr;
125 bug("%s: urndis_ctrl_handle_init: len %u rid %u status 0x%x "
126 "ver_major %u ver_minor %u devflags 0x%x medium 0x%x pktmaxcnt %u "
127 "pktmaxsz %u align %u aflistoffset %u aflistsz %u\n",
128 DEVNAME,
129 letoh32(msg->rm_len),
130 letoh32(msg->rm_rid),
131 letoh32(msg->rm_status),
132 letoh32(msg->rm_ver_major),
133 letoh32(msg->rm_ver_minor),
134 letoh32(msg->rm_devflags),
135 letoh32(msg->rm_medium),
136 letoh32(msg->rm_pktmaxcnt),
137 letoh32(msg->rm_pktmaxsz),
138 letoh32(msg->rm_align),
139 letoh32(msg->rm_aflistoffset),
140 letoh32(msg->rm_aflistsz));
142 if (letoh32(msg->rm_status) != RNDIS_STATUS_SUCCESS) {
143 bug("%s: init failed 0x%x\n",
144 DEVNAME,
145 letoh32(msg->rm_status));
147 return letoh32(msg->rm_status);
150 if (letoh32(msg->rm_devflags) != RNDIS_DF_CONNECTIONLESS) {
151 bug("%s: wrong device type (current type: 0x%x)\n",
152 DEVNAME,
153 letoh32(msg->rm_devflags));
155 return RNDIS_STATUS_FAILURE;
158 if (letoh32(msg->rm_medium) != RNDIS_MEDIUM_802_3) {
159 bug("%s: medium not 802.3 (current medium: 0x%x)\n",
160 DEVNAME, letoh32(msg->rm_medium));
162 return RNDIS_STATUS_FAILURE;
165 ncp->sc_lim_pktsz = letoh32(msg->rm_pktmaxsz);
167 return letoh32(msg->rm_status);
171 uint32_t
172 urndis_ctrl_handle_query(struct NepClassEth *ncp,
173 const struct urndis_comp_hdr *hdr, void **buf, size_t *bufsz)
175 const struct urndis_query_comp *msg;
177 msg = (struct urndis_query_comp *) hdr;
179 bug("%s: urndis_ctrl_handle_query: len %u rid %u status 0x%x "
180 "buflen %u bufoff %u\n",
181 DEVNAME,
182 letoh32(msg->rm_len),
183 letoh32(msg->rm_rid),
184 letoh32(msg->rm_status),
185 letoh32(msg->rm_infobuflen),
186 letoh32(msg->rm_infobufoffset));
188 if (buf && bufsz) {
189 *buf = NULL;
190 *bufsz = 0;
193 if (letoh32(msg->rm_status) != RNDIS_STATUS_SUCCESS) {
194 bug("%s: query failed 0x%x\n",
195 DEVNAME,
196 letoh32(msg->rm_status));
198 return letoh32(msg->rm_status);
201 if (letoh32(msg->rm_infobuflen) + letoh32(msg->rm_infobufoffset) +
202 RNDIS_HEADER_OFFSET > letoh32(msg->rm_len)) {
203 bug("%s: ctrl message error: invalid query info "
204 "len/offset/end_position(%d/%d/%d) -> "
205 "go out of buffer limit %d\n",
206 DEVNAME,
207 letoh32(msg->rm_infobuflen),
208 letoh32(msg->rm_infobufoffset),
209 letoh32(msg->rm_infobuflen) +
210 letoh32(msg->rm_infobufoffset) + RNDIS_HEADER_OFFSET,
211 letoh32(msg->rm_len));
212 return RNDIS_STATUS_FAILURE;
215 if (buf && bufsz) {
216 *buf = psdAllocVec(letoh32(msg->rm_infobuflen));
217 if (*buf == NULL) {
218 bug("%s: out of memory\n", DEVNAME);
219 return RNDIS_STATUS_FAILURE;
220 } else {
221 char *p;
222 *bufsz = letoh32(msg->rm_infobuflen);
224 p = (char *)&msg->rm_rid;
225 p += letoh32(msg->rm_infobufoffset);
226 memcpy(*buf, p, letoh32(msg->rm_infobuflen));
230 return letoh32(msg->rm_status);
234 uint32_t
235 urndis_ctrl_set(struct NepClassEth *ncp, uint32_t oid, void *buf, size_t len)
237 struct urndis_set_req *msg;
238 uint32_t rval;
239 struct urndis_comp_hdr *hdr;
241 msg = psdAllocVec(sizeof(*msg) + len);
242 if (msg == NULL) {
243 bug("%s: out of memory\n", DEVNAME);
244 return RNDIS_STATUS_FAILURE;
247 msg->rm_type = htole32(REMOTE_NDIS_SET_MSG);
248 msg->rm_len = htole32(sizeof(*msg) + len);
249 msg->rm_rid = 0; /* XXX */
250 msg->rm_oid = htole32(oid);
251 msg->rm_infobuflen = htole32(len);
252 if (len != 0) {
253 msg->rm_infobufoffset = htole32(20);
254 memcpy((char*)msg + 20, buf, len);
255 } else
256 msg->rm_infobufoffset = 0;
257 msg->rm_devicevchdl = 0;
259 bug("%s: urndis_ctrl_set send: type %u len %u rid %u oid 0x%x "
260 "infobuflen %u infobufoffset %u devicevchdl %u\n",
261 DEVNAME,
262 letoh32(msg->rm_type),
263 letoh32(msg->rm_len),
264 letoh32(msg->rm_rid),
265 letoh32(msg->rm_oid),
266 letoh32(msg->rm_infobuflen),
267 letoh32(msg->rm_infobufoffset),
268 letoh32(msg->rm_devicevchdl));
270 rval = urndis_ctrl_send(ncp, msg, sizeof(*msg));
271 psdFreeVec(msg);
273 if (rval != RNDIS_STATUS_SUCCESS) {
274 bug("%s: set failed\n", DEVNAME);
275 return rval;
278 if ((hdr = urndis_ctrl_recv(ncp)) == NULL) {
279 bug("%s: unable to get set response\n", DEVNAME);
280 return RNDIS_STATUS_FAILURE;
282 rval = urndis_ctrl_handle(ncp, hdr, NULL, NULL);
283 if (rval != RNDIS_STATUS_SUCCESS)
284 bug("%s: set failed 0x%x\n", DEVNAME, rval);
286 return rval;
290 uint32_t
291 urndis_ctrl_handle_reset(struct NepClassEth *ncp,
292 const struct urndis_comp_hdr *hdr)
294 const struct urndis_reset_comp *msg;
295 uint32_t rval;
297 msg = (struct urndis_reset_comp *) hdr;
299 rval = letoh32(msg->rm_status);
301 bug("%s: urndis_ctrl_handle_reset: len %u status 0x%x "
302 "adrreset %u\n",
303 DEVNAME,
304 letoh32(msg->rm_len),
305 rval,
306 letoh32(msg->rm_adrreset));
308 if (rval != RNDIS_STATUS_SUCCESS) {
309 bug("%s: reset failed 0x%x\n", DEVNAME, rval);
310 return rval;
313 if (letoh32(msg->rm_adrreset) != 0) {
314 uint32_t filter;
316 filter = htole32(ncp->sc_filter);
317 rval = urndis_ctrl_set(ncp, OID_GEN_CURRENT_PACKET_FILTER,
318 &filter, sizeof(filter));
319 if (rval != RNDIS_STATUS_SUCCESS) {
320 bug("%s: unable to reset data filters\n",
321 DEVNAME);
322 return rval;
326 return rval;
330 uint32_t urndis_ctrl_handle(struct NepClassEth *ncp, struct urndis_comp_hdr *hdr,void **buf, size_t *bufsz)
332 uint32_t rval;
334 bug("%s: urndis_ctrl_handle\n", DEVNAME);
336 if (buf && bufsz) {
337 *buf = NULL;
338 *bufsz = 0;
341 switch (letoh32(hdr->rm_type)) {
342 case REMOTE_NDIS_INITIALIZE_CMPLT:
343 rval = urndis_ctrl_handle_init(ncp, hdr);
344 break;
346 case REMOTE_NDIS_QUERY_CMPLT:
347 rval = urndis_ctrl_handle_query(ncp, hdr, buf, bufsz);
348 break;
350 case REMOTE_NDIS_RESET_CMPLT:
351 rval = urndis_ctrl_handle_reset(ncp, hdr);
352 break;
354 case REMOTE_NDIS_KEEPALIVE_CMPLT:
355 case REMOTE_NDIS_SET_CMPLT:
356 rval = letoh32(hdr->rm_status);
357 break;
359 default:
360 bug("%s: ctrl message error: unknown event 0x%x\n",
361 DEVNAME, letoh32(hdr->rm_type));
362 rval = RNDIS_STATUS_FAILURE;
365 psdFreeVec(hdr);
367 return rval;
371 uint32_t
372 urndis_ctrl_query(struct NepClassEth *ncp, uint32_t oid,
373 void *qbuf, size_t qlen,
374 void **rbuf, size_t *rbufsz)
376 struct urndis_query_req *msg;
377 uint32_t rval;
378 struct urndis_comp_hdr *hdr;
380 msg = psdAllocVec(sizeof(*msg) + qlen);
381 if (msg == NULL) {
382 bug("%s: out of memory\n", DEVNAME);
383 return RNDIS_STATUS_FAILURE;
386 msg->rm_type = htole32(REMOTE_NDIS_QUERY_MSG);
387 msg->rm_len = htole32(sizeof(*msg) + qlen);
388 msg->rm_rid = 0; /* XXX */
389 msg->rm_oid = htole32(oid);
390 msg->rm_infobuflen = htole32(qlen);
391 if (qlen != 0) {
392 msg->rm_infobufoffset = htole32(20);
393 memcpy((char*)msg + 20, qbuf, qlen);
394 } else
395 msg->rm_infobufoffset = 0;
396 msg->rm_devicevchdl = 0;
398 bug("%s: urndis_ctrl_query send: type %u len %u rid %u oid 0x%x "
399 "infobuflen %u infobufoffset %u devicevchdl %u\n",
400 DEVNAME,
401 letoh32(msg->rm_type),
402 letoh32(msg->rm_len),
403 letoh32(msg->rm_rid),
404 letoh32(msg->rm_oid),
405 letoh32(msg->rm_infobuflen),
406 letoh32(msg->rm_infobufoffset),
407 letoh32(msg->rm_devicevchdl));
409 rval = urndis_ctrl_send(ncp, msg, sizeof(*msg));
410 psdFreeVec(msg);
412 if (rval != RNDIS_STATUS_SUCCESS) {
413 bug("%s: query failed\n", DEVNAME);
414 return rval;
417 if ((hdr = urndis_ctrl_recv(ncp)) == NULL) {
418 bug("%s: unable to get query response\n", DEVNAME);
419 return RNDIS_STATUS_FAILURE;
421 rval = urndis_ctrl_handle(ncp, hdr, rbuf, rbufsz);
423 return rval;
427 uint32_t urndis_ctrl_init(struct NepClassEth *ncp)
429 struct urndis_init_req *msg;
430 uint32_t rval;
431 struct urndis_comp_hdr *hdr;
433 msg = psdAllocVec(sizeof(*msg));
434 if (msg == NULL) {
435 bug("out of memory\n");
436 return RNDIS_STATUS_FAILURE;
439 msg->rm_type = htole32(REMOTE_NDIS_INITIALIZE_MSG);
440 msg->rm_len = htole32(sizeof(*msg));
441 msg->rm_rid = htole32(0);
442 msg->rm_ver_major = htole32(1);
443 msg->rm_ver_minor = htole32(1);
444 msg->rm_max_xfersz = htole32(RNDIS_BUFSZ);
446 bug("%s: urndis_ctrl_init send: type %u len %u rid %u ver_major %u "
447 "ver_minor %u max_xfersz %u\n",
448 DEVNAME,
449 letoh32(msg->rm_type),
450 letoh32(msg->rm_len),
451 letoh32(msg->rm_rid),
452 letoh32(msg->rm_ver_major),
453 letoh32(msg->rm_ver_minor),
454 letoh32(msg->rm_max_xfersz));
456 //Delay(50);
458 rval = urndis_ctrl_send(ncp, msg, sizeof(*msg));
459 psdFreeVec(msg);
461 if (rval != 0 ) {
462 bug("%s: init failed\n", DEVNAME);
463 return rval;
466 if ((hdr = urndis_ctrl_recv(ncp)) == NULL) {
467 bug("%s: unable to get init response\n", DEVNAME);
468 return RNDIS_STATUS_FAILURE;
470 rval = urndis_ctrl_handle(ncp, hdr, NULL, NULL);
472 return rval;
476 long urndis_encap(struct NepClassEth *ncp, BYTE *m,LONG len )
479 struct urndis_packet_msg *msg;
480 msg = (struct urndis_packet_msg *)m;
482 memset(msg, 0, sizeof(*msg));
483 msg->rm_type = htole32(REMOTE_NDIS_PACKET_MSG);
484 msg->rm_len = htole32(sizeof(*msg) + len);
486 msg->rm_dataoffset = htole32(RNDIS_DATA_OFFSET);
487 msg->rm_datalen = htole32(len);
489 //m_copydata(m, 0, len,((char*)msg + RNDIS_DATA_OFFSET + RNDIS_HEADER_OFFSET));
491 DB(bug("%s: urndis_encap type 0x%x len %u data(off %u len %u)\n",
492 DEVNAME,
493 letoh32(msg->rm_type),
494 letoh32(msg->rm_len),
495 letoh32(msg->rm_dataoffset),
496 letoh32(msg->rm_datalen)));
498 return(sizeof(*msg));
502 void urndis_decap(struct NepClassEth *ncp, const UBYTE *buf, const LONG datalen)
505 struct urndis_packet_msg *msg;
506 int offset;
507 int len;
509 offset = 0;
510 len = datalen;
512 while (len > 0) {
513 msg = (struct urndis_packet_msg *)(buf + offset);
514 DB(bug("%s: urndis_decap buffer size left %u\n", DEVNAME,len));
516 if (len < sizeof(*msg)) {
517 bug("%s: urndis_decap invalid buffer len %u < "
518 "minimum header %u\n",
519 DEVNAME,
520 len,
521 sizeof(*msg));
522 return;
525 DB(bug("%s: urndis_decap len %u data(off:%u len:%u) "
526 "oobdata(off:%u len:%u nb:%u) perpacket(off:%u len:%u)\n",
527 DEVNAME,
528 letoh32(msg->rm_len),
529 letoh32(msg->rm_dataoffset),
530 letoh32(msg->rm_datalen),
531 letoh32(msg->rm_oobdataoffset),
532 letoh32(msg->rm_oobdatalen),
533 letoh32(msg->rm_oobdataelements),
534 letoh32(msg->rm_pktinfooffset),
535 letoh32(msg->rm_pktinfooffset)));
537 if (letoh32(msg->rm_type) != REMOTE_NDIS_PACKET_MSG) {
538 bug("%s: urndis_decap invalid type 0x%x != 0x%x\n",
539 DEVNAME,
540 letoh32(msg->rm_type),
541 REMOTE_NDIS_PACKET_MSG);
542 return;
544 if (letoh32(msg->rm_len) < sizeof(*msg)) {
545 bug("%s: urndis_decap invalid msg len %u < %u\n",
546 DEVNAME,
547 letoh32(msg->rm_len),
548 sizeof(*msg));
549 return;
551 if (letoh32(msg->rm_len) > len) {
552 bug("%s: urndis_decap invalid msg len %u > buffer "
553 "len %u\n",
554 DEVNAME,
555 letoh32(msg->rm_len),
556 len);
557 return;
560 if (letoh32(msg->rm_dataoffset) +
561 letoh32(msg->rm_datalen) + RNDIS_HEADER_OFFSET
562 > letoh32(msg->rm_len)) {
563 bug("%s: urndis_decap invalid data "
564 "len/offset/end_position(%u/%u/%u) -> "
565 "go out of receive buffer limit %u\n",
566 DEVNAME,
567 letoh32(msg->rm_datalen),
568 letoh32(msg->rm_dataoffset),
569 letoh32(msg->rm_dataoffset) +
570 letoh32(msg->rm_datalen) + RNDIS_HEADER_OFFSET,
571 letoh32(msg->rm_len));
572 return;
575 if (letoh32(msg->rm_datalen) < sizeof(struct EtherPacketHeader)) {
576 bug("%s: urndis_decap invalid ethernet size "
577 "%d < %d\n",
578 DEVNAME,
579 letoh32(msg->rm_datalen),
580 sizeof(struct EtherPacketHeader));
581 return;
584 DB(bug("%s: urndis_decap ethernet packet OK,size %d,offset %d\n",DEVNAME, letoh32(msg->rm_datalen),offset));
586 nReadPacket(ncp, ((char*)&msg->rm_dataoffset + letoh32(msg->rm_dataoffset)), letoh32(msg->rm_datalen) );
588 offset += letoh32(msg->rm_len);
589 len -= letoh32(msg->rm_len);
594 void
595 urndis_attach(struct NepClassEth *ncp)
598 uint8_t eaddr[ETHER_ADDR_SIZE];
599 void *buf;
600 size_t bufsz;
601 uint32_t filter;
603 urndis_ctrl_init(ncp);
605 if (urndis_ctrl_query(ncp, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
606 &buf, &bufsz) != RNDIS_STATUS_SUCCESS) {
607 bug("%s: unable to get hardware address\n", DEVNAME);
608 return;
610 if (bufsz == ETHER_ADDR_SIZE) {
611 memcpy(eaddr, buf, ETHER_ADDR_SIZE);
612 bug("%s: address %x:%x:%x:%x:%x:%x\n", DEVNAME, eaddr[0],eaddr[1],eaddr[2],eaddr[3],eaddr[4],eaddr[5]);
613 psdFreeVec(buf);
614 } else {
615 bug("%s: invalid address\n", DEVNAME);
616 psdFreeVec(buf);
617 return;
620 /* Initialize packet filter */
621 ncp->sc_filter = RNDIS_PACKET_TYPE_BROADCAST;
622 ncp->sc_filter |= RNDIS_PACKET_TYPE_ALL_MULTICAST;
623 filter = htole32(ncp->sc_filter);
624 if (urndis_ctrl_set(ncp, OID_GEN_CURRENT_PACKET_FILTER, &filter,
625 sizeof(filter)) != RNDIS_STATUS_SUCCESS) {
626 bug("%s: unable to set data filters\n", DEVNAME);
627 return;
630 bug("%s: urndis_attach OK!\n", DEVNAME);
632 CopyMem(eaddr, ncp->ncp_MacAddress, ETHER_ADDR_SIZE);
633 CopyMem(eaddr, ncp->ncp_ROMAddress, ETHER_ADDR_SIZE);