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.

ndp.c 36KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304
  1. /*
  2. * Copyright (C) 2013 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 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. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <errno.h>
  24. #include <byteswap.h>
  25. #include <ipxe/in.h>
  26. #include <ipxe/iobuf.h>
  27. #include <ipxe/tcpip.h>
  28. #include <ipxe/ipv6.h>
  29. #include <ipxe/icmpv6.h>
  30. #include <ipxe/neighbour.h>
  31. #include <ipxe/dhcpv6.h>
  32. #include <ipxe/ndp.h>
  33. /** @file
  34. *
  35. * IPv6 neighbour discovery protocol
  36. *
  37. */
  38. static struct ipv6conf * ipv6conf_demux ( struct net_device *netdev );
  39. static int
  40. ipv6conf_rx_router_advertisement ( struct net_device *netdev,
  41. struct in6_addr *router,
  42. struct ndp_router_advertisement_header *radv,
  43. size_t len );
  44. /**
  45. * Transmit NDP packet with link-layer address option
  46. *
  47. * @v netdev Network device
  48. * @v sin6_src Source socket address
  49. * @v sin6_dest Destination socket address
  50. * @v data NDP header
  51. * @v len Size of NDP header
  52. * @v option_type NDP option type
  53. * @ret rc Return status code
  54. */
  55. static int ndp_tx_ll_addr ( struct net_device *netdev,
  56. struct sockaddr_in6 *sin6_src,
  57. struct sockaddr_in6 *sin6_dest,
  58. const void *data, size_t len,
  59. unsigned int option_type ) {
  60. struct sockaddr_tcpip *st_src =
  61. ( ( struct sockaddr_tcpip * ) sin6_src );
  62. struct sockaddr_tcpip *st_dest =
  63. ( ( struct sockaddr_tcpip * ) sin6_dest );
  64. struct ll_protocol *ll_protocol = netdev->ll_protocol;
  65. struct io_buffer *iobuf;
  66. struct ndp_ll_addr_option *ll_addr_opt;
  67. union ndp_header *ndp;
  68. size_t option_len;
  69. int rc;
  70. /* Allocate and populate buffer */
  71. option_len = ( ( sizeof ( *ll_addr_opt ) +
  72. ll_protocol->ll_addr_len + NDP_OPTION_BLKSZ - 1 ) &
  73. ~( NDP_OPTION_BLKSZ - 1 ) );
  74. iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len + option_len );
  75. if ( ! iobuf )
  76. return -ENOMEM;
  77. iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN );
  78. memcpy ( iob_put ( iobuf, len ), data, len );
  79. ll_addr_opt = iob_put ( iobuf, option_len );
  80. ll_addr_opt->header.type = option_type;
  81. ll_addr_opt->header.blocks = ( option_len / NDP_OPTION_BLKSZ );
  82. memcpy ( ll_addr_opt->ll_addr, netdev->ll_addr,
  83. ll_protocol->ll_addr_len );
  84. ndp = iobuf->data;
  85. ndp->icmp.chksum = tcpip_chksum ( ndp, ( len + option_len ) );
  86. /* Transmit packet */
  87. if ( ( rc = tcpip_tx ( iobuf, &icmpv6_protocol, st_src, st_dest,
  88. netdev, &ndp->icmp.chksum ) ) != 0 ) {
  89. DBGC ( netdev, "NDP %s could not transmit packet: %s\n",
  90. netdev->name, strerror ( rc ) );
  91. return rc;
  92. }
  93. return 0;
  94. }
  95. /**
  96. * Transmit NDP neighbour discovery request
  97. *
  98. * @v netdev Network device
  99. * @v net_protocol Network-layer protocol
  100. * @v net_dest Destination network-layer address
  101. * @v net_source Source network-layer address
  102. * @ret rc Return status code
  103. */
  104. static int ndp_tx_request ( struct net_device *netdev,
  105. struct net_protocol *net_protocol __unused,
  106. const void *net_dest, const void *net_source ) {
  107. struct sockaddr_in6 sin6_src;
  108. struct sockaddr_in6 sin6_dest;
  109. struct ndp_neighbour_header neigh;
  110. int rc;
  111. /* Construct source address */
  112. memset ( &sin6_src, 0, sizeof ( sin6_src ) );
  113. sin6_src.sin6_family = AF_INET6;
  114. memcpy ( &sin6_src.sin6_addr, net_source,
  115. sizeof ( sin6_src.sin6_addr ) );
  116. /* Construct multicast destination address */
  117. memset ( &sin6_dest, 0, sizeof ( sin6_dest ) );
  118. sin6_dest.sin6_family = AF_INET6;
  119. sin6_dest.sin6_scope_id = netdev->index;
  120. ipv6_solicited_node ( &sin6_dest.sin6_addr, net_dest );
  121. /* Construct neighbour header */
  122. memset ( &neigh, 0, sizeof ( neigh ) );
  123. neigh.icmp.type = ICMPV6_NEIGHBOUR_SOLICITATION;
  124. memcpy ( &neigh.target, net_dest, sizeof ( neigh.target ) );
  125. /* Transmit neighbour discovery packet */
  126. if ( ( rc = ndp_tx_ll_addr ( netdev, &sin6_src, &sin6_dest, &neigh,
  127. sizeof ( neigh ),
  128. NDP_OPT_LL_SOURCE ) ) != 0 )
  129. return rc;
  130. return 0;
  131. }
  132. /** NDP neighbour discovery protocol */
  133. struct neighbour_discovery ndp_discovery = {
  134. .name = "NDP",
  135. .tx_request = ndp_tx_request,
  136. };
  137. /**
  138. * Transmit NDP router solicitation
  139. *
  140. * @v netdev Network device
  141. * @ret rc Return status code
  142. */
  143. static int ndp_tx_router_solicitation ( struct net_device *netdev ) {
  144. struct ndp_router_solicitation_header rsol;
  145. struct sockaddr_in6 sin6_dest;
  146. int rc;
  147. /* Construct multicast destination address */
  148. memset ( &sin6_dest, 0, sizeof ( sin6_dest ) );
  149. sin6_dest.sin6_family = AF_INET6;
  150. sin6_dest.sin6_scope_id = netdev->index;
  151. ipv6_all_routers ( &sin6_dest.sin6_addr );
  152. /* Construct router solicitation */
  153. memset ( &rsol, 0, sizeof ( rsol ) );
  154. rsol.icmp.type = ICMPV6_ROUTER_SOLICITATION;
  155. /* Transmit packet */
  156. if ( ( rc = ndp_tx_ll_addr ( netdev, NULL, &sin6_dest, &rsol,
  157. sizeof ( rsol ), NDP_OPT_LL_SOURCE ) ) !=0)
  158. return rc;
  159. return 0;
  160. }
  161. /**
  162. * Process NDP neighbour solicitation source link-layer address option
  163. *
  164. * @v netdev Network device
  165. * @v sin6_src Source socket address
  166. * @v ndp NDP packet
  167. * @v option NDP option
  168. * @v len NDP option length
  169. * @ret rc Return status code
  170. */
  171. static int
  172. ndp_rx_neighbour_solicitation_ll_source ( struct net_device *netdev,
  173. struct sockaddr_in6 *sin6_src,
  174. union ndp_header *ndp,
  175. union ndp_option *option,
  176. size_t len ) {
  177. struct ndp_neighbour_header *neigh = &ndp->neigh;
  178. struct ndp_ll_addr_option *ll_addr_opt = &option->ll_addr;
  179. struct ll_protocol *ll_protocol = netdev->ll_protocol;
  180. int rc;
  181. /* Silently ignore neighbour solicitations for addresses we do
  182. * not own.
  183. */
  184. if ( ! ipv6_has_addr ( netdev, &neigh->target ) )
  185. return 0;
  186. /* Sanity check */
  187. if ( offsetof ( typeof ( *ll_addr_opt ),
  188. ll_addr[ll_protocol->ll_addr_len] ) > len ) {
  189. DBGC ( netdev, "NDP %s neighbour solicitation link-layer "
  190. "address option too short at %zd bytes\n",
  191. netdev->name, len );
  192. return -EINVAL;
  193. }
  194. /* Create or update neighbour cache entry */
  195. if ( ( rc = neighbour_define ( netdev, &ipv6_protocol,
  196. &sin6_src->sin6_addr,
  197. ll_addr_opt->ll_addr ) ) != 0 ) {
  198. DBGC ( netdev, "NDP %s could not define %s => %s: %s\n",
  199. netdev->name, inet6_ntoa ( &sin6_src->sin6_addr ),
  200. ll_protocol->ntoa ( ll_addr_opt->ll_addr ),
  201. strerror ( rc ) );
  202. return rc;
  203. }
  204. /* Convert neighbour header to advertisement */
  205. memset ( neigh, 0, offsetof ( typeof ( *neigh ), target ) );
  206. neigh->icmp.type = ICMPV6_NEIGHBOUR_ADVERTISEMENT;
  207. neigh->flags = ( NDP_NEIGHBOUR_SOLICITED | NDP_NEIGHBOUR_OVERRIDE );
  208. /* Send neighbour advertisement */
  209. if ( ( rc = ndp_tx_ll_addr ( netdev, NULL, sin6_src, neigh,
  210. sizeof ( *neigh ),
  211. NDP_OPT_LL_TARGET ) ) != 0 )
  212. return rc;
  213. return 0;
  214. }
  215. /**
  216. * Process NDP neighbour advertisement target link-layer address option
  217. *
  218. * @v netdev Network device
  219. * @v sin6_src Source socket address
  220. * @v ndp NDP packet
  221. * @v option NDP option
  222. * @v len NDP option length
  223. * @ret rc Return status code
  224. */
  225. static int
  226. ndp_rx_neighbour_advertisement_ll_target ( struct net_device *netdev,
  227. struct sockaddr_in6 *sin6_src
  228. __unused,
  229. union ndp_header *ndp,
  230. union ndp_option *option,
  231. size_t len ) {
  232. struct ndp_neighbour_header *neigh = &ndp->neigh;
  233. struct ndp_ll_addr_option *ll_addr_opt = &option->ll_addr;
  234. struct ll_protocol *ll_protocol = netdev->ll_protocol;
  235. int rc;
  236. /* Sanity check */
  237. if ( offsetof ( typeof ( *ll_addr_opt ),
  238. ll_addr[ll_protocol->ll_addr_len] ) > len ) {
  239. DBGC ( netdev, "NDP %s neighbour advertisement link-layer "
  240. "address option too short at %zd bytes\n",
  241. netdev->name, len );
  242. return -EINVAL;
  243. }
  244. /* Update neighbour cache entry, if any */
  245. if ( ( rc = neighbour_update ( netdev, &ipv6_protocol, &neigh->target,
  246. ll_addr_opt->ll_addr ) ) != 0 ) {
  247. DBGC ( netdev, "NDP %s could not update %s => %s: %s\n",
  248. netdev->name, inet6_ntoa ( &neigh->target ),
  249. ll_protocol->ntoa ( ll_addr_opt->ll_addr ),
  250. strerror ( rc ) );
  251. return rc;
  252. }
  253. return 0;
  254. }
  255. /**
  256. * Process NDP router advertisement source link-layer address option
  257. *
  258. * @v netdev Network device
  259. * @v sin6_src Source socket address
  260. * @v ndp NDP packet
  261. * @v option NDP option
  262. * @v len NDP option length
  263. * @ret rc Return status code
  264. */
  265. static int
  266. ndp_rx_router_advertisement_ll_source ( struct net_device *netdev,
  267. struct sockaddr_in6 *sin6_src,
  268. union ndp_header *ndp __unused,
  269. union ndp_option *option, size_t len ) {
  270. struct ndp_ll_addr_option *ll_addr_opt = &option->ll_addr;
  271. struct ll_protocol *ll_protocol = netdev->ll_protocol;
  272. int rc;
  273. /* Sanity check */
  274. if ( offsetof ( typeof ( *ll_addr_opt ),
  275. ll_addr[ll_protocol->ll_addr_len] ) > len ) {
  276. DBGC ( netdev, "NDP %s router advertisement link-layer address "
  277. "option too short at %zd bytes\n", netdev->name, len );
  278. return -EINVAL;
  279. }
  280. /* Define neighbour cache entry */
  281. if ( ( rc = neighbour_define ( netdev, &ipv6_protocol,
  282. &sin6_src->sin6_addr,
  283. ll_addr_opt->ll_addr ) ) != 0 ) {
  284. DBGC ( netdev, "NDP %s could not define %s => %s: %s\n",
  285. netdev->name, inet6_ntoa ( &sin6_src->sin6_addr ),
  286. ll_protocol->ntoa ( ll_addr_opt->ll_addr ),
  287. strerror ( rc ) );
  288. return rc;
  289. }
  290. return 0;
  291. }
  292. /**
  293. * Process NDP router advertisement prefix information option
  294. *
  295. * @v netdev Network device
  296. * @v sin6_src Source socket address
  297. * @v ndp NDP packet
  298. * @v option NDP option
  299. * @v len NDP option length
  300. * @ret rc Return status code
  301. */
  302. static int
  303. ndp_rx_router_advertisement_prefix ( struct net_device *netdev,
  304. struct sockaddr_in6 *sin6_src,
  305. union ndp_header *ndp,
  306. union ndp_option *option, size_t len ) {
  307. struct ndp_router_advertisement_header *radv = &ndp->radv;
  308. struct ndp_prefix_information_option *prefix_opt = &option->prefix;
  309. struct in6_addr *router = &sin6_src->sin6_addr;
  310. struct in6_addr address;
  311. struct ipv6conf *ipv6conf;
  312. int prefix_len;
  313. int rc;
  314. /* Sanity check */
  315. if ( sizeof ( *prefix_opt ) > len ) {
  316. DBGC ( netdev, "NDP %s router advertisement prefix option too "
  317. "short at %zd bytes\n", netdev->name, len );
  318. return -EINVAL;
  319. }
  320. /* Identify IPv6 configurator, if any */
  321. ipv6conf = ipv6conf_demux ( netdev );
  322. DBGC ( netdev, "NDP %s found %sdefault router %s ",
  323. netdev->name, ( radv->lifetime ? "" : "non-" ),
  324. inet6_ntoa ( &sin6_src->sin6_addr ) );
  325. DBGC ( netdev, "for %s-link %sautonomous prefix %s/%d%s\n",
  326. ( ( prefix_opt->flags & NDP_PREFIX_ON_LINK ) ? "on" : "off" ),
  327. ( ( prefix_opt->flags & NDP_PREFIX_AUTONOMOUS ) ? "" : "non-" ),
  328. inet6_ntoa ( &prefix_opt->prefix ),
  329. prefix_opt->prefix_len, ( ipv6conf ? "" : " (ignored)" ) );
  330. /* Do nothing unless IPv6 autoconfiguration is in progress */
  331. if ( ! ipv6conf )
  332. return 0;
  333. /* Ignore off-link prefixes */
  334. if ( ! ( prefix_opt->flags & NDP_PREFIX_ON_LINK ) )
  335. return 0;
  336. /* Define prefix */
  337. if ( ( rc = ipv6_set_prefix ( netdev, &prefix_opt->prefix,
  338. prefix_opt->prefix_len,
  339. ( radv->lifetime ?
  340. router : NULL ) ) ) != 0 ) {
  341. DBGC ( netdev, "NDP %s could not define prefix %s/%d: %s\n",
  342. netdev->name, inet6_ntoa ( &prefix_opt->prefix ),
  343. prefix_opt->prefix_len, strerror ( rc ) );
  344. return rc;
  345. }
  346. /* Perform stateless address autoconfiguration, if applicable */
  347. if ( prefix_opt->flags & NDP_PREFIX_AUTONOMOUS ) {
  348. memcpy ( &address, &prefix_opt->prefix, sizeof ( address ) );
  349. prefix_len = ipv6_eui64 ( &address, netdev );
  350. if ( prefix_len < 0 ) {
  351. rc = prefix_len;
  352. DBGC ( netdev, "NDP %s could not construct SLAAC "
  353. "address: %s\n", netdev->name, strerror ( rc ) );
  354. return rc;
  355. }
  356. if ( prefix_len != prefix_opt->prefix_len ) {
  357. DBGC ( netdev, "NDP %s incorrect SLAAC prefix length "
  358. "%d (expected %d)\n", netdev->name,
  359. prefix_opt->prefix_len, prefix_len );
  360. return -EINVAL;
  361. }
  362. if ( ( rc = ipv6_set_address ( netdev, &address ) ) != 0 ) {
  363. DBGC ( netdev, "NDP %s could not set address %s: %s\n",
  364. netdev->name, inet6_ntoa ( &address ),
  365. strerror ( rc ) );
  366. return rc;
  367. }
  368. }
  369. return 0;
  370. }
  371. /** An NDP option handler */
  372. struct ndp_option_handler {
  373. /** ICMPv6 type */
  374. uint8_t icmp_type;
  375. /** Option type */
  376. uint8_t option_type;
  377. /**
  378. * Handle received option
  379. *
  380. * @v netdev Network device
  381. * @v sin6_src Source socket address
  382. * @v ndp NDP packet
  383. * @v option NDP option
  384. * @ret rc Return status code
  385. */
  386. int ( * rx ) ( struct net_device *netdev, struct sockaddr_in6 *sin6_src,
  387. union ndp_header *ndp, union ndp_option *option,
  388. size_t len );
  389. };
  390. /** NDP option handlers */
  391. static struct ndp_option_handler ndp_option_handlers[] = {
  392. {
  393. .icmp_type = ICMPV6_NEIGHBOUR_SOLICITATION,
  394. .option_type = NDP_OPT_LL_SOURCE,
  395. .rx = ndp_rx_neighbour_solicitation_ll_source,
  396. },
  397. {
  398. .icmp_type = ICMPV6_NEIGHBOUR_ADVERTISEMENT,
  399. .option_type = NDP_OPT_LL_TARGET,
  400. .rx = ndp_rx_neighbour_advertisement_ll_target,
  401. },
  402. {
  403. .icmp_type = ICMPV6_ROUTER_ADVERTISEMENT,
  404. .option_type = NDP_OPT_LL_SOURCE,
  405. .rx = ndp_rx_router_advertisement_ll_source,
  406. },
  407. {
  408. .icmp_type = ICMPV6_ROUTER_ADVERTISEMENT,
  409. .option_type = NDP_OPT_PREFIX,
  410. .rx = ndp_rx_router_advertisement_prefix,
  411. },
  412. };
  413. /**
  414. * Process received NDP option
  415. *
  416. * @v netdev Network device
  417. * @v sin6_src Source socket address
  418. * @v ndp NDP packet
  419. * @v option NDP option
  420. * @v len Option length
  421. * @ret rc Return status code
  422. */
  423. static int ndp_rx_option ( struct net_device *netdev,
  424. struct sockaddr_in6 *sin6_src, union ndp_header *ndp,
  425. union ndp_option *option, size_t len ) {
  426. struct ndp_option_handler *handler;
  427. unsigned int i;
  428. /* Locate a suitable option handler, if any */
  429. for ( i = 0 ; i < ( sizeof ( ndp_option_handlers ) /
  430. sizeof ( ndp_option_handlers[0] ) ) ; i++ ) {
  431. handler = &ndp_option_handlers[i];
  432. if ( ( handler->icmp_type == ndp->icmp.type ) &&
  433. ( handler->option_type == option->header.type ) ) {
  434. return handler->rx ( netdev, sin6_src, ndp,
  435. option, len );
  436. }
  437. }
  438. /* Silently ignore unknown options as per RFC 4861 */
  439. return 0;
  440. }
  441. /**
  442. * Process received NDP packet options
  443. *
  444. * @v netdev Network device
  445. * @v sin6_src Source socket address
  446. * @v ndp NDP header
  447. * @v offset Offset to NDP options
  448. * @v len Length of NDP packet
  449. * @ret rc Return status code
  450. */
  451. static int ndp_rx_options ( struct net_device *netdev,
  452. struct sockaddr_in6 *sin6_src,
  453. union ndp_header *ndp, size_t offset, size_t len ) {
  454. union ndp_option *option;
  455. size_t remaining;
  456. size_t option_len;
  457. int rc;
  458. /* Sanity check */
  459. if ( len < offset ) {
  460. DBGC ( netdev, "NDP %s packet too short at %zd bytes (min %zd "
  461. "bytes)\n", netdev->name, len, offset );
  462. return -EINVAL;
  463. }
  464. /* Search for option */
  465. option = ( ( ( void * ) ndp ) + offset );
  466. remaining = ( len - offset );
  467. while ( remaining ) {
  468. /* Sanity check */
  469. if ( ( remaining < sizeof ( option->header ) ) ||
  470. ( option->header.blocks == 0 ) ||
  471. ( remaining < ( option->header.blocks *
  472. NDP_OPTION_BLKSZ ) ) ) {
  473. DBGC ( netdev, "NDP %s bad option length:\n",
  474. netdev->name );
  475. DBGC_HDA ( netdev, 0, option, remaining );
  476. return -EINVAL;
  477. }
  478. option_len = ( option->header.blocks * NDP_OPTION_BLKSZ );
  479. /* Handle option */
  480. if ( ( rc = ndp_rx_option ( netdev, sin6_src, ndp, option,
  481. option_len ) ) != 0 )
  482. return rc;
  483. /* Move to next option */
  484. option = ( ( ( void * ) option ) + option_len );
  485. remaining -= option_len;
  486. }
  487. return 0;
  488. }
  489. /**
  490. * Process received NDP neighbour solicitation or advertisement
  491. *
  492. * @v iobuf I/O buffer
  493. * @v netdev Network device
  494. * @v sin6_src Source socket address
  495. * @v sin6_dest Destination socket address
  496. * @ret rc Return status code
  497. */
  498. static int ndp_rx_neighbour ( struct io_buffer *iobuf,
  499. struct net_device *netdev,
  500. struct sockaddr_in6 *sin6_src,
  501. struct sockaddr_in6 *sin6_dest __unused ) {
  502. union ndp_header *ndp = iobuf->data;
  503. struct ndp_neighbour_header *neigh = &ndp->neigh;
  504. size_t len = iob_len ( iobuf );
  505. int rc;
  506. /* Process options */
  507. if ( ( rc = ndp_rx_options ( netdev, sin6_src, ndp,
  508. offsetof ( typeof ( *neigh ), option ),
  509. len ) ) != 0 )
  510. goto err_options;
  511. err_options:
  512. free_iob ( iobuf );
  513. return rc;
  514. }
  515. /**
  516. * Process received NDP router advertisement
  517. *
  518. * @v iobuf I/O buffer
  519. * @v netdev Network device
  520. * @v sin6_src Source socket address
  521. * @v sin6_dest Destination socket address
  522. * @ret rc Return status code
  523. */
  524. static int
  525. ndp_rx_router_advertisement ( struct io_buffer *iobuf,
  526. struct net_device *netdev,
  527. struct sockaddr_in6 *sin6_src,
  528. struct sockaddr_in6 *sin6_dest __unused ) {
  529. union ndp_header *ndp = iobuf->data;
  530. struct ndp_router_advertisement_header *radv = &ndp->radv;
  531. struct in6_addr *router = &sin6_src->sin6_addr;
  532. size_t len = iob_len ( iobuf );
  533. int rc;
  534. /* Process options */
  535. if ( ( rc = ndp_rx_options ( netdev, sin6_src, ndp,
  536. offsetof ( typeof ( *radv ), option ),
  537. len ) ) != 0 )
  538. goto err_options;
  539. /* Pass to IPv6 autoconfiguration */
  540. if ( ( rc = ipv6conf_rx_router_advertisement ( netdev, router,
  541. radv, len ) ) != 0 )
  542. goto err_ipv6conf;
  543. err_ipv6conf:
  544. err_options:
  545. free_iob ( iobuf );
  546. return rc;
  547. }
  548. /** NDP ICMPv6 handlers */
  549. struct icmpv6_handler ndp_handlers[] __icmpv6_handler = {
  550. {
  551. .type = ICMPV6_NEIGHBOUR_SOLICITATION,
  552. .rx = ndp_rx_neighbour,
  553. },
  554. {
  555. .type = ICMPV6_NEIGHBOUR_ADVERTISEMENT,
  556. .rx = ndp_rx_neighbour,
  557. },
  558. {
  559. .type = ICMPV6_ROUTER_ADVERTISEMENT,
  560. .rx = ndp_rx_router_advertisement,
  561. },
  562. };
  563. /****************************************************************************
  564. *
  565. * NDP settings
  566. *
  567. */
  568. /** An NDP prefix settings block */
  569. struct ndp_prefix_settings {
  570. /** Settings interface */
  571. struct settings settings;
  572. /** Name */
  573. char name[4];
  574. /** Prefix information option */
  575. struct ndp_prefix_information_option *prefix;
  576. };
  577. /** An NDP settings block */
  578. struct ndp_settings {
  579. /** Reference counter */
  580. struct refcnt refcnt;
  581. /** Settings interface */
  582. struct settings settings;
  583. /** Router address */
  584. struct in6_addr router;
  585. /** Router lifetime */
  586. unsigned int lifetime;
  587. /** Length of NDP options */
  588. size_t len;
  589. /** NDP options */
  590. union ndp_option options[0];
  591. };
  592. /** NDP settings scope */
  593. static const struct settings_scope ndp_settings_scope;
  594. /**
  595. * Construct NDP tag
  596. *
  597. * @v type NDP option type
  598. * @v offset Starting offset of data
  599. * @v len Length of data (or 0 to use all remaining data)
  600. * @ret tag NDP tag
  601. */
  602. #define NDP_TAG( type, offset, len ) \
  603. ( ( (len) << 16 ) | ( (offset) << 8 ) | (type) )
  604. /**
  605. * Extract NDP tag type
  606. *
  607. * @v tag NDP tag
  608. * @ret type NDP option type
  609. */
  610. #define NDP_TAG_TYPE( tag ) ( ( (tag) >> 0 ) & 0xff )
  611. /**
  612. * Extract NDP tag offset
  613. *
  614. * @v tag NDP tag
  615. * @ret offset Starting offset of data
  616. */
  617. #define NDP_TAG_OFFSET( tag ) ( ( (tag) >> 8 ) & 0xff )
  618. /**
  619. * Extract NDP tag length
  620. *
  621. * @v tag NDP tag
  622. * @ret len Length of data (or 0 to use all remaining data)
  623. */
  624. #define NDP_TAG_LEN( tag ) ( ( (tag) >> 16 ) & 0xff )
  625. /**
  626. * Extract NDP tag instance
  627. *
  628. * @v tag NDP tag
  629. * @ret instance Instance
  630. */
  631. #define NDP_TAG_INSTANCE( tag ) ( ( (tag) >> 24 ) & 0xff )
  632. /**
  633. * Check applicability of NDP setting
  634. *
  635. * @v settings Settings block
  636. * @v setting Setting to fetch
  637. * @ret applies Setting applies within this settings block
  638. */
  639. static int ndp_applies ( struct settings *settings __unused,
  640. const struct setting *setting ) {
  641. return ( setting->scope == &ndp_settings_scope );
  642. }
  643. /**
  644. * Fetch value of NDP setting
  645. *
  646. * @v settings Settings block
  647. * @v setting Setting to fetch
  648. * @v data Buffer to fill with setting data
  649. * @v len Length of buffer
  650. * @ret len Length of setting data, or negative error
  651. */
  652. static int ndp_fetch ( struct settings *settings,
  653. struct setting *setting,
  654. void *data, size_t len ) {
  655. struct ndp_settings *ndpset =
  656. container_of ( settings, struct ndp_settings, settings );
  657. struct net_device *netdev =
  658. container_of ( settings->parent, struct net_device,
  659. settings.settings );
  660. union ndp_option *option;
  661. unsigned int tag_type;
  662. unsigned int tag_offset;
  663. unsigned int tag_len;
  664. unsigned int tag_instance;
  665. size_t offset;
  666. size_t option_len;
  667. void *option_data;
  668. /* Parse setting tag */
  669. tag_type = NDP_TAG_TYPE ( setting->tag );
  670. tag_offset = NDP_TAG_OFFSET ( setting->tag );
  671. tag_len = NDP_TAG_LEN ( setting->tag );
  672. tag_instance = NDP_TAG_INSTANCE ( setting->tag );
  673. /* Scan through NDP options for requested type. We can assume
  674. * that the options are well-formed, otherwise they would have
  675. * been rejected prior to being stored.
  676. */
  677. for ( offset = 0 ; offset < ndpset->len ; offset += option_len ) {
  678. /* Calculate option length */
  679. option = ( ( ( void * ) ndpset->options ) + offset );
  680. option_len = ( option->header.blocks * NDP_OPTION_BLKSZ );
  681. /* Skip options that do not match this tag */
  682. if ( option->header.type != tag_type )
  683. continue;
  684. /* Skip previous instances of this option */
  685. if ( tag_instance-- != 0 )
  686. continue;
  687. /* Sanity check */
  688. if ( ( tag_offset + tag_len ) > option_len ) {
  689. DBGC ( netdev, "NDP %s option %d too short\n",
  690. netdev->name, tag_type );
  691. return -EINVAL;
  692. }
  693. if ( ! tag_len )
  694. tag_len = ( option_len - tag_offset );
  695. option_data = ( ( ( void * ) option ) + tag_offset );
  696. /* Copy data to output buffer */
  697. if ( len > tag_len )
  698. len = tag_len;
  699. memcpy ( data, option_data, len );
  700. /* Default to hex if no type is specified */
  701. if ( ! setting->type )
  702. setting->type = &setting_type_hex;
  703. return tag_len;
  704. }
  705. return -ENOENT;
  706. }
  707. /** NDP settings operations */
  708. static struct settings_operations ndp_settings_operations = {
  709. .applies = ndp_applies,
  710. .fetch = ndp_fetch,
  711. };
  712. /**
  713. * Check applicability of NDP per-prefix setting
  714. *
  715. * @v settings Settings block
  716. * @v setting Setting to fetch
  717. * @ret applies Setting applies within this settings block
  718. */
  719. static int ndp_prefix_applies ( struct settings *settings __unused,
  720. const struct setting *setting ) {
  721. return ( setting->scope == &ipv6_scope );
  722. }
  723. /**
  724. * Fetch value of NDP IPv6 address setting
  725. *
  726. * @v settings Settings block
  727. * @v data Buffer to fill with setting data
  728. * @v len Length of buffer
  729. * @ret len Length of setting data, or negative error
  730. */
  731. static int ndp_prefix_fetch_ip6 ( struct settings *settings, void *data,
  732. size_t len ) {
  733. struct ndp_prefix_settings *prefset =
  734. container_of ( settings, struct ndp_prefix_settings, settings );
  735. struct ndp_settings *ndpset =
  736. container_of ( settings->parent, struct ndp_settings, settings);
  737. struct net_device *netdev =
  738. container_of ( ndpset->settings.parent, struct net_device,
  739. settings.settings );
  740. struct ndp_prefix_information_option *prefix = prefset->prefix;
  741. struct in6_addr ip6;
  742. int prefix_len;
  743. /* Skip dead prefixes */
  744. if ( ! prefix->valid )
  745. return -ENOENT;
  746. /* Construct IPv6 address via SLAAC, if applicable */
  747. memcpy ( &ip6, &prefix->prefix, sizeof ( ip6 ) );
  748. if ( prefix->flags & NDP_PREFIX_AUTONOMOUS ) {
  749. prefix_len = ipv6_eui64 ( &ip6, netdev );
  750. if ( prefix_len < 0 )
  751. return prefix_len;
  752. if ( prefix_len != prefix->prefix_len )
  753. return -EINVAL;
  754. }
  755. /* Fill in IPv6 address */
  756. if ( len > sizeof ( ip6 ) )
  757. len = sizeof ( ip6 );
  758. memcpy ( data, &ip6, len );
  759. return sizeof ( ip6 );
  760. }
  761. /**
  762. * Fetch value of NDP prefix length setting
  763. *
  764. * @v settings Settings block
  765. * @v data Buffer to fill with setting data
  766. * @v len Length of buffer
  767. * @ret len Length of setting data, or negative error
  768. */
  769. static int ndp_prefix_fetch_len6 ( struct settings *settings, void *data,
  770. size_t len ) {
  771. struct ndp_prefix_settings *prefset =
  772. container_of ( settings, struct ndp_prefix_settings, settings );
  773. struct ndp_prefix_information_option *prefix = prefset->prefix;
  774. uint8_t *len6;
  775. /* Fill in prefix length */
  776. if ( len >= sizeof ( *len6 ) ) {
  777. /* We treat an off-link prefix as having a prefix
  778. * length covering the entire IPv6 address.
  779. */
  780. len6 = data;
  781. *len6 = ( ( prefix->flags & NDP_PREFIX_ON_LINK ) ?
  782. prefix->prefix_len : -1UL );
  783. }
  784. return sizeof ( *len6 );
  785. }
  786. /**
  787. * Fetch value of NDP router address setting
  788. *
  789. * @v settings Settings block
  790. * @v data Buffer to fill with setting data
  791. * @v len Length of buffer
  792. * @ret len Length of setting data, or negative error
  793. */
  794. static int ndp_prefix_fetch_gateway6 ( struct settings *settings,
  795. void *data, size_t len ) {
  796. struct ndp_settings *ndpset =
  797. container_of ( settings->parent, struct ndp_settings, settings);
  798. /* Treat non-routing router as non-existent */
  799. if ( ! ndpset->lifetime )
  800. return -ENOENT;
  801. /* Fill in router address */
  802. if ( len > sizeof ( ndpset->router ) )
  803. len = sizeof ( ndpset->router );
  804. memcpy ( data, &ndpset->router, len );
  805. return sizeof ( ndpset->router );
  806. }
  807. /** An NDP per-prefix setting operation */
  808. struct ndp_prefix_operation {
  809. /** Generic setting */
  810. const struct setting *setting;
  811. /**
  812. * Fetch value of setting
  813. *
  814. * @v settings Settings block
  815. * @v data Buffer to fill with setting data
  816. * @v len Length of buffer
  817. * @ret len Length of setting data, or negative error
  818. */
  819. int ( * fetch ) ( struct settings *settings, void *data, size_t len );
  820. };
  821. /** NDP per-prefix settings operations */
  822. static struct ndp_prefix_operation ndp_prefix_operations[] = {
  823. { &ip6_setting, ndp_prefix_fetch_ip6 },
  824. { &len6_setting, ndp_prefix_fetch_len6 },
  825. { &gateway6_setting, ndp_prefix_fetch_gateway6 },
  826. };
  827. /**
  828. * Fetch value of NDP pre-prefix setting
  829. *
  830. * @v settings Settings block
  831. * @v setting Setting to fetch
  832. * @v data Buffer to fill with setting data
  833. * @v len Length of buffer
  834. * @ret len Length of setting data, or negative error
  835. */
  836. static int ndp_prefix_fetch ( struct settings *settings,
  837. struct setting *setting,
  838. void *data, size_t len ) {
  839. struct ndp_prefix_operation *op;
  840. unsigned int i;
  841. /* Handle per-prefix settings */
  842. for ( i = 0 ; i < ( sizeof ( ndp_prefix_operations ) /
  843. sizeof ( ndp_prefix_operations[0] ) ) ; i++ ) {
  844. op = &ndp_prefix_operations[i];
  845. if ( setting_cmp ( setting, op->setting ) == 0 )
  846. return op->fetch ( settings, data, len );
  847. }
  848. return -ENOENT;
  849. }
  850. /** NDP per-prefix settings operations */
  851. static struct settings_operations ndp_prefix_settings_operations = {
  852. .applies = ndp_prefix_applies,
  853. .fetch = ndp_prefix_fetch,
  854. };
  855. /**
  856. * Register NDP settings
  857. *
  858. * @v netdev Network device
  859. * @v router Router address
  860. * @v lifetime Router lifetime
  861. * @v options NDP options
  862. * @v len Length of options
  863. * @ret rc Return status code
  864. */
  865. static int ndp_register_settings ( struct net_device *netdev,
  866. struct in6_addr *router,
  867. unsigned int lifetime,
  868. union ndp_option *options, size_t len ) {
  869. struct settings *parent = netdev_settings ( netdev );
  870. union ndp_option *option;
  871. struct ndp_settings *ndpset;
  872. struct ndp_prefix_settings *prefset;
  873. size_t offset;
  874. size_t option_len;
  875. unsigned int prefixes;
  876. unsigned int instance;
  877. int order;
  878. int rc;
  879. /* Count number of prefix options. We can assume that the
  880. * options are well-formed, otherwise they would have been
  881. * rejected prior to being stored.
  882. */
  883. order = IPV6_ORDER_PREFIX_ONLY;
  884. for ( prefixes = 0, offset = 0 ; offset < len ; offset += option_len ) {
  885. /* Skip non-prefix options */
  886. option = ( ( ( void * ) options ) + offset );
  887. option_len = ( option->header.blocks * NDP_OPTION_BLKSZ );
  888. if ( option->header.type != NDP_OPT_PREFIX )
  889. continue;
  890. /* Count number of prefixes */
  891. prefixes++;
  892. /* Increase overall order if we have SLAAC addresses */
  893. if ( option->prefix.flags & NDP_PREFIX_AUTONOMOUS )
  894. order = IPV6_ORDER_SLAAC;
  895. }
  896. /* Allocate and initialise structure */
  897. ndpset = zalloc ( sizeof ( *ndpset ) + len +
  898. ( prefixes * sizeof ( *prefset ) ) );
  899. if ( ! ndpset ) {
  900. rc = -ENOMEM;
  901. goto err_alloc;
  902. }
  903. ref_init ( &ndpset->refcnt, NULL );
  904. settings_init ( &ndpset->settings, &ndp_settings_operations,
  905. &ndpset->refcnt, &ndp_settings_scope );
  906. ndpset->settings.order = order;
  907. memcpy ( &ndpset->router, router, sizeof ( ndpset->router ) );
  908. ndpset->lifetime = lifetime;
  909. ndpset->len = len;
  910. memcpy ( ndpset->options, options, len );
  911. prefset = ( ( ( void * ) ndpset->options ) + len );
  912. /* Register settings */
  913. if ( ( rc = register_settings ( &ndpset->settings, parent,
  914. NDP_SETTINGS_NAME ) ) != 0 )
  915. goto err_register;
  916. /* Construct and register per-prefix settings */
  917. for ( instance = 0, offset = 0 ; offset < len ; offset += option_len ) {
  918. /* Skip non-prefix options */
  919. option = ( ( ( void * ) ndpset->options ) + offset );
  920. option_len = ( option->header.blocks * NDP_OPTION_BLKSZ );
  921. if ( option->header.type != NDP_OPT_PREFIX )
  922. continue;
  923. /* Initialise structure */
  924. settings_init ( &prefset->settings,
  925. &ndp_prefix_settings_operations,
  926. &ndpset->refcnt, &ndp_settings_scope );
  927. prefset->settings.order =
  928. ( ( option->prefix.flags & NDP_PREFIX_AUTONOMOUS ) ?
  929. IPV6_ORDER_SLAAC : IPV6_ORDER_PREFIX_ONLY );
  930. prefset->prefix = &option->prefix;
  931. snprintf ( prefset->name, sizeof ( prefset->name ), "%d",
  932. instance++ );
  933. /* Register settings */
  934. if ( ( rc = register_settings ( &prefset->settings,
  935. &ndpset->settings,
  936. prefset->name ) ) != 0 )
  937. goto err_register_prefix;
  938. /* Move to next per-prefix settings */
  939. prefset++;
  940. }
  941. assert ( instance == prefixes );
  942. ref_put ( &ndpset->refcnt );
  943. return 0;
  944. err_register_prefix:
  945. unregister_settings ( &ndpset->settings );
  946. err_register:
  947. ref_put ( &ndpset->refcnt );
  948. err_alloc:
  949. return rc;
  950. }
  951. /** DNS server setting */
  952. const struct setting ndp_dns6_setting __setting ( SETTING_IP6_EXTRA, dns6 ) = {
  953. .name = "dns6",
  954. .description = "DNS server",
  955. .tag = NDP_TAG ( NDP_OPT_RDNSS,
  956. offsetof ( struct ndp_rdnss_option, addresses ), 0 ),
  957. .type = &setting_type_ipv6,
  958. .scope = &ndp_settings_scope,
  959. };
  960. /** DNS search list setting */
  961. const struct setting ndp_dnssl_setting __setting ( SETTING_IP_EXTRA, dnssl ) = {
  962. .name = "dnssl",
  963. .description = "DNS search list",
  964. .tag = NDP_TAG ( NDP_OPT_DNSSL,
  965. offsetof ( struct ndp_dnssl_option, names ), 0 ),
  966. .type = &setting_type_dnssl,
  967. .scope = &ndp_settings_scope,
  968. };
  969. /****************************************************************************
  970. *
  971. * IPv6 autoconfiguration
  972. *
  973. */
  974. /** An IPv6 configurator */
  975. struct ipv6conf {
  976. /** Reference count */
  977. struct refcnt refcnt;
  978. /** List of configurators */
  979. struct list_head list;
  980. /** Job control interface */
  981. struct interface job;
  982. /** DHCPv6 interface */
  983. struct interface dhcp;
  984. /** Network device being configured */
  985. struct net_device *netdev;
  986. /** Retransmission timer */
  987. struct retry_timer timer;
  988. };
  989. /** List of IPv6 configurators */
  990. static LIST_HEAD ( ipv6confs );
  991. /**
  992. * Free IPv6 configurator
  993. *
  994. * @v refcnt Reference count
  995. */
  996. static void ipv6conf_free ( struct refcnt *refcnt ) {
  997. struct ipv6conf *ipv6conf =
  998. container_of ( refcnt, struct ipv6conf, refcnt );
  999. netdev_put ( ipv6conf->netdev );
  1000. free ( ipv6conf );
  1001. }
  1002. /**
  1003. * Identify IPv6 configurator by network device
  1004. *
  1005. * @v netdev Network device
  1006. * @ret ipv6 IPv6 configurator, or NULL
  1007. */
  1008. static struct ipv6conf * ipv6conf_demux ( struct net_device *netdev ) {
  1009. struct ipv6conf *ipv6conf;
  1010. list_for_each_entry ( ipv6conf, &ipv6confs, list ) {
  1011. if ( ipv6conf->netdev == netdev )
  1012. return ipv6conf;
  1013. }
  1014. return NULL;
  1015. }
  1016. /**
  1017. * Finish IPv6 autoconfiguration
  1018. *
  1019. * @v ipv6 IPv6 configurator
  1020. * @v rc Reason for finishing
  1021. */
  1022. static void ipv6conf_done ( struct ipv6conf *ipv6conf, int rc ) {
  1023. /* Shut down interfaces */
  1024. intf_shutdown ( &ipv6conf->job, rc );
  1025. intf_shutdown ( &ipv6conf->dhcp, rc );
  1026. /* Stop timer */
  1027. stop_timer ( &ipv6conf->timer );
  1028. /* Remove from list and drop list's reference */
  1029. list_del ( &ipv6conf->list );
  1030. ref_put ( &ipv6conf->refcnt );
  1031. }
  1032. /**
  1033. * Handle IPv6 configurator timer expiry
  1034. *
  1035. * @v timer Retry timer
  1036. * @v fail Failure indicator
  1037. */
  1038. static void ipv6conf_expired ( struct retry_timer *timer, int fail ) {
  1039. struct ipv6conf *ipv6conf =
  1040. container_of ( timer, struct ipv6conf, timer );
  1041. /* If we have failed, terminate autoconfiguration */
  1042. if ( fail ) {
  1043. ipv6conf_done ( ipv6conf, -ETIMEDOUT );
  1044. return;
  1045. }
  1046. /* Otherwise, transmit router solicitation and restart timer */
  1047. start_timer ( &ipv6conf->timer );
  1048. ndp_tx_router_solicitation ( ipv6conf->netdev );
  1049. }
  1050. /**
  1051. * Handle router advertisement during IPv6 autoconfiguration
  1052. *
  1053. * @v netdev Network device
  1054. * @v router Router address
  1055. * @v radv Router advertisement
  1056. * @v len Length of router advertisement
  1057. * @ret rc Return status code
  1058. *
  1059. * This function assumes that the router advertisement is well-formed,
  1060. * since it must have already passed through option processing.
  1061. */
  1062. static int
  1063. ipv6conf_rx_router_advertisement ( struct net_device *netdev,
  1064. struct in6_addr *router,
  1065. struct ndp_router_advertisement_header *radv,
  1066. size_t len ) {
  1067. struct ipv6conf *ipv6conf;
  1068. size_t option_len;
  1069. int stateful;
  1070. int rc;
  1071. /* Identify IPv6 configurator, if any */
  1072. ipv6conf = ipv6conf_demux ( netdev );
  1073. /* Do nothing unless IPv6 autoconfiguration is in progress */
  1074. if ( ! ipv6conf )
  1075. return 0;
  1076. /* If this is not the first solicited router advertisement, ignore it */
  1077. if ( ! timer_running ( &ipv6conf->timer ) )
  1078. return 0;
  1079. /* Stop router solicitation timer */
  1080. stop_timer ( &ipv6conf->timer );
  1081. /* Register NDP settings */
  1082. option_len = ( len - offsetof ( typeof ( *radv ), option ) );
  1083. if ( ( rc = ndp_register_settings ( netdev, router,
  1084. ntohl ( radv->lifetime ),
  1085. radv->option, option_len ) ) != 0 )
  1086. return rc;
  1087. /* Start DHCPv6 if required */
  1088. if ( radv->flags & ( NDP_ROUTER_MANAGED | NDP_ROUTER_OTHER ) ) {
  1089. stateful = ( radv->flags & NDP_ROUTER_MANAGED );
  1090. if ( ( rc = start_dhcpv6 ( &ipv6conf->dhcp, netdev,
  1091. stateful ) ) != 0 ) {
  1092. DBGC ( netdev, "NDP %s could not start state%s DHCPv6: "
  1093. "%s\n", netdev->name,
  1094. ( stateful ? "ful" : "less" ), strerror ( rc ) );
  1095. ipv6conf_done ( ipv6conf, rc );
  1096. return rc;
  1097. }
  1098. return 0;
  1099. }
  1100. /* Otherwise, terminate autoconfiguration */
  1101. ipv6conf_done ( ipv6conf, 0 );
  1102. return 0;
  1103. }
  1104. /** IPv6 configurator job interface operations */
  1105. static struct interface_operation ipv6conf_job_op[] = {
  1106. INTF_OP ( intf_close, struct ipv6conf *, ipv6conf_done ),
  1107. };
  1108. /** IPv6 configurator job interface descriptor */
  1109. static struct interface_descriptor ipv6conf_job_desc =
  1110. INTF_DESC ( struct ipv6conf, job, ipv6conf_job_op );
  1111. /** IPv6 configurator DHCPv6 interface operations */
  1112. static struct interface_operation ipv6conf_dhcp_op[] = {
  1113. INTF_OP ( intf_close, struct ipv6conf *, ipv6conf_done ),
  1114. };
  1115. /** IPv6 configurator DHCPv6 interface descriptor */
  1116. static struct interface_descriptor ipv6conf_dhcp_desc =
  1117. INTF_DESC ( struct ipv6conf, dhcp, ipv6conf_dhcp_op );
  1118. /**
  1119. * Start IPv6 autoconfiguration
  1120. *
  1121. * @v job Job control interface
  1122. * @v netdev Network device
  1123. * @ret rc Return status code
  1124. */
  1125. int start_ipv6conf ( struct interface *job, struct net_device *netdev ) {
  1126. struct ipv6conf *ipv6conf;
  1127. /* Allocate and initialise structure */
  1128. ipv6conf = zalloc ( sizeof ( *ipv6conf ) );
  1129. if ( ! ipv6conf )
  1130. return -ENOMEM;
  1131. ref_init ( &ipv6conf->refcnt, ipv6conf_free );
  1132. intf_init ( &ipv6conf->job, &ipv6conf_job_desc, &ipv6conf->refcnt );
  1133. intf_init ( &ipv6conf->dhcp, &ipv6conf_dhcp_desc, &ipv6conf->refcnt );
  1134. timer_init ( &ipv6conf->timer, ipv6conf_expired, &ipv6conf->refcnt );
  1135. ipv6conf->netdev = netdev_get ( netdev );
  1136. /* Start timer to initiate router solicitation */
  1137. start_timer_nodelay ( &ipv6conf->timer );
  1138. /* Attach parent interface, transfer reference to list, and return */
  1139. intf_plug_plug ( &ipv6conf->job, job );
  1140. list_add ( &ipv6conf->list, &ipv6confs );
  1141. return 0;
  1142. }
  1143. /** IPv6 network device configurator */
  1144. struct net_device_configurator ipv6_configurator __net_device_configurator = {
  1145. .name = "ipv6",
  1146. .start = start_ipv6conf,
  1147. };