From 94ac6837a35b2a4aaf30f01fb919fc90ee88ac1e Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Fri, 29 Mar 2013 16:49:14 +0100 Subject: libndp: change the was opts are handled Signed-off-by: Jiri Pirko --- libndp/libndp.c | 1068 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 537 insertions(+), 531 deletions(-) (limited to 'libndp') diff --git a/libndp/libndp.c b/libndp/libndp.c index 56cecb1..ad58d0b 100644 --- a/libndp/libndp.c +++ b/libndp/libndp.c @@ -298,875 +298,884 @@ struct ndp_msgra { } opt_mtu; }; -/** - * ndp_msgra_curhoplimit: - * @msgra: RA message structure - * - * Get RA curhoplimit. - * - * Returns: curhoplimit. - **/ -NDP_EXPORT -uint8_t ndp_msgra_curhoplimit(struct ndp_msgra *msgra) +struct ndp_msgns { + struct nd_neighbor_solicit *ns; /* must be first */ +}; + +struct ndp_msgna { + struct nd_neighbor_solicit *na; /* must be first */ +}; + +struct ndp_msgr { + struct nd_redirect *r; /* must be first */ +}; + +struct ndp_msg { +#define NDP_MSG_BUFLEN 1500 + unsigned char buf[NDP_MSG_BUFLEN]; + size_t len; + struct in6_addr addrto; + uint32_t ifindex; + struct icmp6_hdr * icmp6_hdr; + unsigned char * opts_start; /* pointer to buf at the + place where opts start */ + union { + struct ndp_msggeneric generic; + struct ndp_msgrs rs; + struct ndp_msgra ra; + struct ndp_msgns ns; + struct ndp_msgna na; + struct ndp_msgr r; + } nd_msg; +}; + +struct ndp_msg_type_info { +#define NDP_STRABBR_SIZE 4 + char strabbr[NDP_STRABBR_SIZE]; + uint8_t raw_type; + size_t raw_struct_size; + void (*addrto_adjust)(struct in6_addr *addr); +}; + +static void ndp_msg_addrto_adjust_all_nodes(struct in6_addr *addr) { - return msgra->ra->nd_ra_curhoplimit; + struct in6_addr any = IN6ADDR_ANY_INIT; + + if (memcmp(addr, &any, sizeof(any))) + return; + addr->s6_addr32[0] = htonl(0xFF020000); + addr->s6_addr32[1] = 0; + addr->s6_addr32[2] = 0; + addr->s6_addr32[3] = htonl(0x1); } -/** - * ndp_msgra_curhoplimit_set: - * @msgra: RA message structure - * - * Set RA curhoplimit. - **/ -NDP_EXPORT -void ndp_msgra_curhoplimit_set(struct ndp_msgra *msgra, uint8_t curhoplimit) +static void ndp_msg_addrto_adjust_all_routers(struct in6_addr *addr) { - msgra->ra->nd_ra_curhoplimit = curhoplimit; + struct in6_addr any = IN6ADDR_ANY_INIT; + + if (memcmp(addr, &any, sizeof(any))) + return; + addr->s6_addr32[0] = htonl(0xFF020000); + addr->s6_addr32[1] = 0; + addr->s6_addr32[2] = 0; + addr->s6_addr32[3] = htonl(0x2); } -/** - * ndp_msgra_flag_managed: - * @msgra: RA message structure - * - * Get RA managed flag. - * - * Returns: managed flag. - **/ -NDP_EXPORT -bool ndp_msgra_flag_managed(struct ndp_msgra *msgra) +static struct ndp_msg_type_info ndp_msg_type_info_list[] = { - return msgra->ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED; + [NDP_MSG_RS] = { + .strabbr = "RS", + .raw_type = ND_ROUTER_SOLICIT, + .raw_struct_size = sizeof(struct nd_router_solicit), + .addrto_adjust = ndp_msg_addrto_adjust_all_routers, + }, + [NDP_MSG_RA] = { + .strabbr = "RA", + .raw_type = ND_ROUTER_ADVERT, + .raw_struct_size = sizeof(struct nd_router_advert), + }, + [NDP_MSG_NS] = { + .strabbr = "NS", + .raw_type = ND_NEIGHBOR_SOLICIT, + .raw_struct_size = sizeof(struct nd_neighbor_solicit), + .addrto_adjust = ndp_msg_addrto_adjust_all_nodes, + }, + [NDP_MSG_NA] = { + .strabbr = "NA", + .raw_type = ND_NEIGHBOR_ADVERT, + .raw_struct_size = sizeof(struct nd_neighbor_advert), + }, + [NDP_MSG_R] = { + .strabbr = "R", + .raw_type = ND_REDIRECT, + .raw_struct_size = sizeof(struct nd_redirect), + }, +}; + +#define NDP_MSG_TYPE_LIST_SIZE ARRAY_SIZE(ndp_msg_type_info_list) + +struct ndp_msg_type_info *ndp_msg_type_info(enum ndp_msg_type msg_type) +{ + return &ndp_msg_type_info_list[msg_type]; } -/** - * ndp_msgra_flag_managed_set: - * @msgra: RA message structure - * - * Set RA managed flag. - **/ -NDP_EXPORT -void ndp_msgra_flag_managed_set(struct ndp_msgra *msgra, bool flag_managed) +static int ndp_msg_type_by_raw_type(enum ndp_msg_type *p_msg_type, + uint8_t raw_type) { - if (flag_managed) - msgra->ra->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED; - else - msgra->ra->nd_ra_flags_reserved &= ~ND_RA_FLAG_MANAGED; + int i; + + for (i = 0; i < NDP_MSG_TYPE_LIST_SIZE; i++) { + if (ndp_msg_type_info(i)->raw_type == raw_type) { + *p_msg_type = i; + return 0; + } + } + return -ENOENT; +} + +static struct ndp_msg *ndp_msg_alloc(void) +{ + struct ndp_msg *msg; + + msg = myzalloc(sizeof(*msg)); + if (!msg) + return NULL; + msg->icmp6_hdr = (struct icmp6_hdr *) msg->buf; + return msg; +} + +static void ndp_msg_type_set(struct ndp_msg *msg, enum ndp_msg_type msg_type); + +static void ndp_msg_init(struct ndp_msg *msg, enum ndp_msg_type msg_type) +{ + size_t raw_struct_size = ndp_msg_type_info(msg_type)->raw_struct_size; + + ndp_msg_type_set(msg, msg_type); + msg->len = raw_struct_size; + msg->opts_start = msg->buf + raw_struct_size; + + /* Set-up "first pointers" in all ndp_msgrs, ndp_msgra, ndp_msgns, + * ndp_msgna, ndp_msgr structures. + */ + msg->nd_msg.generic.dataptr = ndp_msg_payload(msg); } /** - * ndp_msgra_flag_other: - * @msgra: RA message structure + * ndp_msg_new: + * @p_msg: pointer where new message structure address will be stored + * @msg_type: message type * - * Get RA other flag. + * Allocate new message structure of a specified type and initialize it. * - * Returns: other flag. + * Returns: zero on success or negative number in case of an error. **/ NDP_EXPORT -bool ndp_msgra_flag_other(struct ndp_msgra *msgra) +int ndp_msg_new(struct ndp_msg **p_msg, enum ndp_msg_type msg_type) { - return msgra->ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER; + struct ndp_msg *msg; + + if (msg_type == NDP_MSG_ALL) + return -EINVAL; + msg = ndp_msg_alloc(); + if (!msg) + return -ENOMEM; + ndp_msg_init(msg, msg_type); + *p_msg = msg; + return 0; } /** - * ndp_msgra_flag_other_set: - * @msgra: RA message structure + * ndp_msg_destroy: * - * Set RA other flag. + * Destroy message structure. **/ NDP_EXPORT -void ndp_msgra_flag_other_set(struct ndp_msgra *msgra, bool flag_other) +void ndp_msg_destroy(struct ndp_msg *msg) { - if (flag_other) - msgra->ra->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER; - else - msgra->ra->nd_ra_flags_reserved &= ~ND_RA_FLAG_OTHER; + free(msg); } /** - * ndp_msgra_flag_home_agent: - * @msgra: RA message structure + * ndp_msg_payload: + * @msg: message structure * - * Get RA home_agent flag. + * Get raw Neighbour discovery packet data. * - * Returns: home_agent flag. + * Returns: pointer to raw data. **/ NDP_EXPORT -bool ndp_msgra_flag_home_agent(struct ndp_msgra *msgra) +void *ndp_msg_payload(struct ndp_msg *msg) { - return msgra->ra->nd_ra_flags_reserved & ND_RA_FLAG_HOME_AGENT; + return msg->buf; } /** - * ndp_msgra_flag_home_agent_set: - * @msgra: RA message structure + * ndp_msg_payload_maxlen: + * @msg: message structure * - * Set RA home_agent flag. + * Get raw Neighbour discovery packet data maximum length. + * + * Returns: length in bytes. **/ NDP_EXPORT -void ndp_msgra_flag_home_agent_set(struct ndp_msgra *msgra, - bool flag_home_agent) +size_t ndp_msg_payload_maxlen(struct ndp_msg *msg) { - if (flag_home_agent) - msgra->ra->nd_ra_flags_reserved |= ND_RA_FLAG_HOME_AGENT; - else - msgra->ra->nd_ra_flags_reserved &= ~ND_RA_FLAG_HOME_AGENT; + return sizeof(msg->buf); } /** - * ndp_msgra_router_lifetime: - * @msgra: RA message structure + * ndp_msg_payload_len: + * @msg: message structure * - * Get RA router lifetime. + * Get raw Neighbour discovery packet data length. * - * Returns: router lifetime in seconds. + * Returns: length in bytes. **/ NDP_EXPORT -uint16_t ndp_msgra_router_lifetime(struct ndp_msgra *msgra) +size_t ndp_msg_payload_len(struct ndp_msg *msg) { - return ntohs(msgra->ra->nd_ra_router_lifetime); + return msg->len; } /** - * ndp_msgra_router_lifetime_set: - * @msgra: RA message structure + * ndp_msg_payload_len_set: + * @msg: message structure * - * Set RA router lifetime. + * Set raw Neighbour discovery packet data length. **/ NDP_EXPORT -void ndp_msgra_router_lifetime_set(struct ndp_msgra *msgra, - uint16_t router_lifetime) +void ndp_msg_payload_len_set(struct ndp_msg *msg, size_t len) { - msgra->ra->nd_ra_router_lifetime = htons(router_lifetime); + if (len > sizeof(msg->buf)) + len = sizeof(msg->buf); + msg->len = len; } /** - * ndp_msgra_reachable_time: - * @msgra: RA message structure + * ndp_msg_payload_opts: + * @msg: message structure * - * Get RA reachable time. + * Get raw Neighbour discovery packet options part data. * - * Returns: reachable time in milliseconds. + * Returns: pointer to raw data. **/ NDP_EXPORT -uint32_t ndp_msgra_reachable_time(struct ndp_msgra *msgra) +void *ndp_msg_payload_opts(struct ndp_msg *msg) { - return ntohl(msgra->ra->nd_ra_reachable); + return msg->opts_start; } -/** - * ndp_msgra_reachable_time_set: - * @msgra: RA message structure - * - * Set RA reachable time. - **/ -NDP_EXPORT -void ndp_msgra_reachable_time_set(struct ndp_msgra *msgra, - uint32_t reachable_time) +static void *ndp_msg_payload_opts_offset(struct ndp_msg *msg, int offset) { - msgra->ra->nd_ra_reachable = htonl(reachable_time); + unsigned char *ptr = ndp_msg_payload_opts(msg); + + return ptr + offset; } /** - * ndp_msgra_retransmit_time: - * @msgra: RA message structure + * ndp_msg_payload_opts_len: + * @msg: message structure * - * Get RA retransmit time. + * Get raw Neighbour discovery packet options part data length. * - * Returns: retransmit time in milliseconds. + * Returns: length in bytes. **/ NDP_EXPORT -uint32_t ndp_msgra_retransmit_time(struct ndp_msgra *msgra) +size_t ndp_msg_payload_opts_len(struct ndp_msg *msg) { - return ntohl(msgra->ra->nd_ra_retransmit); + return msg->len - (msg->opts_start - msg->buf); } /** - * ndp_msgra_retransmit_time_set: - * @msgra: RA message structure + * ndp_msgrs: + * @msg: message structure * - * Set RA retransmit time. + * Get RS message structure by passed @msg. + * + * Returns: RS message structure or NULL in case the message is not of type RS. **/ NDP_EXPORT -void ndp_msgra_retransmit_time_set(struct ndp_msgra *msgra, - uint32_t retransmit_time) +struct ndp_msgrs *ndp_msgrs(struct ndp_msg *msg) { - msgra->ra->nd_ra_retransmit = htonl(retransmit_time); + if (ndp_msg_type(msg) != NDP_MSG_RS) + return NULL; + return &msg->nd_msg.rs; } /** - * ndp_msgra_opt_source_linkaddr_present: - * @msgra: RA message structure + * ndp_msgra: + * @msg: message structure * - * Find out if source linkaddr option is present. + * Get RA message structure by passed @msg. * - * Returns: true if option is present. + * Returns: RA message structure or NULL in case the message is not of type RA. **/ NDP_EXPORT -bool ndp_msgra_opt_source_linkaddr_present(struct ndp_msgra *msgra) +struct ndp_msgra *ndp_msgra(struct ndp_msg *msg) { - return msgra->opt_source_linkaddr.present; + if (ndp_msg_type(msg) != NDP_MSG_RA) + return NULL; + return &msg->nd_msg.ra; } /** - * ndp_msgra_opt_source_linkaddr: - * @msgra: RA message structure + * ndp_msgns: + * @msg: message structure * - * Get source linkaddr. User should check if source linkaddr option is - * present before calling this. + * Get NS message structure by passed @msg. * - * Returns: pointer to source linkaddr. + * Returns: NS message structure or NULL in case the message is not of type NS. **/ NDP_EXPORT -unsigned char *ndp_msgra_opt_source_linkaddr(struct ndp_msgra *msgra) +struct ndp_msgns *ndp_msgns(struct ndp_msg *msg) { - return msgra->opt_source_linkaddr.addr; + if (ndp_msg_type(msg) != NDP_MSG_NS) + return NULL; + return &msg->nd_msg.ns; } /** - * ndp_msgra_opt_source_linkaddr_len: - * @msgra: RA message structure + * ndp_msgna: + * @msg: message structure * - * Get source linkaddr length. User should check if source linkaddr option is - * present before calling this. + * Get NA message structure by passed @msg. * - * Returns: source linkaddr length. + * Returns: NA message structure or NULL in case the message is not of type NA. **/ NDP_EXPORT -size_t ndp_msgra_opt_source_linkaddr_len(struct ndp_msgra *msgra) +struct ndp_msgna *ndp_msgna(struct ndp_msg *msg) { - return sizeof(msgra->opt_source_linkaddr.addr); + if (ndp_msg_type(msg) != NDP_MSG_NA) + return NULL; + return &msg->nd_msg.na; } /** - * ndp_msgra_opt_target_linkaddr_present: - * @msgra: RA message structure + * ndp_msgr: + * @msg: message structure * - * Find out if target linkaddr option is present. + * Get R message structure by passed @msg. * - * Returns: true if option is present. + * Returns: R message structure or NULL in case the message is not of type R. **/ NDP_EXPORT -bool ndp_msgra_opt_target_linkaddr_present(struct ndp_msgra *msgra) +struct ndp_msgr *ndp_msgr(struct ndp_msg *msg) { - return msgra->opt_target_linkaddr.present; + if (ndp_msg_type(msg) != NDP_MSG_R) + return NULL; + return &msg->nd_msg.r; } /** - * ndp_msgra_opt_target_linkaddr: - * @msgra: RA message structure + * ndp_msg_type: + * @msg: message structure * - * Get target linkaddr. User should check if target linkaddr option is - * present before calling this. + * Get type of message. * - * Returns: pointer to target linkaddr. + * Returns: Message type **/ NDP_EXPORT -unsigned char *ndp_msgra_opt_target_linkaddr(struct ndp_msgra *msgra) +enum ndp_msg_type ndp_msg_type(struct ndp_msg *msg) +{ + enum ndp_msg_type msg_type; + int err; + + err = ndp_msg_type_by_raw_type(&msg_type, msg->icmp6_hdr->icmp6_type); + /* Type should be always set correctly (ensured by ndp_msg_init) */ + BUG_ON(err); + return msg_type; +} + +static void ndp_msg_type_set(struct ndp_msg *msg, enum ndp_msg_type msg_type) { - return msgra->opt_target_linkaddr.addr; + msg->icmp6_hdr->icmp6_type = ndp_msg_type_info(msg_type)->raw_type; } /** - * ndp_msgra_opt_target_linkaddr_len: - * @msgra: RA message structure + * ndp_msg_addrto: + * @msg: message structure * - * Get target linkaddr length. User should check if target linkaddr option is - * present before calling this. + * Get "to address" of message. * - * Returns: target linkaddr length. + * Returns: pointer to address. **/ NDP_EXPORT -size_t ndp_msgra_opt_target_linkaddr_len(struct ndp_msgra *msgra) +struct in6_addr *ndp_msg_addrto(struct ndp_msg *msg) { - return sizeof(msgra->opt_target_linkaddr.addr); + return &msg->addrto; } /** - * ndp_msgra_opt_prefix_present: - * @msgra: RA message structure + * ndp_msg_ifindex: + * @msg: message structure * - * Find out if prefix option is present. + * Get interface index of message. * - * Returns: true if option is present. + * Returns: Inteface index **/ NDP_EXPORT -bool ndp_msgra_opt_prefix_present(struct ndp_msgra *msgra) +uint32_t ndp_msg_ifindex(struct ndp_msg *msg) { - return msgra->opt_prefix.present; + return msg->ifindex; } /** - * ndp_msgra_opt_prefix: - * @msgra: RA message structure - * - * Get prefix addr. User should check if prefix option is present before - * calling this. + * ndp_msg_ifindex_set: + * @msg: message structure * - * Returns: pointer to address. + * Set raw interface index of message. **/ NDP_EXPORT -struct in6_addr *ndp_msgra_opt_prefix(struct ndp_msgra *msgra) +void ndp_msg_ifindex_set(struct ndp_msg *msg, uint32_t ifindex) { - return &msgra->opt_prefix.prefix; + msg->ifindex = ifindex; } /** - * ndp_msgra_opt_prefix_len: - * @msgra: RA message structure + * ndp_msg_send: + * @ndp: libndp library context + * @msg: message structure * - * Get prefix length. User should check if prefix option is present before - * calling this. + * Send message. * - * Returns: length of prefix. + * Returns: zero on success or negative number in case of an error. **/ NDP_EXPORT -uint8_t ndp_msgra_opt_prefix_len(struct ndp_msgra *msgra) +int ndp_msg_send(struct ndp *ndp, struct ndp_msg *msg) { - return msgra->opt_prefix.prefix_len; + enum ndp_msg_type msg_type = ndp_msg_type(msg); + + if (ndp_msg_type_info(msg_type)->addrto_adjust) + ndp_msg_type_info(msg_type)->addrto_adjust(&msg->addrto); + return mysendto6(ndp->sock, msg->buf, msg->len, 0, + &msg->addrto, msg->ifindex); } + +/** + * SECTION: msgra getters/setters + * @short_description: Getters and setters for RA message + */ + /** - * ndp_msgra_opt_prefix_valid_time: + * ndp_msgra_curhoplimit: * @msgra: RA message structure * - * Get prefix valid time. User should check if prefix option is present - * before calling this. + * Get RA curhoplimit. * - * Returns: valid time in seconds, (uint32_t) -1 means infinity. + * Returns: curhoplimit. **/ NDP_EXPORT -uint32_t ndp_msgra_opt_prefix_valid_time(struct ndp_msgra *msgra) +uint8_t ndp_msgra_curhoplimit(struct ndp_msgra *msgra) { - return msgra->opt_prefix.valid_time; + return msgra->ra->nd_ra_curhoplimit; } /** - * ndp_msgra_opt_prefix_preferred_time: + * ndp_msgra_curhoplimit_set: * @msgra: RA message structure * - * Get prefix preferred time. User should check if prefix option is present - * before calling this. - * - * Returns: preferred time in seconds, (uint32_t) -1 means infinity. + * Set RA curhoplimit. **/ NDP_EXPORT -uint32_t ndp_msgra_opt_prefix_preferred_time(struct ndp_msgra *msgra) +void ndp_msgra_curhoplimit_set(struct ndp_msgra *msgra, uint8_t curhoplimit) { - return msgra->opt_prefix.preferred_time; + msgra->ra->nd_ra_curhoplimit = curhoplimit; } /** - * ndp_msgra_opt_mtu_present: + * ndp_msgra_flag_managed: * @msgra: RA message structure * - * Find out if mtu option is present. + * Get RA managed flag. * - * Returns: true if option is present. + * Returns: managed flag. **/ NDP_EXPORT -bool ndp_msgra_opt_mtu_present(struct ndp_msgra *msgra) +bool ndp_msgra_flag_managed(struct ndp_msgra *msgra) { - return msgra->opt_mtu.present; + return msgra->ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED; } /** - * ndp_msgra_opt_mtu: + * ndp_msgra_flag_managed_set: * @msgra: RA message structure * - * Get MTU. User should check if mtu option is present before calling this. - * - * Returns: MTU. + * Set RA managed flag. **/ NDP_EXPORT -uint32_t ndp_msgra_opt_mtu(struct ndp_msgra *msgra) -{ - return msgra->opt_mtu.mtu; -} - -struct ndp_msgns { - struct nd_neighbor_solicit *ns; /* must be first */ -}; - -struct ndp_msgna { - struct nd_neighbor_solicit *na; /* must be first */ -}; - -struct ndp_msgr { - struct nd_redirect *r; /* must be first */ -}; - -struct ndp_msg { -#define NDP_MSG_BUFLEN 1500 - unsigned char buf[NDP_MSG_BUFLEN]; - size_t len; - struct in6_addr addrto; - uint32_t ifindex; - struct icmp6_hdr * icmp6_hdr; - unsigned char * opts_start; /* pointer to buf at the - place where opts start */ - union { - struct ndp_msggeneric generic; - struct ndp_msgrs rs; - struct ndp_msgra ra; - struct ndp_msgns ns; - struct ndp_msgna na; - struct ndp_msgr r; - } nd_msg; -}; - -struct ndp_msg_type_info { -#define NDP_STRABBR_SIZE 4 - char strabbr[NDP_STRABBR_SIZE]; - uint8_t raw_type; - size_t raw_struct_size; - void (*addrto_adjust)(struct in6_addr *addr); -}; - -static void ndp_msg_addrto_adjust_all_nodes(struct in6_addr *addr) -{ - struct in6_addr any = IN6ADDR_ANY_INIT; - - if (memcmp(addr, &any, sizeof(any))) - return; - addr->s6_addr32[0] = htonl(0xFF020000); - addr->s6_addr32[1] = 0; - addr->s6_addr32[2] = 0; - addr->s6_addr32[3] = htonl(0x1); -} - -static void ndp_msg_addrto_adjust_all_routers(struct in6_addr *addr) -{ - struct in6_addr any = IN6ADDR_ANY_INIT; - - if (memcmp(addr, &any, sizeof(any))) - return; - addr->s6_addr32[0] = htonl(0xFF020000); - addr->s6_addr32[1] = 0; - addr->s6_addr32[2] = 0; - addr->s6_addr32[3] = htonl(0x2); -} - -static struct ndp_msg_type_info ndp_msg_type_info_list[] = -{ - [NDP_MSG_RS] = { - .strabbr = "RS", - .raw_type = ND_ROUTER_SOLICIT, - .raw_struct_size = sizeof(struct nd_router_solicit), - .addrto_adjust = ndp_msg_addrto_adjust_all_routers, - }, - [NDP_MSG_RA] = { - .strabbr = "RA", - .raw_type = ND_ROUTER_ADVERT, - .raw_struct_size = sizeof(struct nd_router_advert), - }, - [NDP_MSG_NS] = { - .strabbr = "NS", - .raw_type = ND_NEIGHBOR_SOLICIT, - .raw_struct_size = sizeof(struct nd_neighbor_solicit), - .addrto_adjust = ndp_msg_addrto_adjust_all_nodes, - }, - [NDP_MSG_NA] = { - .strabbr = "NA", - .raw_type = ND_NEIGHBOR_ADVERT, - .raw_struct_size = sizeof(struct nd_neighbor_advert), - }, - [NDP_MSG_R] = { - .strabbr = "R", - .raw_type = ND_REDIRECT, - .raw_struct_size = sizeof(struct nd_redirect), - }, -}; - -#define NDP_MSG_TYPE_LIST_SIZE ARRAY_SIZE(ndp_msg_type_info_list) - -struct ndp_msg_type_info *ndp_msg_type_info(enum ndp_msg_type msg_type) -{ - return &ndp_msg_type_info_list[msg_type]; -} - -static int ndp_msg_type_by_raw_type(enum ndp_msg_type *p_msg_type, - uint8_t raw_type) -{ - int i; - - for (i = 0; i < NDP_MSG_TYPE_LIST_SIZE; i++) { - if (ndp_msg_type_info(i)->raw_type == raw_type) { - *p_msg_type = i; - return 0; - } - } - return -ENOENT; -} - -static struct ndp_msg *ndp_msg_alloc(void) -{ - struct ndp_msg *msg; - - msg = myzalloc(sizeof(*msg)); - if (!msg) - return NULL; - msg->icmp6_hdr = (struct icmp6_hdr *) msg->buf; - return msg; -} - -static void ndp_msg_type_set(struct ndp_msg *msg, enum ndp_msg_type msg_type); - -static void ndp_msg_init(struct ndp_msg *msg, enum ndp_msg_type msg_type) +void ndp_msgra_flag_managed_set(struct ndp_msgra *msgra, bool flag_managed) { - size_t raw_struct_size = ndp_msg_type_info(msg_type)->raw_struct_size; - - ndp_msg_type_set(msg, msg_type); - msg->len = raw_struct_size; - msg->opts_start = msg->buf + raw_struct_size; - - /* Set-up "first pointers" in all ndp_msgrs, ndp_msgra, ndp_msgns, - * ndp_msgna, ndp_msgr structures. - */ - msg->nd_msg.generic.dataptr = ndp_msg_payload(msg); + if (flag_managed) + msgra->ra->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED; + else + msgra->ra->nd_ra_flags_reserved &= ~ND_RA_FLAG_MANAGED; } /** - * ndp_msg_new: - * @p_msg: pointer where new message structure address will be stored - * @msg_type: message type + * ndp_msgra_flag_other: + * @msgra: RA message structure * - * Allocate new message structure of a specified type and initialize it. + * Get RA other flag. * - * Returns: zero on success or negative number in case of an error. + * Returns: other flag. **/ NDP_EXPORT -int ndp_msg_new(struct ndp_msg **p_msg, enum ndp_msg_type msg_type) +bool ndp_msgra_flag_other(struct ndp_msgra *msgra) { - struct ndp_msg *msg; - - if (msg_type == NDP_MSG_ALL) - return -EINVAL; - msg = ndp_msg_alloc(); - if (!msg) - return -ENOMEM; - ndp_msg_init(msg, msg_type); - *p_msg = msg; - return 0; + return msgra->ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER; } /** - * ndp_msg_destroy: + * ndp_msgra_flag_other_set: + * @msgra: RA message structure * - * Destroy message structure. + * Set RA other flag. **/ NDP_EXPORT -void ndp_msg_destroy(struct ndp_msg *msg) +void ndp_msgra_flag_other_set(struct ndp_msgra *msgra, bool flag_other) { - free(msg); + if (flag_other) + msgra->ra->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER; + else + msgra->ra->nd_ra_flags_reserved &= ~ND_RA_FLAG_OTHER; } /** - * ndp_msg_payload: - * @msg: message structure + * ndp_msgra_flag_home_agent: + * @msgra: RA message structure * - * Get raw Neighbour discovery packet data. + * Get RA home_agent flag. * - * Returns: pointer to raw data. + * Returns: home_agent flag. **/ NDP_EXPORT -void *ndp_msg_payload(struct ndp_msg *msg) +bool ndp_msgra_flag_home_agent(struct ndp_msgra *msgra) { - return msg->buf; + return msgra->ra->nd_ra_flags_reserved & ND_RA_FLAG_HOME_AGENT; } /** - * ndp_msg_payload_maxlen: - * @msg: message structure - * - * Get raw Neighbour discovery packet data maximum length. + * ndp_msgra_flag_home_agent_set: + * @msgra: RA message structure * - * Returns: length in bytes. + * Set RA home_agent flag. **/ NDP_EXPORT -size_t ndp_msg_payload_maxlen(struct ndp_msg *msg) +void ndp_msgra_flag_home_agent_set(struct ndp_msgra *msgra, + bool flag_home_agent) { - return sizeof(msg->buf); + if (flag_home_agent) + msgra->ra->nd_ra_flags_reserved |= ND_RA_FLAG_HOME_AGENT; + else + msgra->ra->nd_ra_flags_reserved &= ~ND_RA_FLAG_HOME_AGENT; } /** - * ndp_msg_payload_len: - * @msg: message structure + * ndp_msgra_router_lifetime: + * @msgra: RA message structure * - * Get raw Neighbour discovery packet data length. + * Get RA router lifetime. * - * Returns: length in bytes. + * Returns: router lifetime in seconds. **/ NDP_EXPORT -size_t ndp_msg_payload_len(struct ndp_msg *msg) +uint16_t ndp_msgra_router_lifetime(struct ndp_msgra *msgra) { - return msg->len; + return ntohs(msgra->ra->nd_ra_router_lifetime); } /** - * ndp_msg_payload_len_set: - * @msg: message structure + * ndp_msgra_router_lifetime_set: + * @msgra: RA message structure * - * Set raw Neighbour discovery packet data length. + * Set RA router lifetime. **/ NDP_EXPORT -void ndp_msg_payload_len_set(struct ndp_msg *msg, size_t len) +void ndp_msgra_router_lifetime_set(struct ndp_msgra *msgra, + uint16_t router_lifetime) { - if (len > sizeof(msg->buf)) - len = sizeof(msg->buf); - msg->len = len; + msgra->ra->nd_ra_router_lifetime = htons(router_lifetime); } /** - * ndp_msg_payload_opts: - * @msg: message structure + * ndp_msgra_reachable_time: + * @msgra: RA message structure * - * Get raw Neighbour discovery packet options part data. + * Get RA reachable time. * - * Returns: pointer to raw data. + * Returns: reachable time in milliseconds. **/ NDP_EXPORT -void *ndp_msg_payload_opts(struct ndp_msg *msg) +uint32_t ndp_msgra_reachable_time(struct ndp_msgra *msgra) { - return msg->opts_start; + return ntohl(msgra->ra->nd_ra_reachable); } /** - * ndp_msg_payload_opts_len: - * @msg: message structure - * - * Get raw Neighbour discovery packet options part data length. + * ndp_msgra_reachable_time_set: + * @msgra: RA message structure * - * Returns: length in bytes. + * Set RA reachable time. **/ NDP_EXPORT -size_t ndp_msg_payload_opts_len(struct ndp_msg *msg) +void ndp_msgra_reachable_time_set(struct ndp_msgra *msgra, + uint32_t reachable_time) { - return msg->len - (msg->opts_start - msg->buf); + msgra->ra->nd_ra_reachable = htonl(reachable_time); } /** - * ndp_msgrs: - * @msg: message structure + * ndp_msgra_retransmit_time: + * @msgra: RA message structure * - * Get RS message structure by passed @msg. + * Get RA retransmit time. * - * Returns: RS message structure or NULL in case the message is not of type RS. + * Returns: retransmit time in milliseconds. **/ NDP_EXPORT -struct ndp_msgrs *ndp_msgrs(struct ndp_msg *msg) +uint32_t ndp_msgra_retransmit_time(struct ndp_msgra *msgra) { - if (ndp_msg_type(msg) != NDP_MSG_RS) - return NULL; - return &msg->nd_msg.rs; + return ntohl(msgra->ra->nd_ra_retransmit); } /** - * ndp_msgra: - * @msg: message structure - * - * Get RA message structure by passed @msg. + * ndp_msgra_retransmit_time_set: + * @msgra: RA message structure * - * Returns: RA message structure or NULL in case the message is not of type RA. + * Set RA retransmit time. **/ NDP_EXPORT -struct ndp_msgra *ndp_msgra(struct ndp_msg *msg) +void ndp_msgra_retransmit_time_set(struct ndp_msgra *msgra, + uint32_t retransmit_time) { - if (ndp_msg_type(msg) != NDP_MSG_RA) - return NULL; - return &msg->nd_msg.ra; + msgra->ra->nd_ra_retransmit = htonl(retransmit_time); } + /** - * ndp_msgns: + * SECTION: msg_opt infrastructure + * @short_description: Infrastructure for options + */ + +struct ndp_msg_opt_type_info { + uint8_t raw_type; +}; + +static struct ndp_msg_opt_type_info ndp_msg_opt_type_info_list[] = +{ + [NDP_MSG_OPT_SLLADDR] = { + .raw_type = ND_OPT_SOURCE_LINKADDR, + }, + [NDP_MSG_OPT_TLLADDR] = { + .raw_type = ND_OPT_TARGET_LINKADDR, + }, + [NDP_MSG_OPT_PREFIX] = { + .raw_type = ND_OPT_PREFIX_INFORMATION, + }, + [NDP_MSG_OPT_REDIR] = { + .raw_type = ND_OPT_REDIRECTED_HEADER, + }, + [NDP_MSG_OPT_MTU] = { + .raw_type = ND_OPT_MTU, + }, +}; + +#define NDP_MSG_OPT_TYPE_LIST_SIZE ARRAY_SIZE(ndp_msg_opt_type_info_list) + +struct ndp_msg_opt_type_info *ndp_msg_opt_type_info(enum ndp_msg_opt_type msg_opt_type) +{ + return &ndp_msg_opt_type_info_list[msg_opt_type]; +} + +/** + * ndp_msg_next_opt_offset: * @msg: message structure + * @offset: option payload offset + * @opt_type: option type * - * Get NS message structure by passed @msg. + * Find next offset of option of given type. If offset is -1, start from + * beginning, otherwise start from the given offset. + * This funstion is internally used by ndp_msg_opt_for_each_offset() macro. * - * Returns: NS message structure or NULL in case the message is not of type NS. + * Returns: offset in opt payload of found opt of -1 in case it was not found. **/ NDP_EXPORT -struct ndp_msgns *ndp_msgns(struct ndp_msg *msg) -{ - if (ndp_msg_type(msg) != NDP_MSG_NS) - return NULL; - return &msg->nd_msg.ns; +int ndp_msg_next_opt_offset(struct ndp_msg *msg, int offset, + enum ndp_msg_opt_type opt_type) +{ + unsigned char *opts_start = ndp_msg_payload_opts(msg); + unsigned char *ptr = opts_start; + size_t len = ndp_msg_payload_opts_len(msg); + uint8_t opt_raw_type = ndp_msg_opt_type_info(opt_type)->raw_type; + bool ignore = true; + + if (offset == -1) { + offset = 0; + ignore = false; + } + + ptr += offset; + len -= offset; + while (len > 0) { + uint8_t cur_opt_raw_type = ptr[0]; + uint8_t cur_opt_len = ptr[1] << 3; /* convert to bytes */ + + if (!cur_opt_len || len < cur_opt_len) + break; + if (cur_opt_raw_type == opt_raw_type && !ignore) + return ptr - opts_start; + ptr += cur_opt_len; + len -= cur_opt_len; + ignore = false; + } + return -1; } + /** - * ndp_msgna: + * SECTION: msg_opt getters/setters + * @short_description: Getters and setters for options + */ + +/** + * ndp_msg_opt_slladdr: * @msg: message structure * - * Get NA message structure by passed @msg. + * Get source linkaddr. + * User should use this function only inside ndp_msg_opt_for_each_offset() + * macro loop. * - * Returns: NA message structure or NULL in case the message is not of type NA. + * Returns: pointer to source linkaddr. **/ NDP_EXPORT -struct ndp_msgna *ndp_msgna(struct ndp_msg *msg) +unsigned char *ndp_msg_opt_slladdr(struct ndp_msg *msg, int offset) { - if (ndp_msg_type(msg) != NDP_MSG_NA) - return NULL; - return &msg->nd_msg.na; + unsigned char *opt_data = ndp_msg_payload_opts_offset(msg, offset); + + return &opt_data[2]; } /** - * ndp_msgr: + * ndp_msg_opt_slladdr_len: * @msg: message structure * - * Get R message structure by passed @msg. + * Get source linkaddr length. + * User should use this function only inside ndp_msg_opt_for_each_offset() + * macro loop. * - * Returns: R message structure or NULL in case the message is not of type R. + * Returns: source linkaddr length. **/ NDP_EXPORT -struct ndp_msgr *ndp_msgr(struct ndp_msg *msg) +size_t ndp_msg_opt_slladdr_len(struct ndp_msg *msg, int offset) { - if (ndp_msg_type(msg) != NDP_MSG_R) - return NULL; - return &msg->nd_msg.r; + return ETH_ALEN; } /** - * ndp_msg_type: + * ndp_msg_opt_tlladdr: * @msg: message structure * - * Get type of message. + * Get target linkaddr. + * User should use this function only inside ndp_msg_opt_for_each_offset() + * macro loop. * - * Returns: Message type + * Returns: pointer to target linkaddr. **/ NDP_EXPORT -enum ndp_msg_type ndp_msg_type(struct ndp_msg *msg) +unsigned char *ndp_msg_opt_tlladdr(struct ndp_msg *msg, int offset) { - enum ndp_msg_type msg_type; - int err; + unsigned char *opt_data = ndp_msg_payload_opts_offset(msg, offset); - err = ndp_msg_type_by_raw_type(&msg_type, msg->icmp6_hdr->icmp6_type); - /* Type should be always set correctly (ensured by ndp_msg_init) */ - BUG_ON(err); - return msg_type; + return &opt_data[2]; } -static void ndp_msg_type_set(struct ndp_msg *msg, enum ndp_msg_type msg_type) +/** + * ndp_msg_opt_tlladdr_len: + * @msg: message structure + * + * Get target linkaddr length. + * User should use this function only inside ndp_msg_opt_for_each_offset() + * macro loop. + * + * Returns: target linkaddr length. + **/ +NDP_EXPORT +size_t ndp_msg_opt_tlladdr_len(struct ndp_msg *msg, int offset) { - msg->icmp6_hdr->icmp6_type = ndp_msg_type_info(msg_type)->raw_type; + return ETH_ALEN; } /** - * ndp_msg_addrto: + * ndp_msg_opt_prefix: * @msg: message structure * - * Get "to address" of message. + * Get prefix addr. + * User should use this function only inside ndp_msg_opt_for_each_offset() + * macro loop. * * Returns: pointer to address. **/ NDP_EXPORT -struct in6_addr *ndp_msg_addrto(struct ndp_msg *msg) +struct in6_addr *ndp_msg_opt_prefix(struct ndp_msg *msg, int offset) { - return &msg->addrto; + struct nd_opt_prefix_info *pi = + ndp_msg_payload_opts_offset(msg, offset); + + return &pi->nd_opt_pi_prefix; } /** - * ndp_msg_ifindex: + * ndp_msg_opt_prefix_len: * @msg: message structure * - * Get interface index of message. + * Get prefix length. + * User should use this function only inside ndp_msg_opt_for_each_offset() + * macro loop. * - * Returns: Inteface index + * Returns: length of prefix. **/ NDP_EXPORT -uint32_t ndp_msg_ifindex(struct ndp_msg *msg) +uint8_t ndp_msg_opt_prefix_len(struct ndp_msg *msg, int offset) { - return msg->ifindex; + struct nd_opt_prefix_info *pi = + ndp_msg_payload_opts_offset(msg, offset); + + return pi->nd_opt_pi_prefix_len; } /** - * ndp_msg_ifindex_set: + * ndp_msg_opt_prefix_valid_time: * @msg: message structure * - * Set raw interface index of message. + * Get prefix valid time. + * User should use this function only inside ndp_msg_opt_for_each_offset() + * macro loop. + * + * Returns: valid time in seconds, (uint32_t) -1 means infinity. **/ NDP_EXPORT -void ndp_msg_ifindex_set(struct ndp_msg *msg, uint32_t ifindex) +uint32_t ndp_msg_opt_prefix_valid_time(struct ndp_msg *msg, int offset) { - msg->ifindex = ifindex; + struct nd_opt_prefix_info *pi = + ndp_msg_payload_opts_offset(msg, offset); + + return ntohl(pi->nd_opt_pi_valid_time); } /** - * ndp_msg_send: - * @ndp: libndp library context + * ndp_msg_opt_prefix_preferred_time: * @msg: message structure * - * Send message. + * Get prefix preferred time. + * User should use this function only inside ndp_msg_opt_for_each_offset() + * macro loop. * - * Returns: zero on success or negative number in case of an error. + * Returns: preferred time in seconds, (uint32_t) -1 means infinity. **/ NDP_EXPORT -int ndp_msg_send(struct ndp *ndp, struct ndp_msg *msg) +uint32_t ndp_msg_opt_prefix_preferred_time(struct ndp_msg *msg, int offset) { - enum ndp_msg_type msg_type = ndp_msg_type(msg); - - if (ndp_msg_type_info(msg_type)->addrto_adjust) - ndp_msg_type_info(msg_type)->addrto_adjust(&msg->addrto); - return mysendto6(ndp->sock, msg->buf, msg->len, 0, - &msg->addrto, msg->ifindex); -} + struct nd_opt_prefix_info *pi = + ndp_msg_payload_opts_offset(msg, offset); -static void ndp_process_ra_opt(struct ndp_msgra *msgra, unsigned char *opt_data, - uint8_t opt_type, uint8_t opt_len) -{ - if (opt_type == ND_OPT_SOURCE_LINKADDR) { - if (opt_len != 8) - return; /* unsupported address length */ - memcpy(msgra->opt_source_linkaddr.addr, &opt_data[2], - sizeof(msgra->opt_source_linkaddr)); - msgra->opt_source_linkaddr.present = true; - } else if (opt_type == ND_OPT_TARGET_LINKADDR) { - if (opt_len != 8) - return; /* unsupported address length */ - memcpy(msgra->opt_target_linkaddr.addr, &opt_data[2], - sizeof(msgra->opt_target_linkaddr)); - msgra->opt_target_linkaddr.present = true; - } else if (opt_type == ND_OPT_PREFIX_INFORMATION) { - struct nd_opt_prefix_info *pi; - - pi = (struct nd_opt_prefix_info *) opt_data; - msgra->opt_prefix.prefix = pi->nd_opt_pi_prefix; - msgra->opt_prefix.prefix_len = pi->nd_opt_pi_prefix_len; - msgra->opt_prefix.valid_time = ntohl(pi->nd_opt_pi_valid_time); - msgra->opt_prefix.preferred_time = - ntohl(pi->nd_opt_pi_preferred_time); - msgra->opt_prefix.flag_onlink = - pi->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK; - msgra->opt_prefix.flag_auto = - pi->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO; - msgra->opt_prefix.flag_raddr = - pi->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_RADDR; - msgra->opt_prefix.present = true; - } else if (opt_type == ND_OPT_MTU) { - struct nd_opt_mtu *mtu; - - mtu = (struct nd_opt_mtu *) opt_data; - msgra->opt_mtu.mtu = ntohl(mtu->nd_opt_mtu_mtu); - msgra->opt_mtu.present = true; - } + return ntohl(pi->nd_opt_pi_preferred_time); } -static void ndp_process_ra(struct ndp *ndp, struct ndp_msg *msg) +/** + * ndp_msg_opt_mtu: + * @msg: message structure + * + * Get MTU. User should check if mtu option is present before calling this. + * + * Returns: MTU. + **/ +NDP_EXPORT +uint32_t ndp_msg_opt_mtu(struct ndp_msg *msg, int offset) { - struct ndp_msgra *msgra = ndp_msgra(msg); - size_t len = ndp_msg_payload_len(msg); - unsigned char *ptr; - - ptr = ndp_msg_payload_opts(msg); - len = ndp_msg_payload_opts_len(msg); - while (len > 0) { - uint8_t opt_type = ptr[0]; - uint8_t opt_len = ptr[1] << 3; /* convert to bytes */ + struct nd_opt_mtu *mtu = ndp_msg_payload_opts_offset(msg, offset); - if (!opt_len || len < opt_len) - break; - ndp_process_ra_opt(msgra, ptr, opt_type, opt_len); - ptr += opt_len; - len -= opt_len; - } + return ntohl(mtu->nd_opt_mtu_mtu); } static int ndp_call_handlers(struct ndp *ndp, struct ndp_msg *msg); @@ -1211,9 +1220,6 @@ static int ndp_sock_recv(struct ndp *ndp) dbg(ndp, "rcvd %s, len: %luB", ndp_msg_type_info(msg_type)->strabbr, len); - if (msg->icmp6_hdr->icmp6_type == ND_ROUTER_ADVERT) - ndp_process_ra(ndp, msg); - err = ndp_call_handlers(ndp, msg);; free_msg: -- cgit v1.2.1