You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

rndis.c 24KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072
  1. /*
  2. * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. *
  19. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. /** @file
  25. *
  26. * Remote Network Driver Interface Specification
  27. *
  28. */
  29. #include <unistd.h>
  30. #include <string.h>
  31. #include <errno.h>
  32. #include <byteswap.h>
  33. #include <ipxe/iobuf.h>
  34. #include <ipxe/netdevice.h>
  35. #include <ipxe/ethernet.h>
  36. #include <ipxe/device.h>
  37. #include <ipxe/rndis.h>
  38. /**
  39. * Allocate I/O buffer
  40. *
  41. * @v len Length
  42. * @ret iobuf I/O buffer, or NULL
  43. */
  44. static struct io_buffer * rndis_alloc_iob ( size_t len ) {
  45. struct rndis_header *header;
  46. struct io_buffer *iobuf;
  47. /* Allocate I/O buffer and reserve space */
  48. iobuf = alloc_iob ( sizeof ( *header ) + len );
  49. if ( iobuf )
  50. iob_reserve ( iobuf, sizeof ( *header ) );
  51. return iobuf;
  52. }
  53. /**
  54. * Wait for completion
  55. *
  56. * @v rndis RNDIS device
  57. * @v wait_id Request ID
  58. * @ret rc Return status code
  59. */
  60. static int rndis_wait ( struct rndis_device *rndis, unsigned int wait_id ) {
  61. unsigned int i;
  62. /* Record query ID */
  63. rndis->wait_id = wait_id;
  64. /* Wait for operation to complete */
  65. for ( i = 0 ; i < RNDIS_MAX_WAIT_MS ; i++ ) {
  66. /* Check for completion */
  67. if ( ! rndis->wait_id )
  68. return rndis->wait_rc;
  69. /* Poll RNDIS device */
  70. rndis->op->poll ( rndis );
  71. /* Delay for 1ms */
  72. mdelay ( 1 );
  73. }
  74. DBGC ( rndis, "RNDIS %s timed out waiting for ID %#08x\n",
  75. rndis->name, wait_id );
  76. return -ETIMEDOUT;
  77. }
  78. /**
  79. * Transmit message
  80. *
  81. * @v rndis RNDIS device
  82. * @v iobuf I/O buffer
  83. * @v type Message type
  84. * @ret rc Return status code
  85. */
  86. static int rndis_tx_message ( struct rndis_device *rndis,
  87. struct io_buffer *iobuf, unsigned int type ) {
  88. struct rndis_header *header;
  89. int rc;
  90. /* Prepend RNDIS header */
  91. header = iob_push ( iobuf, sizeof ( *header ) );
  92. header->type = cpu_to_le32 ( type );
  93. header->len = cpu_to_le32 ( iob_len ( iobuf ) );
  94. /* Transmit message */
  95. if ( ( rc = rndis->op->transmit ( rndis, iobuf ) ) != 0 ) {
  96. DBGC ( rndis, "RNDIS %s could not transmit: %s\n",
  97. rndis->name, strerror ( rc ) );
  98. return rc;
  99. }
  100. return 0;
  101. }
  102. /**
  103. * Complete message transmission
  104. *
  105. * @v rndis RNDIS device
  106. * @v iobuf I/O buffer
  107. * @v rc Packet status code
  108. */
  109. void rndis_tx_complete_err ( struct rndis_device *rndis,
  110. struct io_buffer *iobuf, int rc ) {
  111. struct net_device *netdev = rndis->netdev;
  112. struct rndis_header *header;
  113. size_t len = iob_len ( iobuf );
  114. /* Sanity check */
  115. if ( len < sizeof ( *header ) ) {
  116. DBGC ( rndis, "RNDIS %s completed underlength transmission:\n",
  117. rndis->name );
  118. DBGC_HDA ( rndis, 0, iobuf->data, len );
  119. netdev_tx_err ( netdev, NULL, -EINVAL );
  120. return;
  121. }
  122. header = iobuf->data;
  123. /* Complete buffer */
  124. if ( header->type == cpu_to_le32 ( RNDIS_PACKET_MSG ) ) {
  125. netdev_tx_complete_err ( netdev, iobuf, rc );
  126. } else {
  127. free_iob ( iobuf );
  128. }
  129. }
  130. /**
  131. * Transmit data packet
  132. *
  133. * @v rndis RNDIS device
  134. * @v iobuf I/O buffer
  135. * @ret rc Return status code
  136. */
  137. static int rndis_tx_data ( struct rndis_device *rndis,
  138. struct io_buffer *iobuf ) {
  139. struct rndis_packet_message *msg;
  140. size_t len = iob_len ( iobuf );
  141. int rc;
  142. /* Prepend packet message header */
  143. msg = iob_push ( iobuf, sizeof ( *msg ) );
  144. memset ( msg, 0, sizeof ( *msg ) );
  145. msg->data.offset = cpu_to_le32 ( sizeof ( *msg ) );
  146. msg->data.len = cpu_to_le32 ( len );
  147. /* Transmit message */
  148. if ( ( rc = rndis_tx_message ( rndis, iobuf, RNDIS_PACKET_MSG ) ) != 0 )
  149. return rc;
  150. return 0;
  151. }
  152. /**
  153. * Defer transmitted packet
  154. *
  155. * @v rndis RNDIS device
  156. * @v iobuf I/O buffer
  157. * @ret rc Return status code
  158. *
  159. * As with netdev_tx_defer(), the caller must ensure that space in the
  160. * transmit descriptor ring is freed up before calling
  161. * rndis_tx_complete().
  162. *
  163. * Unlike netdev_tx_defer(), this call may fail.
  164. */
  165. int rndis_tx_defer ( struct rndis_device *rndis, struct io_buffer *iobuf ) {
  166. struct net_device *netdev = rndis->netdev;
  167. struct rndis_header *header;
  168. struct rndis_packet_message *msg;
  169. /* Fail unless this was a packet message. Only packet
  170. * messages correspond to I/O buffers in the network device's
  171. * TX queue; other messages cannot be deferred in this way.
  172. */
  173. assert ( iob_len ( iobuf ) >= sizeof ( *header ) );
  174. header = iobuf->data;
  175. if ( header->type != cpu_to_le32 ( RNDIS_PACKET_MSG ) )
  176. return -ENOTSUP;
  177. /* Strip RNDIS header and packet message header, to return
  178. * this packet to the state in which we received it.
  179. */
  180. iob_pull ( iobuf, ( sizeof ( *header ) + sizeof ( *msg ) ) );
  181. /* Defer packet */
  182. netdev_tx_defer ( netdev, iobuf );
  183. return 0;
  184. }
  185. /**
  186. * Receive data packet
  187. *
  188. * @v rndis RNDIS device
  189. * @v iobuf I/O buffer
  190. */
  191. static void rndis_rx_data ( struct rndis_device *rndis,
  192. struct io_buffer *iobuf ) {
  193. struct net_device *netdev = rndis->netdev;
  194. struct rndis_packet_message *msg;
  195. size_t len = iob_len ( iobuf );
  196. size_t data_offset;
  197. size_t data_len;
  198. int rc;
  199. /* Sanity check */
  200. if ( len < sizeof ( *msg ) ) {
  201. DBGC ( rndis, "RNDIS %s received underlength data packet:\n",
  202. rndis->name );
  203. DBGC_HDA ( rndis, 0, iobuf->data, len );
  204. rc = -EINVAL;
  205. goto err_len;
  206. }
  207. msg = iobuf->data;
  208. /* Locate and sanity check data buffer */
  209. data_offset = le32_to_cpu ( msg->data.offset );
  210. data_len = le32_to_cpu ( msg->data.len );
  211. if ( ( data_offset > len ) || ( data_len > ( len - data_offset ) ) ) {
  212. DBGC ( rndis, "RNDIS %s data packet data exceeds packet:\n",
  213. rndis->name );
  214. DBGC_HDA ( rndis, 0, iobuf->data, len );
  215. rc = -EINVAL;
  216. goto err_data;
  217. }
  218. /* Strip non-data portions */
  219. iob_pull ( iobuf, data_offset );
  220. iob_unput ( iobuf, ( iob_len ( iobuf ) - data_len ) );
  221. /* Hand off to network stack */
  222. netdev_rx ( netdev, iob_disown ( iobuf ) );
  223. return;
  224. err_data:
  225. err_len:
  226. /* Report error to network stack */
  227. netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
  228. }
  229. /**
  230. * Transmit initialisation message
  231. *
  232. * @v rndis RNDIS device
  233. * @v id Request ID
  234. * @ret rc Return status code
  235. */
  236. static int rndis_tx_initialise ( struct rndis_device *rndis, unsigned int id ) {
  237. struct io_buffer *iobuf;
  238. struct rndis_initialise_message *msg;
  239. int rc;
  240. /* Allocate I/O buffer */
  241. iobuf = rndis_alloc_iob ( sizeof ( *msg ) );
  242. if ( ! iobuf ) {
  243. rc = -ENOMEM;
  244. goto err_alloc;
  245. }
  246. /* Construct message */
  247. msg = iob_put ( iobuf, sizeof ( *msg ) );
  248. memset ( msg, 0, sizeof ( *msg ) );
  249. msg->id = id; /* Non-endian */
  250. msg->major = cpu_to_le32 ( RNDIS_VERSION_MAJOR );
  251. msg->minor = cpu_to_le32 ( RNDIS_VERSION_MINOR );
  252. msg->mtu = cpu_to_le32 ( RNDIS_MTU );
  253. /* Transmit message */
  254. if ( ( rc = rndis_tx_message ( rndis, iobuf,
  255. RNDIS_INITIALISE_MSG ) ) != 0 )
  256. goto err_tx;
  257. return 0;
  258. err_tx:
  259. free_iob ( iobuf );
  260. err_alloc:
  261. return rc;
  262. }
  263. /**
  264. * Receive initialisation completion
  265. *
  266. * @v rndis RNDIS device
  267. * @v iobuf I/O buffer
  268. */
  269. static void rndis_rx_initialise ( struct rndis_device *rndis,
  270. struct io_buffer *iobuf ) {
  271. struct rndis_initialise_completion *cmplt;
  272. size_t len = iob_len ( iobuf );
  273. unsigned int id;
  274. int rc;
  275. /* Sanity check */
  276. if ( len < sizeof ( *cmplt ) ) {
  277. DBGC ( rndis, "RNDIS %s received underlength initialisation "
  278. "completion:\n", rndis->name );
  279. DBGC_HDA ( rndis, 0, iobuf->data, len );
  280. rc = -EINVAL;
  281. goto err_len;
  282. }
  283. cmplt = iobuf->data;
  284. /* Extract request ID */
  285. id = cmplt->id; /* Non-endian */
  286. /* Check status */
  287. if ( cmplt->status ) {
  288. DBGC ( rndis, "RNDIS %s received initialisation completion "
  289. "failure %#08x\n", rndis->name,
  290. le32_to_cpu ( cmplt->status ) );
  291. rc = -EIO;
  292. goto err_status;
  293. }
  294. /* Success */
  295. rc = 0;
  296. err_status:
  297. /* Record completion result if applicable */
  298. if ( id == rndis->wait_id ) {
  299. rndis->wait_id = 0;
  300. rndis->wait_rc = rc;
  301. }
  302. err_len:
  303. free_iob ( iobuf );
  304. }
  305. /**
  306. * Initialise RNDIS
  307. *
  308. * @v rndis RNDIS device
  309. * @ret rc Return status code
  310. */
  311. static int rndis_initialise ( struct rndis_device *rndis ) {
  312. int rc;
  313. /* Transmit initialisation message */
  314. if ( ( rc = rndis_tx_initialise ( rndis, RNDIS_INIT_ID ) ) != 0 )
  315. return rc;
  316. /* Wait for response */
  317. if ( ( rc = rndis_wait ( rndis, RNDIS_INIT_ID ) ) != 0 )
  318. return rc;
  319. return 0;
  320. }
  321. /**
  322. * Transmit halt message
  323. *
  324. * @v rndis RNDIS device
  325. * @ret rc Return status code
  326. */
  327. static int rndis_tx_halt ( struct rndis_device *rndis ) {
  328. struct io_buffer *iobuf;
  329. struct rndis_halt_message *msg;
  330. int rc;
  331. /* Allocate I/O buffer */
  332. iobuf = rndis_alloc_iob ( sizeof ( *msg ) );
  333. if ( ! iobuf ) {
  334. rc = -ENOMEM;
  335. goto err_alloc;
  336. }
  337. /* Construct message */
  338. msg = iob_put ( iobuf, sizeof ( *msg ) );
  339. memset ( msg, 0, sizeof ( *msg ) );
  340. /* Transmit message */
  341. if ( ( rc = rndis_tx_message ( rndis, iobuf, RNDIS_HALT_MSG ) ) != 0 )
  342. goto err_tx;
  343. return 0;
  344. err_tx:
  345. free_iob ( iobuf );
  346. err_alloc:
  347. return rc;
  348. }
  349. /**
  350. * Halt RNDIS
  351. *
  352. * @v rndis RNDIS device
  353. * @ret rc Return status code
  354. */
  355. static int rndis_halt ( struct rndis_device *rndis ) {
  356. int rc;
  357. /* Transmit halt message */
  358. if ( ( rc = rndis_tx_halt ( rndis ) ) != 0 )
  359. return rc;
  360. return 0;
  361. }
  362. /**
  363. * Transmit OID message
  364. *
  365. * @v rndis RNDIS device
  366. * @v oid Object ID
  367. * @v data New OID value (or NULL to query current value)
  368. * @v len Length of new OID value
  369. * @ret rc Return status code
  370. */
  371. static int rndis_tx_oid ( struct rndis_device *rndis, unsigned int oid,
  372. const void *data, size_t len ) {
  373. struct io_buffer *iobuf;
  374. struct rndis_oid_message *msg;
  375. unsigned int type;
  376. int rc;
  377. /* Allocate I/O buffer */
  378. iobuf = rndis_alloc_iob ( sizeof ( *msg ) + len );
  379. if ( ! iobuf ) {
  380. rc = -ENOMEM;
  381. goto err_alloc;
  382. }
  383. /* Construct message. We use the OID as the request ID. */
  384. msg = iob_put ( iobuf, sizeof ( *msg ) );
  385. memset ( msg, 0, sizeof ( *msg ) );
  386. msg->id = oid; /* Non-endian */
  387. msg->oid = cpu_to_le32 ( oid );
  388. msg->offset = cpu_to_le32 ( sizeof ( *msg ) );
  389. msg->len = cpu_to_le32 ( len );
  390. memcpy ( iob_put ( iobuf, len ), data, len );
  391. /* Transmit message */
  392. type = ( data ? RNDIS_SET_MSG : RNDIS_QUERY_MSG );
  393. if ( ( rc = rndis_tx_message ( rndis, iobuf, type ) ) != 0 )
  394. goto err_tx;
  395. return 0;
  396. err_tx:
  397. free_iob ( iobuf );
  398. err_alloc:
  399. return rc;
  400. }
  401. /**
  402. * Receive query OID completion
  403. *
  404. * @v rndis RNDIS device
  405. * @v iobuf I/O buffer
  406. */
  407. static void rndis_rx_query_oid ( struct rndis_device *rndis,
  408. struct io_buffer *iobuf ) {
  409. struct net_device *netdev = rndis->netdev;
  410. struct rndis_query_completion *cmplt;
  411. size_t len = iob_len ( iobuf );
  412. size_t info_offset;
  413. size_t info_len;
  414. unsigned int id;
  415. void *info;
  416. uint32_t *link_status;
  417. int rc;
  418. /* Sanity check */
  419. if ( len < sizeof ( *cmplt ) ) {
  420. DBGC ( rndis, "RNDIS %s received underlength query "
  421. "completion:\n", rndis->name );
  422. DBGC_HDA ( rndis, 0, iobuf->data, len );
  423. rc = -EINVAL;
  424. goto err_len;
  425. }
  426. cmplt = iobuf->data;
  427. /* Extract request ID */
  428. id = cmplt->id; /* Non-endian */
  429. /* Check status */
  430. if ( cmplt->status ) {
  431. DBGC ( rndis, "RNDIS %s received query completion failure "
  432. "%#08x\n", rndis->name, le32_to_cpu ( cmplt->status ) );
  433. DBGC_HDA ( rndis, 0, iobuf->data, len );
  434. rc = -EIO;
  435. goto err_status;
  436. }
  437. /* Locate and sanity check information buffer */
  438. info_offset = le32_to_cpu ( cmplt->offset );
  439. info_len = le32_to_cpu ( cmplt->len );
  440. if ( ( info_offset > len ) || ( info_len > ( len - info_offset ) ) ) {
  441. DBGC ( rndis, "RNDIS %s query completion information exceeds "
  442. "packet:\n", rndis->name );
  443. DBGC_HDA ( rndis, 0, iobuf->data, len );
  444. rc = -EINVAL;
  445. goto err_info;
  446. }
  447. info = ( ( ( void * ) cmplt ) + info_offset );
  448. /* Handle OID */
  449. switch ( id ) {
  450. case RNDIS_OID_802_3_PERMANENT_ADDRESS:
  451. if ( info_len > sizeof ( netdev->hw_addr ) )
  452. info_len = sizeof ( netdev->hw_addr );
  453. memcpy ( netdev->hw_addr, info, info_len );
  454. break;
  455. case RNDIS_OID_802_3_CURRENT_ADDRESS:
  456. if ( info_len > sizeof ( netdev->ll_addr ) )
  457. info_len = sizeof ( netdev->ll_addr );
  458. memcpy ( netdev->ll_addr, info, info_len );
  459. break;
  460. case RNDIS_OID_GEN_MEDIA_CONNECT_STATUS:
  461. if ( info_len != sizeof ( *link_status ) ) {
  462. DBGC ( rndis, "RNDIS %s invalid link status:\n",
  463. rndis->name );
  464. DBGC_HDA ( rndis, 0, iobuf->data, len );
  465. rc = -EPROTO;
  466. goto err_link_status;
  467. }
  468. link_status = info;
  469. if ( *link_status == 0 ) {
  470. DBGC ( rndis, "RNDIS %s link is up\n", rndis->name );
  471. netdev_link_up ( netdev );
  472. } else {
  473. DBGC ( rndis, "RNDIS %s link is down: %#08x\n",
  474. rndis->name, le32_to_cpu ( *link_status ) );
  475. netdev_link_down ( netdev );
  476. }
  477. break;
  478. default:
  479. DBGC ( rndis, "RNDIS %s unexpected query completion ID %#08x\n",
  480. rndis->name, id );
  481. DBGC_HDA ( rndis, 0, iobuf->data, len );
  482. rc = -EPROTO;
  483. goto err_id;
  484. }
  485. /* Success */
  486. rc = 0;
  487. err_id:
  488. err_link_status:
  489. err_info:
  490. err_status:
  491. /* Record completion result if applicable */
  492. if ( id == rndis->wait_id ) {
  493. rndis->wait_id = 0;
  494. rndis->wait_rc = rc;
  495. }
  496. err_len:
  497. /* Free I/O buffer */
  498. free_iob ( iobuf );
  499. }
  500. /**
  501. * Receive set OID completion
  502. *
  503. * @v rndis RNDIS device
  504. * @v iobuf I/O buffer
  505. */
  506. static void rndis_rx_set_oid ( struct rndis_device *rndis,
  507. struct io_buffer *iobuf ) {
  508. struct rndis_set_completion *cmplt;
  509. size_t len = iob_len ( iobuf );
  510. unsigned int id;
  511. int rc;
  512. /* Sanity check */
  513. if ( len < sizeof ( *cmplt ) ) {
  514. DBGC ( rndis, "RNDIS %s received underlength set completion:\n",
  515. rndis->name );
  516. DBGC_HDA ( rndis, 0, iobuf->data, len );
  517. rc = -EINVAL;
  518. goto err_len;
  519. }
  520. cmplt = iobuf->data;
  521. /* Extract request ID */
  522. id = cmplt->id; /* Non-endian */
  523. /* Check status */
  524. if ( cmplt->status ) {
  525. DBGC ( rndis, "RNDIS %s received set completion failure "
  526. "%#08x\n", rndis->name, le32_to_cpu ( cmplt->status ) );
  527. DBGC_HDA ( rndis, 0, iobuf->data, len );
  528. rc = -EIO;
  529. goto err_status;
  530. }
  531. /* Success */
  532. rc = 0;
  533. err_status:
  534. /* Record completion result if applicable */
  535. if ( id == rndis->wait_id ) {
  536. rndis->wait_id = 0;
  537. rndis->wait_rc = rc;
  538. }
  539. err_len:
  540. /* Free I/O buffer */
  541. free_iob ( iobuf );
  542. }
  543. /**
  544. * Query or set OID
  545. *
  546. * @v rndis RNDIS device
  547. * @v oid Object ID
  548. * @v data New OID value (or NULL to query current value)
  549. * @v len Length of new OID value
  550. * @ret rc Return status code
  551. */
  552. static int rndis_oid ( struct rndis_device *rndis, unsigned int oid,
  553. const void *data, size_t len ) {
  554. int rc;
  555. /* Transmit query */
  556. if ( ( rc = rndis_tx_oid ( rndis, oid, data, len ) ) != 0 )
  557. return rc;
  558. /* Wait for response */
  559. if ( ( rc = rndis_wait ( rndis, oid ) ) != 0 )
  560. return rc;
  561. return 0;
  562. }
  563. /**
  564. * Describe RNDIS device
  565. *
  566. * @v rndis RNDIS device
  567. * @ret rc Return status code
  568. */
  569. static int rndis_describe ( struct rndis_device *rndis ) {
  570. struct net_device *netdev = rndis->netdev;
  571. int rc;
  572. /* Assign device name (for debugging) */
  573. rndis->name = netdev->dev->name;
  574. /* Open RNDIS device to read MAC addresses */
  575. if ( ( rc = rndis->op->open ( rndis ) ) != 0 ) {
  576. DBGC ( rndis, "RNDIS %s could not open: %s\n",
  577. rndis->name, strerror ( rc ) );
  578. goto err_open;
  579. }
  580. /* Initialise RNDIS */
  581. if ( ( rc = rndis_initialise ( rndis ) ) != 0 )
  582. goto err_initialise;
  583. /* Query permanent MAC address */
  584. if ( ( rc = rndis_oid ( rndis, RNDIS_OID_802_3_PERMANENT_ADDRESS,
  585. NULL, 0 ) ) != 0 )
  586. goto err_query_permanent;
  587. /* Query current MAC address */
  588. if ( ( rc = rndis_oid ( rndis, RNDIS_OID_802_3_CURRENT_ADDRESS,
  589. NULL, 0 ) ) != 0 )
  590. goto err_query_current;
  591. /* Get link status */
  592. if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
  593. NULL, 0 ) ) != 0 )
  594. goto err_query_link;
  595. /* Halt RNDIS device */
  596. rndis_halt ( rndis );
  597. /* Close RNDIS device */
  598. rndis->op->close ( rndis );
  599. return 0;
  600. err_query_link:
  601. err_query_current:
  602. err_query_permanent:
  603. rndis_halt ( rndis );
  604. err_initialise:
  605. rndis->op->close ( rndis );
  606. err_open:
  607. return rc;
  608. }
  609. /**
  610. * Receive indicate status message
  611. *
  612. * @v rndis RNDIS device
  613. * @v iobuf I/O buffer
  614. */
  615. static void rndis_rx_status ( struct rndis_device *rndis,
  616. struct io_buffer *iobuf ) {
  617. struct net_device *netdev = rndis->netdev;
  618. struct rndis_indicate_status_message *msg;
  619. size_t len = iob_len ( iobuf );
  620. unsigned int status;
  621. int rc;
  622. /* Sanity check */
  623. if ( len < sizeof ( *msg ) ) {
  624. DBGC ( rndis, "RNDIS %s received underlength status message:\n",
  625. rndis->name );
  626. DBGC_HDA ( rndis, 0, iobuf->data, len );
  627. rc = -EINVAL;
  628. goto err_len;
  629. }
  630. msg = iobuf->data;
  631. /* Extract status */
  632. status = le32_to_cpu ( msg->status );
  633. /* Handle status */
  634. switch ( msg->status ) {
  635. case RNDIS_STATUS_MEDIA_CONNECT:
  636. DBGC ( rndis, "RNDIS %s link is up\n", rndis->name );
  637. netdev_link_up ( netdev );
  638. break;
  639. case RNDIS_STATUS_MEDIA_DISCONNECT:
  640. DBGC ( rndis, "RNDIS %s link is down\n", rndis->name );
  641. netdev_link_down ( netdev );
  642. break;
  643. case RNDIS_STATUS_WTF_WORLD:
  644. /* Ignore */
  645. break;
  646. default:
  647. DBGC ( rndis, "RNDIS %s unexpected status %#08x:\n",
  648. rndis->name, status );
  649. DBGC_HDA ( rndis, 0, iobuf->data, len );
  650. rc = -ENOTSUP;
  651. goto err_status;
  652. }
  653. /* Free I/O buffer */
  654. free_iob ( iobuf );
  655. return;
  656. err_status:
  657. err_len:
  658. /* Report error via network device statistics */
  659. netdev_rx_err ( netdev, iobuf, rc );
  660. }
  661. /**
  662. * Receive RNDIS message
  663. *
  664. * @v rndis RNDIS device
  665. * @v iobuf I/O buffer
  666. * @v type Message type
  667. */
  668. static void rndis_rx_message ( struct rndis_device *rndis,
  669. struct io_buffer *iobuf, unsigned int type ) {
  670. struct net_device *netdev = rndis->netdev;
  671. int rc;
  672. /* Handle packet */
  673. switch ( type ) {
  674. case RNDIS_PACKET_MSG:
  675. rndis_rx_data ( rndis, iob_disown ( iobuf ) );
  676. break;
  677. case RNDIS_INITIALISE_CMPLT:
  678. rndis_rx_initialise ( rndis, iob_disown ( iobuf ) );
  679. break;
  680. case RNDIS_QUERY_CMPLT:
  681. rndis_rx_query_oid ( rndis, iob_disown ( iobuf ) );
  682. break;
  683. case RNDIS_SET_CMPLT:
  684. rndis_rx_set_oid ( rndis, iob_disown ( iobuf ) );
  685. break;
  686. case RNDIS_INDICATE_STATUS_MSG:
  687. rndis_rx_status ( rndis, iob_disown ( iobuf ) );
  688. break;
  689. default:
  690. DBGC ( rndis, "RNDIS %s received unexpected type %#08x\n",
  691. rndis->name, type );
  692. DBGC_HDA ( rndis, 0, iobuf->data, iob_len ( iobuf ) );
  693. rc = -EPROTO;
  694. goto err_type;
  695. }
  696. return;
  697. err_type:
  698. /* Report error via network device statistics */
  699. netdev_rx_err ( netdev, iobuf, rc );
  700. }
  701. /**
  702. * Receive packet from underlying transport layer
  703. *
  704. * @v rndis RNDIS device
  705. * @v iobuf I/O buffer
  706. */
  707. void rndis_rx ( struct rndis_device *rndis, struct io_buffer *iobuf ) {
  708. struct net_device *netdev = rndis->netdev;
  709. struct rndis_header *header;
  710. unsigned int type;
  711. int rc;
  712. /* Sanity check */
  713. if ( iob_len ( iobuf ) < sizeof ( *header ) ) {
  714. DBGC ( rndis, "RNDIS %s received underlength packet:\n",
  715. rndis->name );
  716. DBGC_HDA ( rndis, 0, iobuf->data, iob_len ( iobuf ) );
  717. rc = -EINVAL;
  718. goto drop;
  719. }
  720. header = iobuf->data;
  721. /* Parse and strip header */
  722. type = le32_to_cpu ( header->type );
  723. iob_pull ( iobuf, sizeof ( *header ) );
  724. /* Handle message */
  725. rndis_rx_message ( rndis, iob_disown ( iobuf ), type );
  726. return;
  727. drop:
  728. /* Record error */
  729. netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
  730. }
  731. /**
  732. * Discard packet from underlying transport layer
  733. *
  734. * @v rndis RNDIS device
  735. * @v iobuf I/O buffer
  736. * @v rc Packet status code
  737. */
  738. void rndis_rx_err ( struct rndis_device *rndis, struct io_buffer *iobuf,
  739. int rc ) {
  740. struct net_device *netdev = rndis->netdev;
  741. /* Record error */
  742. netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
  743. }
  744. /**
  745. * Set receive filter
  746. *
  747. * @v rndis RNDIS device
  748. * @v filter Receive filter
  749. * @ret rc Return status code
  750. */
  751. static int rndis_filter ( struct rndis_device *rndis, unsigned int filter ) {
  752. uint32_t value = cpu_to_le32 ( filter );
  753. int rc;
  754. /* Set receive filter */
  755. if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
  756. &value, sizeof ( value ) ) ) != 0 ) {
  757. DBGC ( rndis, "RNDIS %s could not set receive filter to %#08x: "
  758. "%s\n", rndis->name, filter, strerror ( rc ) );
  759. return rc;
  760. }
  761. return 0;
  762. }
  763. /**
  764. * Open network device
  765. *
  766. * @v netdev Network device
  767. * @ret rc Return status code
  768. */
  769. static int rndis_open ( struct net_device *netdev ) {
  770. struct rndis_device *rndis = netdev->priv;
  771. int rc;
  772. /* Open RNDIS device */
  773. if ( ( rc = rndis->op->open ( rndis ) ) != 0 ) {
  774. DBGC ( rndis, "RNDIS %s could not open: %s\n",
  775. rndis->name, strerror ( rc ) );
  776. goto err_open;
  777. }
  778. /* Initialise RNDIS */
  779. if ( ( rc = rndis_initialise ( rndis ) ) != 0 )
  780. goto err_initialise;
  781. /* Set receive filter */
  782. if ( ( rc = rndis_filter ( rndis, ( RNDIS_FILTER_UNICAST |
  783. RNDIS_FILTER_MULTICAST |
  784. RNDIS_FILTER_ALL_MULTICAST |
  785. RNDIS_FILTER_BROADCAST |
  786. RNDIS_FILTER_PROMISCUOUS ) ) ) != 0)
  787. goto err_set_filter;
  788. /* Update link status */
  789. if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
  790. NULL, 0 ) ) != 0 )
  791. goto err_query_link;
  792. return 0;
  793. err_query_link:
  794. err_set_filter:
  795. rndis_halt ( rndis );
  796. err_initialise:
  797. rndis->op->close ( rndis );
  798. err_open:
  799. return rc;
  800. }
  801. /**
  802. * Close network device
  803. *
  804. * @v netdev Network device
  805. */
  806. static void rndis_close ( struct net_device *netdev ) {
  807. struct rndis_device *rndis = netdev->priv;
  808. /* Clear receive filter */
  809. rndis_filter ( rndis, 0 );
  810. /* Halt RNDIS device */
  811. rndis_halt ( rndis );
  812. /* Close RNDIS device */
  813. rndis->op->close ( rndis );
  814. }
  815. /**
  816. * Transmit packet
  817. *
  818. * @v netdev Network device
  819. * @v iobuf I/O buffer
  820. * @ret rc Return status code
  821. */
  822. static int rndis_transmit ( struct net_device *netdev,
  823. struct io_buffer *iobuf ) {
  824. struct rndis_device *rndis = netdev->priv;
  825. /* Transmit data packet */
  826. return rndis_tx_data ( rndis, iobuf );
  827. }
  828. /**
  829. * Poll for completed and received packets
  830. *
  831. * @v netdev Network device
  832. */
  833. static void rndis_poll ( struct net_device *netdev ) {
  834. struct rndis_device *rndis = netdev->priv;
  835. /* Poll RNDIS device */
  836. rndis->op->poll ( rndis );
  837. }
  838. /** Network device operations */
  839. static struct net_device_operations rndis_operations = {
  840. .open = rndis_open,
  841. .close = rndis_close,
  842. .transmit = rndis_transmit,
  843. .poll = rndis_poll,
  844. };
  845. /**
  846. * Allocate RNDIS device
  847. *
  848. * @v priv_len Length of private data
  849. * @ret rndis RNDIS device, or NULL on allocation failure
  850. */
  851. struct rndis_device * alloc_rndis ( size_t priv_len ) {
  852. struct net_device *netdev;
  853. struct rndis_device *rndis;
  854. /* Allocate and initialise structure */
  855. netdev = alloc_etherdev ( sizeof ( *rndis ) + priv_len );
  856. if ( ! netdev )
  857. return NULL;
  858. netdev_init ( netdev, &rndis_operations );
  859. rndis = netdev->priv;
  860. rndis->netdev = netdev;
  861. rndis->priv = ( ( ( void * ) rndis ) + sizeof ( *rndis ) );
  862. return rndis;
  863. }
  864. /**
  865. * Register RNDIS device
  866. *
  867. * @v rndis RNDIS device
  868. * @ret rc Return status code
  869. *
  870. * Note that this routine will open and use the RNDIS device in order
  871. * to query the MAC address. The device must be immediately ready for
  872. * use prior to registration.
  873. */
  874. int register_rndis ( struct rndis_device *rndis ) {
  875. struct net_device *netdev = rndis->netdev;
  876. int rc;
  877. /* Describe RNDIS device */
  878. if ( ( rc = rndis_describe ( rndis ) ) != 0 )
  879. goto err_describe;
  880. /* Register network device */
  881. if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
  882. DBGC ( rndis, "RNDIS %s could not register: %s\n",
  883. rndis->name, strerror ( rc ) );
  884. goto err_register;
  885. }
  886. return 0;
  887. unregister_netdev ( netdev );
  888. err_register:
  889. err_describe:
  890. return rc;
  891. }
  892. /**
  893. * Unregister RNDIS device
  894. *
  895. * @v rndis RNDIS device
  896. */
  897. void unregister_rndis ( struct rndis_device *rndis ) {
  898. struct net_device *netdev = rndis->netdev;
  899. /* Unregister network device */
  900. unregister_netdev ( netdev );
  901. }
  902. /**
  903. * Free RNDIS device
  904. *
  905. * @v rndis RNDIS device
  906. */
  907. void free_rndis ( struct rndis_device *rndis ) {
  908. struct net_device *netdev = rndis->netdev;
  909. /* Free network device */
  910. netdev_nullify ( netdev );
  911. netdev_put ( netdev );
  912. }