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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029
  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 halt message
  319. *
  320. * @v rndis RNDIS device
  321. * @ret rc Return status code
  322. */
  323. static int rndis_tx_halt ( struct rndis_device *rndis ) {
  324. struct io_buffer *iobuf;
  325. struct rndis_halt_message *msg;
  326. int rc;
  327. /* Allocate I/O buffer */
  328. iobuf = rndis_alloc_iob ( sizeof ( *msg ) );
  329. if ( ! iobuf ) {
  330. rc = -ENOMEM;
  331. goto err_alloc;
  332. }
  333. /* Construct message */
  334. msg = iob_put ( iobuf, sizeof ( *msg ) );
  335. memset ( msg, 0, sizeof ( *msg ) );
  336. /* Transmit message */
  337. if ( ( rc = rndis_tx_message ( rndis, iobuf, RNDIS_HALT_MSG ) ) != 0 )
  338. goto err_tx;
  339. return 0;
  340. err_tx:
  341. free_iob ( iobuf );
  342. err_alloc:
  343. return rc;
  344. }
  345. /**
  346. * Halt RNDIS
  347. *
  348. * @v rndis RNDIS device
  349. * @ret rc Return status code
  350. */
  351. static int rndis_halt ( struct rndis_device *rndis ) {
  352. int rc;
  353. /* Transmit halt message */
  354. if ( ( rc = rndis_tx_halt ( rndis ) ) != 0 )
  355. return rc;
  356. return 0;
  357. }
  358. /**
  359. * Transmit OID message
  360. *
  361. * @v rndis RNDIS device
  362. * @v oid Object ID
  363. * @v data New OID value (or NULL to query current value)
  364. * @v len Length of new OID value
  365. * @ret rc Return status code
  366. */
  367. static int rndis_tx_oid ( struct rndis_device *rndis, unsigned int oid,
  368. const void *data, size_t len ) {
  369. struct io_buffer *iobuf;
  370. struct rndis_oid_message *msg;
  371. unsigned int type;
  372. int rc;
  373. /* Allocate I/O buffer */
  374. iobuf = rndis_alloc_iob ( sizeof ( *msg ) + len );
  375. if ( ! iobuf ) {
  376. rc = -ENOMEM;
  377. goto err_alloc;
  378. }
  379. /* Construct message. We use the OID as the request ID. */
  380. msg = iob_put ( iobuf, sizeof ( *msg ) );
  381. memset ( msg, 0, sizeof ( *msg ) );
  382. msg->id = oid; /* Non-endian */
  383. msg->oid = cpu_to_le32 ( oid );
  384. msg->offset = cpu_to_le32 ( sizeof ( *msg ) );
  385. msg->len = cpu_to_le32 ( len );
  386. memcpy ( iob_put ( iobuf, len ), data, len );
  387. /* Transmit message */
  388. type = ( data ? RNDIS_SET_MSG : RNDIS_QUERY_MSG );
  389. if ( ( rc = rndis_tx_message ( rndis, iobuf, type ) ) != 0 )
  390. goto err_tx;
  391. return 0;
  392. err_tx:
  393. free_iob ( iobuf );
  394. err_alloc:
  395. return rc;
  396. }
  397. /**
  398. * Receive query OID completion
  399. *
  400. * @v rndis RNDIS device
  401. * @v iobuf I/O buffer
  402. */
  403. static void rndis_rx_query_oid ( struct rndis_device *rndis,
  404. struct io_buffer *iobuf ) {
  405. struct net_device *netdev = rndis->netdev;
  406. struct rndis_query_completion *cmplt;
  407. size_t len = iob_len ( iobuf );
  408. size_t info_offset;
  409. size_t info_len;
  410. unsigned int id;
  411. void *info;
  412. uint32_t *link_status;
  413. int rc;
  414. /* Sanity check */
  415. if ( len < sizeof ( *cmplt ) ) {
  416. DBGC ( rndis, "RNDIS %s received underlength query "
  417. "completion:\n", rndis->name );
  418. DBGC_HDA ( rndis, 0, iobuf->data, len );
  419. rc = -EINVAL;
  420. goto err_len;
  421. }
  422. cmplt = iobuf->data;
  423. /* Extract request ID */
  424. id = cmplt->id; /* Non-endian */
  425. /* Check status */
  426. if ( cmplt->status ) {
  427. DBGC ( rndis, "RNDIS %s received query completion failure "
  428. "%#08x\n", rndis->name, le32_to_cpu ( cmplt->status ) );
  429. DBGC_HDA ( rndis, 0, iobuf->data, len );
  430. rc = -EIO;
  431. goto err_status;
  432. }
  433. /* Locate and sanity check information buffer */
  434. info_offset = le32_to_cpu ( cmplt->offset );
  435. info_len = le32_to_cpu ( cmplt->len );
  436. if ( ( info_offset > len ) || ( info_len > ( len - info_offset ) ) ) {
  437. DBGC ( rndis, "RNDIS %s query completion information exceeds "
  438. "packet:\n", rndis->name );
  439. DBGC_HDA ( rndis, 0, iobuf->data, len );
  440. rc = -EINVAL;
  441. goto err_info;
  442. }
  443. info = ( ( ( void * ) cmplt ) + info_offset );
  444. /* Handle OID */
  445. switch ( id ) {
  446. case RNDIS_OID_802_3_PERMANENT_ADDRESS:
  447. if ( info_len > sizeof ( netdev->hw_addr ) )
  448. info_len = sizeof ( netdev->hw_addr );
  449. memcpy ( netdev->hw_addr, info, info_len );
  450. break;
  451. case RNDIS_OID_802_3_CURRENT_ADDRESS:
  452. if ( info_len > sizeof ( netdev->ll_addr ) )
  453. info_len = sizeof ( netdev->ll_addr );
  454. memcpy ( netdev->ll_addr, info, info_len );
  455. break;
  456. case RNDIS_OID_GEN_MEDIA_CONNECT_STATUS:
  457. if ( info_len != sizeof ( *link_status ) ) {
  458. DBGC ( rndis, "RNDIS %s invalid link status:\n",
  459. rndis->name );
  460. DBGC_HDA ( rndis, 0, iobuf->data, len );
  461. rc = -EPROTO;
  462. goto err_link_status;
  463. }
  464. link_status = info;
  465. if ( *link_status == 0 ) {
  466. DBGC ( rndis, "RNDIS %s link is up\n", rndis->name );
  467. netdev_link_up ( netdev );
  468. } else {
  469. DBGC ( rndis, "RNDIS %s link is down: %#08x\n",
  470. rndis->name, le32_to_cpu ( *link_status ) );
  471. netdev_link_down ( netdev );
  472. }
  473. break;
  474. default:
  475. DBGC ( rndis, "RNDIS %s unexpected query completion ID %#08x\n",
  476. rndis->name, id );
  477. DBGC_HDA ( rndis, 0, iobuf->data, len );
  478. rc = -EPROTO;
  479. goto err_id;
  480. }
  481. /* Success */
  482. rc = 0;
  483. err_id:
  484. err_link_status:
  485. err_info:
  486. err_status:
  487. /* Record completion result if applicable */
  488. if ( id == rndis->wait_id ) {
  489. rndis->wait_id = 0;
  490. rndis->wait_rc = rc;
  491. }
  492. err_len:
  493. /* Free I/O buffer */
  494. free_iob ( iobuf );
  495. }
  496. /**
  497. * Receive set OID completion
  498. *
  499. * @v rndis RNDIS device
  500. * @v iobuf I/O buffer
  501. */
  502. static void rndis_rx_set_oid ( struct rndis_device *rndis,
  503. struct io_buffer *iobuf ) {
  504. struct rndis_set_completion *cmplt;
  505. size_t len = iob_len ( iobuf );
  506. unsigned int id;
  507. int rc;
  508. /* Sanity check */
  509. if ( len < sizeof ( *cmplt ) ) {
  510. DBGC ( rndis, "RNDIS %s received underlength set completion:\n",
  511. rndis->name );
  512. DBGC_HDA ( rndis, 0, iobuf->data, len );
  513. rc = -EINVAL;
  514. goto err_len;
  515. }
  516. cmplt = iobuf->data;
  517. /* Extract request ID */
  518. id = cmplt->id; /* Non-endian */
  519. /* Check status */
  520. if ( cmplt->status ) {
  521. DBGC ( rndis, "RNDIS %s received set completion failure "
  522. "%#08x\n", rndis->name, le32_to_cpu ( cmplt->status ) );
  523. DBGC_HDA ( rndis, 0, iobuf->data, len );
  524. rc = -EIO;
  525. goto err_status;
  526. }
  527. /* Success */
  528. rc = 0;
  529. err_status:
  530. /* Record completion result if applicable */
  531. if ( id == rndis->wait_id ) {
  532. rndis->wait_id = 0;
  533. rndis->wait_rc = rc;
  534. }
  535. err_len:
  536. /* Free I/O buffer */
  537. free_iob ( iobuf );
  538. }
  539. /**
  540. * Query or set OID
  541. *
  542. * @v rndis RNDIS device
  543. * @v oid Object ID
  544. * @v data New OID value (or NULL to query current value)
  545. * @v len Length of new OID value
  546. * @ret rc Return status code
  547. */
  548. static int rndis_oid ( struct rndis_device *rndis, unsigned int oid,
  549. const void *data, size_t len ) {
  550. int rc;
  551. /* Transmit query */
  552. if ( ( rc = rndis_tx_oid ( rndis, oid, data, len ) ) != 0 )
  553. return rc;
  554. /* Wait for response */
  555. if ( ( rc = rndis_wait ( rndis, oid ) ) != 0 )
  556. return rc;
  557. return 0;
  558. }
  559. /**
  560. * Receive indicate status message
  561. *
  562. * @v rndis RNDIS device
  563. * @v iobuf I/O buffer
  564. */
  565. static void rndis_rx_status ( struct rndis_device *rndis,
  566. struct io_buffer *iobuf ) {
  567. struct net_device *netdev = rndis->netdev;
  568. struct rndis_indicate_status_message *msg;
  569. size_t len = iob_len ( iobuf );
  570. unsigned int status;
  571. int rc;
  572. /* Sanity check */
  573. if ( len < sizeof ( *msg ) ) {
  574. DBGC ( rndis, "RNDIS %s received underlength status message:\n",
  575. rndis->name );
  576. DBGC_HDA ( rndis, 0, iobuf->data, len );
  577. rc = -EINVAL;
  578. goto err_len;
  579. }
  580. msg = iobuf->data;
  581. /* Extract status */
  582. status = le32_to_cpu ( msg->status );
  583. /* Handle status */
  584. switch ( msg->status ) {
  585. case RNDIS_STATUS_MEDIA_CONNECT:
  586. DBGC ( rndis, "RNDIS %s link is up\n", rndis->name );
  587. netdev_link_up ( netdev );
  588. break;
  589. case RNDIS_STATUS_MEDIA_DISCONNECT:
  590. DBGC ( rndis, "RNDIS %s link is down\n", rndis->name );
  591. netdev_link_down ( netdev );
  592. break;
  593. default:
  594. DBGC ( rndis, "RNDIS %s unexpected status %#08x:\n",
  595. rndis->name, status );
  596. DBGC_HDA ( rndis, 0, iobuf->data, len );
  597. rc = -ENOTSUP;
  598. goto err_status;
  599. }
  600. /* Free I/O buffer */
  601. free_iob ( iobuf );
  602. return;
  603. err_status:
  604. err_len:
  605. /* Report error via network device statistics */
  606. netdev_rx_err ( netdev, iobuf, rc );
  607. }
  608. /**
  609. * Receive RNDIS message
  610. *
  611. * @v rndis RNDIS device
  612. * @v iobuf I/O buffer
  613. * @v type Message type
  614. */
  615. static void rndis_rx_message ( struct rndis_device *rndis,
  616. struct io_buffer *iobuf, unsigned int type ) {
  617. struct net_device *netdev = rndis->netdev;
  618. int rc;
  619. /* Handle packet */
  620. switch ( type ) {
  621. case RNDIS_PACKET_MSG:
  622. rndis_rx_data ( rndis, iob_disown ( iobuf ) );
  623. break;
  624. case RNDIS_INITIALISE_CMPLT:
  625. rndis_rx_initialise ( rndis, iob_disown ( iobuf ) );
  626. break;
  627. case RNDIS_QUERY_CMPLT:
  628. rndis_rx_query_oid ( rndis, iob_disown ( iobuf ) );
  629. break;
  630. case RNDIS_SET_CMPLT:
  631. rndis_rx_set_oid ( rndis, iob_disown ( iobuf ) );
  632. break;
  633. case RNDIS_INDICATE_STATUS_MSG:
  634. rndis_rx_status ( rndis, iob_disown ( iobuf ) );
  635. break;
  636. default:
  637. DBGC ( rndis, "RNDIS %s received unexpected type %#08x\n",
  638. rndis->name, type );
  639. DBGC_HDA ( rndis, 0, iobuf->data, iob_len ( iobuf ) );
  640. rc = -EPROTO;
  641. goto err_type;
  642. }
  643. return;
  644. err_type:
  645. /* Report error via network device statistics */
  646. netdev_rx_err ( netdev, iobuf, rc );
  647. }
  648. /**
  649. * Receive packet from underlying transport layer
  650. *
  651. * @v rndis RNDIS device
  652. * @v iobuf I/O buffer
  653. */
  654. void rndis_rx ( struct rndis_device *rndis, struct io_buffer *iobuf ) {
  655. struct net_device *netdev = rndis->netdev;
  656. struct rndis_header *header;
  657. unsigned int type;
  658. int rc;
  659. /* Sanity check */
  660. if ( iob_len ( iobuf ) < sizeof ( *header ) ) {
  661. DBGC ( rndis, "RNDIS %s received underlength packet:\n",
  662. rndis->name );
  663. DBGC_HDA ( rndis, 0, iobuf->data, iob_len ( iobuf ) );
  664. rc = -EINVAL;
  665. goto drop;
  666. }
  667. header = iobuf->data;
  668. /* Parse and strip header */
  669. type = le32_to_cpu ( header->type );
  670. iob_pull ( iobuf, sizeof ( *header ) );
  671. /* Handle message */
  672. rndis_rx_message ( rndis, iob_disown ( iobuf ), type );
  673. return;
  674. drop:
  675. /* Record error */
  676. netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
  677. }
  678. /**
  679. * Set receive filter
  680. *
  681. * @v rndis RNDIS device
  682. * @v filter Receive filter
  683. * @ret rc Return status code
  684. */
  685. static int rndis_filter ( struct rndis_device *rndis, unsigned int filter ) {
  686. uint32_t value = cpu_to_le32 ( filter );
  687. int rc;
  688. /* Set receive filter */
  689. if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
  690. &value, sizeof ( value ) ) ) != 0 ) {
  691. DBGC ( rndis, "RNDIS %s could not set receive filter to %#08x: "
  692. "%s\n", rndis->name, filter, strerror ( rc ) );
  693. return rc;
  694. }
  695. return 0;
  696. }
  697. /**
  698. * Open network device
  699. *
  700. * @v netdev Network device
  701. * @ret rc Return status code
  702. */
  703. static int rndis_open ( struct net_device *netdev ) {
  704. struct rndis_device *rndis = netdev->priv;
  705. int rc;
  706. /* Open RNDIS device */
  707. if ( ( rc = rndis->op->open ( rndis ) ) != 0 ) {
  708. DBGC ( rndis, "RNDIS %s could not open: %s\n",
  709. rndis->name, strerror ( rc ) );
  710. goto err_open;
  711. }
  712. /* Initialise RNDIS */
  713. if ( ( rc = rndis_initialise ( rndis ) ) != 0 )
  714. goto err_initialise;
  715. /* Set receive filter */
  716. if ( ( rc = rndis_filter ( rndis, ( RNDIS_FILTER_UNICAST |
  717. RNDIS_FILTER_MULTICAST |
  718. RNDIS_FILTER_ALL_MULTICAST |
  719. RNDIS_FILTER_BROADCAST |
  720. RNDIS_FILTER_PROMISCUOUS ) ) ) != 0)
  721. goto err_set_filter;
  722. /* Update link status */
  723. if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
  724. NULL, 0 ) ) != 0 )
  725. goto err_query_link;
  726. return 0;
  727. err_query_link:
  728. err_set_filter:
  729. rndis_halt ( rndis );
  730. err_initialise:
  731. rndis->op->close ( rndis );
  732. err_open:
  733. return rc;
  734. }
  735. /**
  736. * Close network device
  737. *
  738. * @v netdev Network device
  739. */
  740. static void rndis_close ( struct net_device *netdev ) {
  741. struct rndis_device *rndis = netdev->priv;
  742. /* Clear receive filter */
  743. rndis_filter ( rndis, 0 );
  744. /* Halt RNDIS device */
  745. rndis_halt ( rndis );
  746. /* Close RNDIS device */
  747. rndis->op->close ( rndis );
  748. }
  749. /**
  750. * Transmit packet
  751. *
  752. * @v netdev Network device
  753. * @v iobuf I/O buffer
  754. * @ret rc Return status code
  755. */
  756. static int rndis_transmit ( struct net_device *netdev,
  757. struct io_buffer *iobuf ) {
  758. struct rndis_device *rndis = netdev->priv;
  759. /* Transmit data packet */
  760. return rndis_tx_data ( rndis, iobuf );
  761. }
  762. /**
  763. * Poll for completed and received packets
  764. *
  765. * @v netdev Network device
  766. */
  767. static void rndis_poll ( struct net_device *netdev ) {
  768. struct rndis_device *rndis = netdev->priv;
  769. /* Poll RNDIS device */
  770. rndis->op->poll ( rndis );
  771. }
  772. /** Network device operations */
  773. static struct net_device_operations rndis_operations = {
  774. .open = rndis_open,
  775. .close = rndis_close,
  776. .transmit = rndis_transmit,
  777. .poll = rndis_poll,
  778. };
  779. /**
  780. * Allocate RNDIS device
  781. *
  782. * @v priv_len Length of private data
  783. * @ret rndis RNDIS device, or NULL on allocation failure
  784. */
  785. struct rndis_device * alloc_rndis ( size_t priv_len ) {
  786. struct net_device *netdev;
  787. struct rndis_device *rndis;
  788. /* Allocate and initialise structure */
  789. netdev = alloc_etherdev ( sizeof ( *rndis ) + priv_len );
  790. if ( ! netdev )
  791. return NULL;
  792. netdev_init ( netdev, &rndis_operations );
  793. rndis = netdev->priv;
  794. rndis->netdev = netdev;
  795. rndis->priv = ( ( ( void * ) rndis ) + sizeof ( *rndis ) );
  796. return rndis;
  797. }
  798. /**
  799. * Register RNDIS device
  800. *
  801. * @v rndis RNDIS device
  802. * @ret rc Return status code
  803. *
  804. * Note that this routine will open and use the RNDIS device in order
  805. * to query the MAC address. The device must be immediately ready for
  806. * use prior to registration.
  807. */
  808. int register_rndis ( struct rndis_device *rndis ) {
  809. struct net_device *netdev = rndis->netdev;
  810. int rc;
  811. /* Assign device name (for debugging) */
  812. rndis->name = netdev->dev->name;
  813. /* Register network device */
  814. if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
  815. DBGC ( rndis, "RNDIS %s could not register: %s\n",
  816. rndis->name, strerror ( rc ) );
  817. goto err_register;
  818. }
  819. /* Open RNDIS device to read MAC addresses */
  820. if ( ( rc = rndis->op->open ( rndis ) ) != 0 ) {
  821. DBGC ( rndis, "RNDIS %s could not open: %s\n",
  822. rndis->name, strerror ( rc ) );
  823. goto err_open;
  824. }
  825. /* Initialise RNDIS */
  826. if ( ( rc = rndis_initialise ( rndis ) ) != 0 )
  827. goto err_initialise;
  828. /* Query permanent MAC address */
  829. if ( ( rc = rndis_oid ( rndis, RNDIS_OID_802_3_PERMANENT_ADDRESS,
  830. NULL, 0 ) ) != 0 )
  831. goto err_query_permanent;
  832. /* Query current MAC address */
  833. if ( ( rc = rndis_oid ( rndis, RNDIS_OID_802_3_CURRENT_ADDRESS,
  834. NULL, 0 ) ) != 0 )
  835. goto err_query_current;
  836. /* Get link status */
  837. if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
  838. NULL, 0 ) ) != 0 )
  839. goto err_query_link;
  840. /* Halt RNDIS device */
  841. rndis_halt ( rndis );
  842. /* Close RNDIS device */
  843. rndis->op->close ( rndis );
  844. return 0;
  845. err_query_link:
  846. err_query_current:
  847. err_query_permanent:
  848. rndis_halt ( rndis );
  849. err_initialise:
  850. rndis->op->close ( rndis );
  851. err_open:
  852. unregister_netdev ( netdev );
  853. err_register:
  854. return rc;
  855. }
  856. /**
  857. * Unregister RNDIS device
  858. *
  859. * @v rndis RNDIS device
  860. */
  861. void unregister_rndis ( struct rndis_device *rndis ) {
  862. struct net_device *netdev = rndis->netdev;
  863. /* Unregister network device */
  864. unregister_netdev ( netdev );
  865. }
  866. /**
  867. * Free RNDIS device
  868. *
  869. * @v rndis RNDIS device
  870. */
  871. void free_rndis ( struct rndis_device *rndis ) {
  872. struct net_device *netdev = rndis->netdev;
  873. /* Free network device */
  874. netdev_nullify ( netdev );
  875. netdev_put ( netdev );
  876. }