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

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048
  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. case RNDIS_STATUS_WTF_WORLD:
  594. /* Ignore */
  595. break;
  596. default:
  597. DBGC ( rndis, "RNDIS %s unexpected status %#08x:\n",
  598. rndis->name, status );
  599. DBGC_HDA ( rndis, 0, iobuf->data, len );
  600. rc = -ENOTSUP;
  601. goto err_status;
  602. }
  603. /* Free I/O buffer */
  604. free_iob ( iobuf );
  605. return;
  606. err_status:
  607. err_len:
  608. /* Report error via network device statistics */
  609. netdev_rx_err ( netdev, iobuf, rc );
  610. }
  611. /**
  612. * Receive RNDIS message
  613. *
  614. * @v rndis RNDIS device
  615. * @v iobuf I/O buffer
  616. * @v type Message type
  617. */
  618. static void rndis_rx_message ( struct rndis_device *rndis,
  619. struct io_buffer *iobuf, unsigned int type ) {
  620. struct net_device *netdev = rndis->netdev;
  621. int rc;
  622. /* Handle packet */
  623. switch ( type ) {
  624. case RNDIS_PACKET_MSG:
  625. rndis_rx_data ( rndis, iob_disown ( iobuf ) );
  626. break;
  627. case RNDIS_INITIALISE_CMPLT:
  628. rndis_rx_initialise ( rndis, iob_disown ( iobuf ) );
  629. break;
  630. case RNDIS_QUERY_CMPLT:
  631. rndis_rx_query_oid ( rndis, iob_disown ( iobuf ) );
  632. break;
  633. case RNDIS_SET_CMPLT:
  634. rndis_rx_set_oid ( rndis, iob_disown ( iobuf ) );
  635. break;
  636. case RNDIS_INDICATE_STATUS_MSG:
  637. rndis_rx_status ( rndis, iob_disown ( iobuf ) );
  638. break;
  639. default:
  640. DBGC ( rndis, "RNDIS %s received unexpected type %#08x\n",
  641. rndis->name, type );
  642. DBGC_HDA ( rndis, 0, iobuf->data, iob_len ( iobuf ) );
  643. rc = -EPROTO;
  644. goto err_type;
  645. }
  646. return;
  647. err_type:
  648. /* Report error via network device statistics */
  649. netdev_rx_err ( netdev, iobuf, rc );
  650. }
  651. /**
  652. * Receive packet from underlying transport layer
  653. *
  654. * @v rndis RNDIS device
  655. * @v iobuf I/O buffer
  656. */
  657. void rndis_rx ( struct rndis_device *rndis, struct io_buffer *iobuf ) {
  658. struct net_device *netdev = rndis->netdev;
  659. struct rndis_header *header;
  660. unsigned int type;
  661. int rc;
  662. /* Sanity check */
  663. if ( iob_len ( iobuf ) < sizeof ( *header ) ) {
  664. DBGC ( rndis, "RNDIS %s received underlength packet:\n",
  665. rndis->name );
  666. DBGC_HDA ( rndis, 0, iobuf->data, iob_len ( iobuf ) );
  667. rc = -EINVAL;
  668. goto drop;
  669. }
  670. header = iobuf->data;
  671. /* Parse and strip header */
  672. type = le32_to_cpu ( header->type );
  673. iob_pull ( iobuf, sizeof ( *header ) );
  674. /* Handle message */
  675. rndis_rx_message ( rndis, iob_disown ( iobuf ), type );
  676. return;
  677. drop:
  678. /* Record error */
  679. netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
  680. }
  681. /**
  682. * Discard packet from underlying transport layer
  683. *
  684. * @v rndis RNDIS device
  685. * @v iobuf I/O buffer
  686. * @v rc Packet status code
  687. */
  688. void rndis_rx_err ( struct rndis_device *rndis, struct io_buffer *iobuf,
  689. int rc ) {
  690. struct net_device *netdev = rndis->netdev;
  691. /* Record error */
  692. netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
  693. }
  694. /**
  695. * Set receive filter
  696. *
  697. * @v rndis RNDIS device
  698. * @v filter Receive filter
  699. * @ret rc Return status code
  700. */
  701. static int rndis_filter ( struct rndis_device *rndis, unsigned int filter ) {
  702. uint32_t value = cpu_to_le32 ( filter );
  703. int rc;
  704. /* Set receive filter */
  705. if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
  706. &value, sizeof ( value ) ) ) != 0 ) {
  707. DBGC ( rndis, "RNDIS %s could not set receive filter to %#08x: "
  708. "%s\n", rndis->name, filter, strerror ( rc ) );
  709. return rc;
  710. }
  711. return 0;
  712. }
  713. /**
  714. * Open network device
  715. *
  716. * @v netdev Network device
  717. * @ret rc Return status code
  718. */
  719. static int rndis_open ( struct net_device *netdev ) {
  720. struct rndis_device *rndis = netdev->priv;
  721. int rc;
  722. /* Open RNDIS device */
  723. if ( ( rc = rndis->op->open ( rndis ) ) != 0 ) {
  724. DBGC ( rndis, "RNDIS %s could not open: %s\n",
  725. rndis->name, strerror ( rc ) );
  726. goto err_open;
  727. }
  728. /* Initialise RNDIS */
  729. if ( ( rc = rndis_initialise ( rndis ) ) != 0 )
  730. goto err_initialise;
  731. /* Set receive filter */
  732. if ( ( rc = rndis_filter ( rndis, ( RNDIS_FILTER_UNICAST |
  733. RNDIS_FILTER_MULTICAST |
  734. RNDIS_FILTER_ALL_MULTICAST |
  735. RNDIS_FILTER_BROADCAST |
  736. RNDIS_FILTER_PROMISCUOUS ) ) ) != 0)
  737. goto err_set_filter;
  738. /* Update link status */
  739. if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
  740. NULL, 0 ) ) != 0 )
  741. goto err_query_link;
  742. return 0;
  743. err_query_link:
  744. err_set_filter:
  745. rndis_halt ( rndis );
  746. err_initialise:
  747. rndis->op->close ( rndis );
  748. err_open:
  749. return rc;
  750. }
  751. /**
  752. * Close network device
  753. *
  754. * @v netdev Network device
  755. */
  756. static void rndis_close ( struct net_device *netdev ) {
  757. struct rndis_device *rndis = netdev->priv;
  758. /* Clear receive filter */
  759. rndis_filter ( rndis, 0 );
  760. /* Halt RNDIS device */
  761. rndis_halt ( rndis );
  762. /* Close RNDIS device */
  763. rndis->op->close ( rndis );
  764. }
  765. /**
  766. * Transmit packet
  767. *
  768. * @v netdev Network device
  769. * @v iobuf I/O buffer
  770. * @ret rc Return status code
  771. */
  772. static int rndis_transmit ( struct net_device *netdev,
  773. struct io_buffer *iobuf ) {
  774. struct rndis_device *rndis = netdev->priv;
  775. /* Transmit data packet */
  776. return rndis_tx_data ( rndis, iobuf );
  777. }
  778. /**
  779. * Poll for completed and received packets
  780. *
  781. * @v netdev Network device
  782. */
  783. static void rndis_poll ( struct net_device *netdev ) {
  784. struct rndis_device *rndis = netdev->priv;
  785. /* Poll RNDIS device */
  786. rndis->op->poll ( rndis );
  787. }
  788. /** Network device operations */
  789. static struct net_device_operations rndis_operations = {
  790. .open = rndis_open,
  791. .close = rndis_close,
  792. .transmit = rndis_transmit,
  793. .poll = rndis_poll,
  794. };
  795. /**
  796. * Allocate RNDIS device
  797. *
  798. * @v priv_len Length of private data
  799. * @ret rndis RNDIS device, or NULL on allocation failure
  800. */
  801. struct rndis_device * alloc_rndis ( size_t priv_len ) {
  802. struct net_device *netdev;
  803. struct rndis_device *rndis;
  804. /* Allocate and initialise structure */
  805. netdev = alloc_etherdev ( sizeof ( *rndis ) + priv_len );
  806. if ( ! netdev )
  807. return NULL;
  808. netdev_init ( netdev, &rndis_operations );
  809. rndis = netdev->priv;
  810. rndis->netdev = netdev;
  811. rndis->priv = ( ( ( void * ) rndis ) + sizeof ( *rndis ) );
  812. return rndis;
  813. }
  814. /**
  815. * Register RNDIS device
  816. *
  817. * @v rndis RNDIS device
  818. * @ret rc Return status code
  819. *
  820. * Note that this routine will open and use the RNDIS device in order
  821. * to query the MAC address. The device must be immediately ready for
  822. * use prior to registration.
  823. */
  824. int register_rndis ( struct rndis_device *rndis ) {
  825. struct net_device *netdev = rndis->netdev;
  826. int rc;
  827. /* Assign device name (for debugging) */
  828. rndis->name = netdev->dev->name;
  829. /* Register network device */
  830. if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
  831. DBGC ( rndis, "RNDIS %s could not register: %s\n",
  832. rndis->name, strerror ( rc ) );
  833. goto err_register;
  834. }
  835. /* Open RNDIS device to read MAC addresses */
  836. if ( ( rc = rndis->op->open ( rndis ) ) != 0 ) {
  837. DBGC ( rndis, "RNDIS %s could not open: %s\n",
  838. rndis->name, strerror ( rc ) );
  839. goto err_open;
  840. }
  841. /* Initialise RNDIS */
  842. if ( ( rc = rndis_initialise ( rndis ) ) != 0 )
  843. goto err_initialise;
  844. /* Query permanent MAC address */
  845. if ( ( rc = rndis_oid ( rndis, RNDIS_OID_802_3_PERMANENT_ADDRESS,
  846. NULL, 0 ) ) != 0 )
  847. goto err_query_permanent;
  848. /* Query current MAC address */
  849. if ( ( rc = rndis_oid ( rndis, RNDIS_OID_802_3_CURRENT_ADDRESS,
  850. NULL, 0 ) ) != 0 )
  851. goto err_query_current;
  852. /* Get link status */
  853. if ( ( rc = rndis_oid ( rndis, RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
  854. NULL, 0 ) ) != 0 )
  855. goto err_query_link;
  856. /* Halt RNDIS device */
  857. rndis_halt ( rndis );
  858. /* Close RNDIS device */
  859. rndis->op->close ( rndis );
  860. return 0;
  861. err_query_link:
  862. err_query_current:
  863. err_query_permanent:
  864. rndis_halt ( rndis );
  865. err_initialise:
  866. rndis->op->close ( rndis );
  867. err_open:
  868. unregister_netdev ( netdev );
  869. err_register:
  870. return rc;
  871. }
  872. /**
  873. * Unregister RNDIS device
  874. *
  875. * @v rndis RNDIS device
  876. */
  877. void unregister_rndis ( struct rndis_device *rndis ) {
  878. struct net_device *netdev = rndis->netdev;
  879. /* Unregister network device */
  880. unregister_netdev ( netdev );
  881. }
  882. /**
  883. * Free RNDIS device
  884. *
  885. * @v rndis RNDIS device
  886. */
  887. void free_rndis ( struct rndis_device *rndis ) {
  888. struct net_device *netdev = rndis->netdev;
  889. /* Free network device */
  890. netdev_nullify ( netdev );
  891. netdev_put ( netdev );
  892. }