/** * Transmit NDP neighbour solicitation/advertisement packet * * @v netdev Network device * @v sin6_src Source socket address * @v sin6_dest Destination socket address * @v target Neighbour target address * @v icmp_type ICMPv6 type * @v flags NDP flags * @v option_type NDP option type * @ret rc Return status code */ static int ndp_tx_neighbour ( struct net_device *netdev, struct sockaddr_in6 *sin6_src, struct sockaddr_in6 *sin6_dest, const struct in6_addr *target, unsigned int icmp_type, unsigned int flags, unsigned int option_type ) { struct sockaddr_tcpip *st_src = ( ( struct sockaddr_tcpip * ) sin6_src ); struct sockaddr_tcpip *st_dest = ( ( struct sockaddr_tcpip * ) sin6_dest ); struct ll_protocol *ll_protocol = netdev->ll_protocol; struct io_buffer *iobuf; struct ndp_neighbour_header *neigh; struct ndp_ll_addr_option *ll_addr_opt; size_t option_len; size_t len; int rc; /* Allocate and populate buffer */ option_len = ( ( sizeof ( *ll_addr_opt ) + ll_protocol->ll_addr_len + NDP_OPTION_BLKSZ - 1 ) & ~( NDP_OPTION_BLKSZ - 1 ) ); len = ( sizeof ( *neigh ) + option_len ); iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len ); if ( ! iobuf ) return -ENOMEM; iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN ); neigh = iob_put ( iobuf, len ); memset ( neigh, 0, len ); neigh->icmp.type = icmp_type; neigh->flags = flags; memcpy ( &neigh->target, target, sizeof ( neigh->target ) ); ll_addr_opt = &neigh->option[0].ll_addr; ll_addr_opt->header.type = option_type; ll_addr_opt->header.blocks = ( option_len / NDP_OPTION_BLKSZ ); memcpy ( ll_addr_opt->ll_addr, netdev->ll_addr, ll_protocol->ll_addr_len ); neigh->icmp.chksum = tcpip_chksum ( neigh, len ); /* Transmit packet */ if ( ( rc = tcpip_tx ( iobuf, &icmpv6_protocol, st_src, st_dest, netdev, &neigh->icmp.chksum ) ) != 0 ) { DBGC ( netdev, "NDP could not transmit packet: %s\n", strerror ( rc ) ); return rc; } return 0; }
static void gdbudp_send ( const char *buf, size_t len ) { struct io_buffer *iob; struct ethhdr *ethhdr; struct iphdr *iphdr; struct udp_header *udphdr; /* Check that we are connected */ if ( dest_addr.sin_port == 0 ) { return; } gdbudp_ensure_netdev_open ( netdev ); iob = alloc_iob ( sizeof ( *ethhdr ) + sizeof ( *iphdr ) + sizeof ( *udphdr ) + len ); if ( !iob ) { return; } /* Payload */ iob_reserve ( iob, sizeof ( *ethhdr ) + sizeof ( *iphdr ) + sizeof ( *udphdr ) ); memcpy ( iob_put ( iob, len ), buf, len ); /* UDP header */ udphdr = iob_push ( iob, sizeof ( *udphdr ) ); udphdr->src = source_addr.sin_port; udphdr->dest = dest_addr.sin_port; udphdr->len = htons ( iob_len ( iob ) ); udphdr->chksum = 0; /* optional and we are not using it */ /* IP header */ iphdr = iob_push ( iob, sizeof ( *iphdr ) ); memset ( iphdr, 0, sizeof ( *iphdr ) ); iphdr->verhdrlen = ( IP_VER | ( sizeof ( *iphdr ) / 4 ) ); iphdr->service = IP_TOS; iphdr->len = htons ( iob_len ( iob ) ); iphdr->ttl = IP_TTL; iphdr->protocol = IP_UDP; iphdr->dest.s_addr = dest_addr.sin_addr.s_addr; iphdr->src.s_addr = source_addr.sin_addr.s_addr; iphdr->chksum = tcpip_chksum ( iphdr, sizeof ( *iphdr ) ); /* Ethernet header */ ethhdr = iob_push ( iob, sizeof ( *ethhdr ) ); memcpy ( ethhdr->h_dest, dest_eth, ETH_ALEN ); memcpy ( ethhdr->h_source, netdev->ll_addr, ETH_ALEN ); ethhdr->h_protocol = htons ( ETH_P_IP ); netdev_tx ( netdev, iob ); }
/** * Transmit NDP packet with link-layer address option * * @v netdev Network device * @v sin6_src Source socket address * @v sin6_dest Destination socket address * @v data NDP header * @v len Size of NDP header * @v option_type NDP option type * @ret rc Return status code */ static int ndp_tx_ll_addr ( struct net_device *netdev, struct sockaddr_in6 *sin6_src, struct sockaddr_in6 *sin6_dest, const void *data, size_t len, unsigned int option_type ) { struct sockaddr_tcpip *st_src = ( ( struct sockaddr_tcpip * ) sin6_src ); struct sockaddr_tcpip *st_dest = ( ( struct sockaddr_tcpip * ) sin6_dest ); struct ll_protocol *ll_protocol = netdev->ll_protocol; struct io_buffer *iobuf; struct ndp_ll_addr_option *ll_addr_opt; union ndp_header *ndp; size_t option_len; int rc; /* Allocate and populate buffer */ option_len = ( ( sizeof ( *ll_addr_opt ) + ll_protocol->ll_addr_len + NDP_OPTION_BLKSZ - 1 ) & ~( NDP_OPTION_BLKSZ - 1 ) ); iobuf = alloc_iob ( MAX_LL_NET_HEADER_LEN + len + option_len ); if ( ! iobuf ) return -ENOMEM; iob_reserve ( iobuf, MAX_LL_NET_HEADER_LEN ); memcpy ( iob_put ( iobuf, len ), data, len ); ll_addr_opt = iob_put ( iobuf, option_len ); ll_addr_opt->header.type = option_type; ll_addr_opt->header.blocks = ( option_len / NDP_OPTION_BLKSZ ); memcpy ( ll_addr_opt->ll_addr, netdev->ll_addr, ll_protocol->ll_addr_len ); ndp = iobuf->data; ndp->icmp.chksum = tcpip_chksum ( ndp, ( len + option_len ) ); /* Transmit packet */ if ( ( rc = tcpip_tx ( iobuf, &icmpv6_protocol, st_src, st_dest, netdev, &ndp->icmp.chksum ) ) != 0 ) { DBGC ( netdev, "NDP could not transmit packet: %s\n", strerror ( rc ) ); return rc; } return 0; }