Annotation of embedaddon/mtr/packet/construct_unix.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:     mtr  --  a network diagnostic tool
                      3:     Copyright (C) 2016  Matt Kimball
                      4: 
                      5:     This program is free software; you can redistribute it and/or modify
                      6:     it under the terms of the GNU General Public License version 2 as
                      7:     published by the Free Software Foundation.
                      8: 
                      9:     This program is distributed in the hope that it will be useful,
                     10:     but WITHOUT ANY WARRANTY; without even the implied warranty of
                     11:     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     12:     GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
                     17: */
                     18: 
                     19: #include "construct_unix.h"
                     20: 
                     21: #include <errno.h>
                     22: #include <stdio.h>
                     23: #include <string.h>
                     24: #include <sys/socket.h>
                     25: #include <unistd.h>
                     26: 
                     27: #include "protocols.h"
                     28: 
                     29: /*  A source of data for computing a checksum  */
                     30: struct checksum_source_t {
                     31:     const void *data;
                     32:     size_t size;
                     33: };
                     34: 
                     35: /*  Compute the IP checksum (or ICMP checksum) of a packet.  */
                     36: static
                     37: uint16_t compute_checksum(
                     38:     const void *packet,
                     39:     int size)
                     40: {
                     41:     const uint8_t *packet_bytes = (uint8_t *) packet;
                     42:     uint32_t sum = 0;
                     43:     int i;
                     44: 
                     45:     for (i = 0; i < size; i++) {
                     46:         if ((i & 1) == 0) {
                     47:             sum += packet_bytes[i] << 8;
                     48:         } else {
                     49:             sum += packet_bytes[i];
                     50:         }
                     51:     }
                     52: 
                     53:     /*
                     54:        Sums which overflow a 16-bit value have the high bits
                     55:        added back into the low 16 bits.
                     56:      */
                     57:     while (sum >> 16) {
                     58:         sum = (sum >> 16) + (sum & 0xffff);
                     59:     }
                     60: 
                     61:     /*
                     62:        The value stored is the one's complement of the
                     63:        mathematical sum.
                     64:      */
                     65:     return (~sum & 0xffff);
                     66: }
                     67: 
                     68: /*  Encode the IP header length field in the order required by the OS.  */
                     69: static
                     70: uint16_t length_byte_swap(
                     71:     const struct net_state_t *net_state,
                     72:     uint16_t length)
                     73: {
                     74:     if (net_state->platform.ip_length_host_order) {
                     75:         return length;
                     76:     } else {
                     77:         return htons(length);
                     78:     }
                     79: }
                     80: 
                     81: /*  Construct a combined sockaddr from a source address and source port  */
                     82: static
                     83: void construct_addr_port(
                     84:     struct sockaddr_storage *addr_with_port,
                     85:     const struct sockaddr_storage *addr,
                     86:     int port)
                     87: {
                     88:     struct sockaddr_in *addr4;
                     89:     struct sockaddr_in6 *addr6;
                     90: 
                     91:     memcpy(addr_with_port, addr, sizeof(struct sockaddr_storage));
                     92: 
                     93:     if (addr->ss_family == AF_INET6) {
                     94:         addr6 = (struct sockaddr_in6 *) addr_with_port;
                     95:         addr6->sin6_port = htons(port);
                     96:     } else {
                     97:         addr4 = (struct sockaddr_in *) addr_with_port;
                     98:         addr4->sin_port = htons(port);
                     99:     }
                    100: }
                    101: 
                    102: /*  Construct a header for IP version 4  */
                    103: static
                    104: void construct_ip4_header(
                    105:     const struct net_state_t *net_state,
                    106:     char *packet_buffer,
                    107:     int packet_size,
                    108:     const struct sockaddr_storage *srcaddr,
                    109:     const struct sockaddr_storage *destaddr,
                    110:     const struct probe_param_t *param)
                    111: {
                    112:     struct IPHeader *ip;
                    113:     struct sockaddr_in *srcaddr4 = (struct sockaddr_in *) srcaddr;
                    114:     struct sockaddr_in *destaddr4 = (struct sockaddr_in *) destaddr;
                    115: 
                    116:     ip = (struct IPHeader *) &packet_buffer[0];
                    117: 
                    118:     memset(ip, 0, sizeof(struct IPHeader));
                    119: 
                    120:     ip->version = 0x45;
                    121:     ip->tos = param->type_of_service;
                    122:     ip->len = length_byte_swap(net_state, packet_size);
                    123:     ip->ttl = param->ttl;
                    124:     ip->protocol = param->protocol;
                    125:     memcpy(&ip->saddr, &srcaddr4->sin_addr, sizeof(uint32_t));
                    126:     memcpy(&ip->daddr, &destaddr4->sin_addr, sizeof(uint32_t));
                    127: }
                    128: 
                    129: /*  Construct an ICMP header for IPv4  */
                    130: static
                    131: void construct_icmp4_header(
                    132:     const struct net_state_t *net_state,
                    133:     int sequence,
                    134:     char *packet_buffer,
                    135:     int packet_size,
                    136:     const struct probe_param_t *param)
                    137: {
                    138:     struct ICMPHeader *icmp;
                    139:     int icmp_size;
                    140: 
                    141:     icmp = (struct ICMPHeader *) &packet_buffer[sizeof(struct IPHeader)];
                    142:     icmp_size = packet_size - sizeof(struct IPHeader);
                    143: 
                    144:     memset(icmp, 0, sizeof(struct ICMPHeader));
                    145: 
                    146:     icmp->type = ICMP_ECHO;
                    147:     icmp->id = htons(getpid());
                    148:     icmp->sequence = htons(sequence);
                    149:     icmp->checksum = htons(compute_checksum(icmp, icmp_size));
                    150: }
                    151: 
                    152: /*  Construct an ICMP header for IPv6  */
                    153: static
                    154: int construct_icmp6_packet(
                    155:     const struct net_state_t *net_state,
                    156:     int sequence,
                    157:     char *packet_buffer,
                    158:     int packet_size,
                    159:     const struct probe_param_t *param)
                    160: {
                    161:     struct ICMPHeader *icmp;
                    162: 
                    163:     icmp = (struct ICMPHeader *) packet_buffer;
                    164: 
                    165:     memset(icmp, 0, sizeof(struct ICMPHeader));
                    166: 
                    167:     icmp->type = ICMP6_ECHO;
                    168:     icmp->id = htons(getpid());
                    169:     icmp->sequence = htons(sequence);
                    170: 
                    171:     return 0;
                    172: }
                    173: 
                    174: /*
                    175:     Set the port numbers for an outgoing UDP probe.
                    176:     There is limited space in the header for a sequence number
                    177:     to identify the probe upon return.
                    178: 
                    179:     We store the sequence number in the destination port, the local
                    180:     port, or the checksum.  The location chosen depends upon which
                    181:     probe parameters have been requested.
                    182: */
                    183: static
                    184: void set_udp_ports(
                    185:     struct UDPHeader *udp,
                    186:     int sequence,
                    187:     const struct probe_param_t *param)
                    188: {
                    189:     if (param->dest_port) {
                    190:         udp->dstport = htons(param->dest_port);
                    191: 
                    192:         if (param->local_port) {
                    193:             udp->srcport = htons(param->local_port);
                    194:             udp->checksum = htons(sequence);
                    195:         } else {
                    196:             udp->srcport = htons(sequence);
                    197:             udp->checksum = 0;
                    198:         }
                    199:     } else {
                    200:         udp->dstport = htons(sequence);
                    201: 
                    202:         if (param->local_port) {
                    203:             udp->srcport = htons(param->local_port);
                    204:         } else {
                    205:             udp->srcport = htons(getpid());
                    206:         }
                    207: 
                    208:         udp->checksum = 0;
                    209:     }
                    210: }
                    211: 
                    212: /*
                    213:     Construct a header for UDP probes, using the port number associated
                    214:     with the probe.
                    215: */
                    216: static
                    217: void construct_udp4_header(
                    218:     const struct net_state_t *net_state,
                    219:     int sequence,
                    220:     char *packet_buffer,
                    221:     int packet_size,
                    222:     const struct probe_param_t *param)
                    223: {
                    224:     struct UDPHeader *udp;
                    225:     int udp_size;
                    226: 
                    227:     udp = (struct UDPHeader *) &packet_buffer[sizeof(struct IPHeader)];
                    228:     udp_size = packet_size - sizeof(struct IPHeader);
                    229: 
                    230:     memset(udp, 0, sizeof(struct UDPHeader));
                    231: 
                    232:     set_udp_ports(udp, sequence, param);
                    233:     udp->length = htons(udp_size);
                    234: }
                    235: 
                    236: /*  Construct a header for UDPv6 probes  */
                    237: static
                    238: int construct_udp6_packet(
                    239:     const struct net_state_t *net_state,
                    240:     int sequence,
                    241:     char *packet_buffer,
                    242:     int packet_size,
                    243:     const struct probe_param_t *param)
                    244: {
                    245:     int udp_socket = net_state->platform.udp6_send_socket;
                    246:     struct UDPHeader *udp;
                    247:     int udp_size;
                    248: 
                    249:     udp = (struct UDPHeader *) packet_buffer;
                    250:     udp_size = packet_size;
                    251: 
                    252:     memset(udp, 0, sizeof(struct UDPHeader));
                    253: 
                    254:     set_udp_ports(udp, sequence, param);
                    255:     udp->length = htons(udp_size);
                    256: 
                    257:     /*
                    258:        Instruct the kernel to put the pseudoheader checksum into the
                    259:        UDP header.
                    260:      */
                    261:     int chksum_offset = (char *) &udp->checksum - (char *) udp;
                    262:     if (setsockopt(udp_socket, IPPROTO_IPV6,
                    263:                    IPV6_CHECKSUM, &chksum_offset, sizeof(int))) {
                    264:         return -1;
                    265:     }
                    266: 
                    267:     return 0;
                    268: }
                    269: 
                    270: /*
                    271:     Set the socket options for an outgoing stream protocol socket based on
                    272:     the packet parameters.
                    273: */
                    274: static
                    275: int set_stream_socket_options(
                    276:     int stream_socket,
                    277:     const struct probe_param_t *param)
                    278: {
                    279:     int level;
                    280:     int opt;
                    281:     int reuse = 1;
                    282: 
                    283:     /*  Allow binding to a local port previously in use  */
                    284: #ifdef SO_REUSEPORT
                    285:     /*
                    286:        FreeBSD wants SO_REUSEPORT in addition to SO_REUSEADDR to
                    287:        bind to the same port
                    288:      */
                    289:     if (setsockopt(stream_socket, SOL_SOCKET, SO_REUSEPORT,
                    290:                    &reuse, sizeof(int)) == -1) {
                    291: 
                    292:         return -1;
                    293:     }
                    294: #endif
                    295: 
                    296:     if (setsockopt(stream_socket, SOL_SOCKET, SO_REUSEADDR,
                    297:                    &reuse, sizeof(int)) == -1) {
                    298: 
                    299:         return -1;
                    300:     }
                    301: 
                    302:     /*  Set the number of hops the probe will transit across  */
                    303:     if (param->ip_version == 6) {
                    304:         level = IPPROTO_IPV6;
                    305:         opt = IPV6_UNICAST_HOPS;
                    306:     } else {
                    307:         level = IPPROTO_IP;
                    308:         opt = IP_TTL;
                    309:     }
                    310: 
                    311:     if (setsockopt(stream_socket, level, opt, &param->ttl, sizeof(int)) ==
                    312:         -1) {
                    313: 
                    314:         return -1;
                    315:     }
                    316: 
                    317:     /*  Set the "type of service" field of the IP header  */
                    318:     if (param->ip_version == 6) {
                    319:         level = IPPROTO_IPV6;
                    320:         opt = IPV6_TCLASS;
                    321:     } else {
                    322:         level = IPPROTO_IP;
                    323:         opt = IP_TOS;
                    324:     }
                    325: 
                    326:     if (setsockopt(stream_socket, level, opt,
                    327:                    &param->type_of_service, sizeof(int)) == -1) {
                    328: 
                    329:         return -1;
                    330:     }
                    331: #ifdef SO_MARK
                    332:     if (param->routing_mark) {
                    333:         if (setsockopt(stream_socket, SOL_SOCKET,
                    334:                        SO_MARK, &param->routing_mark, sizeof(int))) {
                    335:             return -1;
                    336:         }
                    337:     }
                    338: #endif
                    339: 
                    340:     return 0;
                    341: }
                    342: 
                    343: /*
                    344:     Open a TCP or SCTP socket, respecting the probe paramters as much as
                    345:     we can, and use it as an outgoing probe.
                    346: */
                    347: static
                    348: int open_stream_socket(
                    349:     const struct net_state_t *net_state,
                    350:     int protocol,
                    351:     int port,
                    352:     const struct sockaddr_storage *src_sockaddr,
                    353:     const struct sockaddr_storage *dest_sockaddr,
                    354:     const struct probe_param_t *param)
                    355: {
                    356:     int stream_socket;
                    357:     int addr_len;
                    358:     int dest_port;
                    359:     struct sockaddr_storage dest_port_addr;
                    360:     struct sockaddr_storage src_port_addr;
                    361: 
                    362:     if (param->ip_version == 6) {
                    363:         stream_socket = socket(AF_INET6, SOCK_STREAM, protocol);
                    364:         addr_len = sizeof(struct sockaddr_in6);
                    365:     } else if (param->ip_version == 4) {
                    366:         stream_socket = socket(AF_INET, SOCK_STREAM, protocol);
                    367:         addr_len = sizeof(struct sockaddr_in);
                    368:     } else {
                    369:         errno = EINVAL;
                    370:         return -1;
                    371:     }
                    372: 
                    373:     if (stream_socket == -1) {
                    374:         return -1;
                    375:     }
                    376: 
                    377:     set_socket_nonblocking(stream_socket);
                    378: 
                    379:     if (set_stream_socket_options(stream_socket, param)) {
                    380:         close(stream_socket);
                    381:         return -1;
                    382:     }
                    383: 
                    384:     /*
                    385:        Bind to a known local port so we can identify which probe
                    386:        causes a TTL expiration.
                    387:      */
                    388:     construct_addr_port(&src_port_addr, src_sockaddr, port);
                    389:     if (bind(stream_socket, (struct sockaddr *) &src_port_addr, addr_len)) {
                    390:         close(stream_socket);
                    391:         return -1;
                    392:     }
                    393: 
                    394:     if (param->dest_port) {
                    395:         dest_port = param->dest_port;
                    396:     } else {
                    397:         /*  Use http if no port is specified  */
                    398:         dest_port = HTTP_PORT;
                    399:     }
                    400: 
                    401:     /*  Attempt a connection  */
                    402:     construct_addr_port(&dest_port_addr, dest_sockaddr, dest_port);
                    403:     if (connect
                    404:         (stream_socket, (struct sockaddr *) &dest_port_addr, addr_len)) {
                    405: 
                    406:         /*  EINPROGRESS simply means the connection is in progress  */
                    407:         if (errno != EINPROGRESS) {
                    408:             close(stream_socket);
                    409:             return -1;
                    410:         }
                    411:     }
                    412: 
                    413:     return stream_socket;
                    414: }
                    415: 
                    416: /*
                    417:     Determine the size of the constructed packet based on the packet
                    418:     parameters.  This is the amount of space the packet *we* construct
                    419:     uses, and doesn't include any headers the operating system tacks
                    420:     onto the packet.  (Such as the IPv6 header on non-Linux operating
                    421:     systems.)
                    422: */
                    423: static
                    424: int compute_packet_size(
                    425:     const struct net_state_t *net_state,
                    426:     const struct probe_param_t *param)
                    427: {
                    428:     int packet_size;
                    429: 
                    430:     if (param->protocol == IPPROTO_TCP) {
                    431:         return 0;
                    432:     }
                    433: #ifdef IPPROTO_SCTP
                    434:     if (param->protocol == IPPROTO_SCTP) {
                    435:         return 0;
                    436:     }
                    437: #endif
                    438: 
                    439:     /*  Start by determining the full size, including omitted headers  */
                    440:     if (param->ip_version == 6) {
                    441:         packet_size = sizeof(struct IP6Header);
                    442:     } else if (param->ip_version == 4) {
                    443:         packet_size = sizeof(struct IPHeader);
                    444:     } else {
                    445:         errno = EINVAL;
                    446:         return -1;
                    447:     }
                    448: 
                    449:     if (param->protocol == IPPROTO_ICMP) {
                    450:         packet_size += sizeof(struct ICMPHeader);
                    451:     } else if (param->protocol == IPPROTO_UDP) {
                    452:         packet_size += sizeof(struct UDPHeader);
                    453: 
                    454:         /*  We may need to put the sequence number in the payload  */
                    455:         packet_size += sizeof(int);
                    456:     } else {
                    457:         errno = EINVAL;
                    458:         return -1;
                    459:     }
                    460: 
                    461:     /*
                    462:        If the requested size from send-probe is greater, extend the
                    463:        packet size.
                    464:      */
                    465:     if (param->packet_size > packet_size) {
                    466:         packet_size = param->packet_size;
                    467:     }
                    468: 
                    469:     /*
                    470:        Since we don't explicitly construct the IPv6 header, we
                    471:        need to account for it in our transmitted size.
                    472:      */
                    473:     if (param->ip_version == 6) {
                    474:         packet_size -= sizeof(struct IP6Header);
                    475:     }
                    476: 
                    477:     return packet_size;
                    478: }
                    479: 
                    480: /*  Construct a packet for an IPv4 probe  */
                    481: static
                    482: int construct_ip4_packet(
                    483:     const struct net_state_t *net_state,
                    484:     int *packet_socket,
                    485:     int sequence,
                    486:     char *packet_buffer,
                    487:     int packet_size,
                    488:     const struct sockaddr_storage *src_sockaddr,
                    489:     const struct sockaddr_storage *dest_sockaddr,
                    490:     const struct probe_param_t *param)
                    491: {
                    492:     int send_socket = net_state->platform.ip4_send_socket;
                    493:     bool is_stream_protocol = false;
                    494: 
                    495:     if (param->protocol == IPPROTO_TCP) {
                    496:         is_stream_protocol = true;
                    497: #ifdef IPPROTO_SCTP
                    498:     } else if (param->protocol == IPPROTO_SCTP) {
                    499:         is_stream_protocol = true;
                    500: #endif
                    501:     } else {
                    502:         construct_ip4_header(net_state, packet_buffer, packet_size,
                    503:                              src_sockaddr, dest_sockaddr, param);
                    504: 
                    505:         if (param->protocol == IPPROTO_ICMP) {
                    506:             construct_icmp4_header(net_state, sequence, packet_buffer,
                    507:                                    packet_size, param);
                    508:         } else if (param->protocol == IPPROTO_UDP) {
                    509:             construct_udp4_header(net_state, sequence, packet_buffer,
                    510:                                   packet_size, param);
                    511:         } else {
                    512:             errno = EINVAL;
                    513:             return -1;
                    514:         }
                    515:     }
                    516: 
                    517:     if (is_stream_protocol) {
                    518:         send_socket =
                    519:             open_stream_socket(net_state, param->protocol, sequence,
                    520:                                src_sockaddr, dest_sockaddr, param);
                    521: 
                    522:         if (send_socket == -1) {
                    523:             return -1;
                    524:         }
                    525: 
                    526:         *packet_socket = send_socket;
                    527:         return 0;
                    528:     }
                    529: 
                    530:     /*
                    531:        The routing mark requires CAP_NET_ADMIN, as opposed to the
                    532:        CAP_NET_RAW which we are sometimes explicitly given.
                    533:        If we don't have CAP_NET_ADMIN, this will fail, so we'll 
                    534:        only set the mark if the user has explicitly requested it.
                    535: 
                    536:        Unfortunately, this means that once the mark is set, it won't
                    537:        be set on the socket again until a new mark is explicitly
                    538:        specified.
                    539:      */
                    540: #ifdef SO_MARK
                    541:     if (param->routing_mark) {
                    542:         if (setsockopt(send_socket, SOL_SOCKET,
                    543:                        SO_MARK, &param->routing_mark, sizeof(int))) {
                    544:             return -1;
                    545:         }
                    546:     }
                    547: #endif
                    548: 
                    549:     return 0;
                    550: }
                    551: 
                    552: /*  Construct a packet for an IPv6 probe  */
                    553: static
                    554: int construct_ip6_packet(
                    555:     const struct net_state_t *net_state,
                    556:     int *packet_socket,
                    557:     int sequence,
                    558:     char *packet_buffer,
                    559:     int packet_size,
                    560:     const struct sockaddr_storage *src_sockaddr,
                    561:     const struct sockaddr_storage *dest_sockaddr,
                    562:     const struct probe_param_t *param)
                    563: {
                    564:     int send_socket;
                    565:     bool is_stream_protocol = false;
                    566:     bool bind_send_socket = true;
                    567:     struct sockaddr_storage current_sockaddr;
                    568:     int current_sockaddr_len;
                    569: 
                    570:     if (param->protocol == IPPROTO_TCP) {
                    571:         is_stream_protocol = true;
                    572: #ifdef IPPROTO_SCTP
                    573:     } else if (param->protocol == IPPROTO_SCTP) {
                    574:         is_stream_protocol = true;
                    575: #endif
                    576:     } else if (param->protocol == IPPROTO_ICMP) {
                    577:         send_socket = net_state->platform.icmp6_send_socket;
                    578: 
                    579:         if (construct_icmp6_packet
                    580:             (net_state, sequence, packet_buffer, packet_size, param)) {
                    581:             return -1;
                    582:         }
                    583:     } else if (param->protocol == IPPROTO_UDP) {
                    584:         send_socket = net_state->platform.udp6_send_socket;
                    585: 
                    586:         if (construct_udp6_packet
                    587:             (net_state, sequence, packet_buffer, packet_size, param)) {
                    588:             return -1;
                    589:         }
                    590:     } else {
                    591:         errno = EINVAL;
                    592:         return -1;
                    593:     }
                    594: 
                    595:     if (is_stream_protocol) {
                    596:         send_socket =
                    597:             open_stream_socket(net_state, param->protocol, sequence,
                    598:                                src_sockaddr, dest_sockaddr, param);
                    599: 
                    600:         if (send_socket == -1) {
                    601:             return -1;
                    602:         }
                    603: 
                    604:         *packet_socket = send_socket;
                    605:         return 0;
                    606:     }
                    607: 
                    608:     /*
                    609:        Check the current socket address, and if it is the same
                    610:        as the source address we intend, we will skip the bind.
                    611:        This is to accomodate Solaris, which, as of Solaris 11.3,
                    612:        will return an EINVAL error on bind if the socket is already
                    613:        bound, even if the same address is used.
                    614:      */
                    615:     current_sockaddr_len = sizeof(struct sockaddr_in6);
                    616:     if (getsockname(send_socket, (struct sockaddr *) &current_sockaddr,
                    617:                     &current_sockaddr_len) == 0) {
                    618: 
                    619:         if (memcmp(&current_sockaddr,
                    620:                    src_sockaddr, sizeof(struct sockaddr_in6)) == 0) {
                    621:             bind_send_socket = false;
                    622:         }
                    623:     }
                    624: 
                    625:     /*  Bind to our local address  */
                    626:     if (bind_send_socket) {
                    627:         if (bind(send_socket, (struct sockaddr *) src_sockaddr,
                    628:                  sizeof(struct sockaddr_in6))) {
                    629:             return -1;
                    630:         }
                    631:     }
                    632: 
                    633:     /*  The traffic class in IPv6 is analagous to ToS in IPv4  */
                    634:     if (setsockopt(send_socket, IPPROTO_IPV6,
                    635:                    IPV6_TCLASS, &param->type_of_service, sizeof(int))) {
                    636:         return -1;
                    637:     }
                    638: 
                    639:     /*  Set the time-to-live  */
                    640:     if (setsockopt(send_socket, IPPROTO_IPV6,
                    641:                    IPV6_UNICAST_HOPS, &param->ttl, sizeof(int))) {
                    642:         return -1;
                    643:     }
                    644: #ifdef SO_MARK
                    645:     if (param->routing_mark) {
                    646:         if (setsockopt(send_socket,
                    647:                        SOL_SOCKET, SO_MARK, &param->routing_mark,
                    648:                        sizeof(int))) {
                    649:             return -1;
                    650:         }
                    651:     }
                    652: #endif
                    653: 
                    654:     return 0;
                    655: }
                    656: 
                    657: /*  Construct a probe packet based on the probe parameters  */
                    658: int construct_packet(
                    659:     const struct net_state_t *net_state,
                    660:     int *packet_socket,
                    661:     int sequence,
                    662:     char *packet_buffer,
                    663:     int packet_buffer_size,
                    664:     const struct sockaddr_storage *dest_sockaddr,
                    665:     const struct sockaddr_storage *src_sockaddr,
                    666:     const struct probe_param_t *param)
                    667: {
                    668:     int packet_size;
                    669: 
                    670:     packet_size = compute_packet_size(net_state, param);
                    671:     if (packet_size < 0) {
                    672:         return -1;
                    673:     }
                    674: 
                    675:     if (packet_buffer_size < packet_size) {
                    676:         errno = EINVAL;
                    677:         return -1;
                    678:     }
                    679: 
                    680:     memset(packet_buffer, param->bit_pattern, packet_size);
                    681: 
                    682:     if (param->ip_version == 6) {
                    683:         if (construct_ip6_packet(net_state, packet_socket, sequence,
                    684:                                  packet_buffer, packet_size,
                    685:                                  src_sockaddr, dest_sockaddr, param)) {
                    686:             return -1;
                    687:         }
                    688:     } else if (param->ip_version == 4) {
                    689:         if (construct_ip4_packet(net_state, packet_socket, sequence,
                    690:                                  packet_buffer, packet_size,
                    691:                                  src_sockaddr, dest_sockaddr, param)) {
                    692:             return -1;
                    693:         }
                    694:     } else {
                    695:         errno = EINVAL;
                    696:         return -1;
                    697:     }
                    698: 
                    699:     return packet_size;
                    700: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>