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 23KB

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