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

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