[21580dd] | 1 | /*
|
---|
| 2 | * Copyright (c) 2009 Lukas Mejdrech
|
---|
| 3 | * All rights reserved.
|
---|
| 4 | *
|
---|
| 5 | * Redistribution and use in source and binary forms, with or without
|
---|
| 6 | * modification, are permitted provided that the following conditions
|
---|
| 7 | * are met:
|
---|
| 8 | *
|
---|
| 9 | * - Redistributions of source code must retain the above copyright
|
---|
| 10 | * notice, this list of conditions and the following disclaimer.
|
---|
| 11 | * - Redistributions in binary form must reproduce the above copyright
|
---|
| 12 | * notice, this list of conditions and the following disclaimer in the
|
---|
| 13 | * documentation and/or other materials provided with the distribution.
|
---|
| 14 | * - The name of the author may not be used to endorse or promote products
|
---|
| 15 | * derived from this software without specific prior written permission.
|
---|
| 16 | *
|
---|
| 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
---|
| 18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
---|
| 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
---|
| 20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
---|
| 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
---|
| 22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
---|
| 23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
---|
| 24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
---|
| 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
---|
| 26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
| 27 | */
|
---|
| 28 |
|
---|
| 29 | /** @addtogroup ip
|
---|
| 30 | * @{
|
---|
| 31 | */
|
---|
| 32 |
|
---|
| 33 | /** @file
|
---|
| 34 | * IP client interface implementation.
|
---|
| 35 | * @see ip_client.h
|
---|
| 36 | */
|
---|
| 37 |
|
---|
| 38 | #include <errno.h>
|
---|
| 39 | #include <sys/types.h>
|
---|
| 40 |
|
---|
[849ed54] | 41 | #include <ip_client.h>
|
---|
[0a866eeb] | 42 | #include <packet_client.h>
|
---|
[849ed54] | 43 | #include <ip_header.h>
|
---|
[21580dd] | 44 |
|
---|
[c69d327] | 45 | #include <net/packet.h>
|
---|
[0a866eeb] | 46 |
|
---|
[a64c64d] | 47 | size_t ip_client_header_length(packet_t packet){
|
---|
| 48 | ip_header_ref header;
|
---|
| 49 |
|
---|
| 50 | header = (ip_header_ref) packet_get_data(packet);
|
---|
| 51 | if((! header)
|
---|
| 52 | || (packet_get_data_length(packet) < sizeof(ip_header_t))){
|
---|
| 53 | return 0;
|
---|
| 54 | }
|
---|
| 55 | return IP_HEADER_LENGTH(header);
|
---|
| 56 | }
|
---|
| 57 |
|
---|
[14f1db0] | 58 | int ip_client_get_pseudo_header(ip_protocol_t protocol, struct sockaddr * src, socklen_t srclen, struct sockaddr * dest, socklen_t destlen, size_t data_length, void **header, size_t * headerlen){
|
---|
[a64c64d] | 59 | ipv4_pseudo_header_ref header_in;
|
---|
| 60 | struct sockaddr_in * address_in;
|
---|
| 61 |
|
---|
| 62 | if(!(header && headerlen)){
|
---|
| 63 | return EBADMEM;
|
---|
| 64 | }
|
---|
| 65 | if(!(src && dest && (srclen > 0) && ((size_t) srclen >= sizeof(struct sockaddr)) && (srclen == destlen) && (src->sa_family == dest->sa_family))){
|
---|
| 66 | return EINVAL;
|
---|
| 67 | }
|
---|
| 68 |
|
---|
| 69 | switch(src->sa_family){
|
---|
| 70 | case AF_INET:
|
---|
| 71 | if(srclen != sizeof(struct sockaddr_in)){
|
---|
| 72 | return EINVAL;
|
---|
| 73 | }
|
---|
| 74 | *headerlen = sizeof(*header_in);
|
---|
| 75 | header_in = (ipv4_pseudo_header_ref) malloc(*headerlen);
|
---|
| 76 | if(! header_in){
|
---|
| 77 | return ENOMEM;
|
---|
| 78 | }
|
---|
| 79 | bzero(header_in, * headerlen);
|
---|
| 80 | address_in = (struct sockaddr_in *) dest;
|
---|
| 81 | header_in->destination_address = address_in->sin_addr.s_addr;
|
---|
| 82 | address_in = (struct sockaddr_in *) src;
|
---|
| 83 | header_in->source_address = address_in->sin_addr.s_addr;
|
---|
| 84 | header_in->protocol = protocol;
|
---|
| 85 | header_in->data_length = htons(data_length);
|
---|
[14f1db0] | 86 | *header = header_in;
|
---|
[a64c64d] | 87 | return EOK;
|
---|
| 88 | // TODO IPv6
|
---|
| 89 | /* case AF_INET6:
|
---|
| 90 | if(addrlen != sizeof(struct sockaddr_in6)){
|
---|
| 91 | return EINVAL;
|
---|
| 92 | }
|
---|
| 93 | address_in6 = (struct sockaddr_in6 *) addr;
|
---|
| 94 | return EOK;
|
---|
| 95 | */ default:
|
---|
| 96 | return EAFNOSUPPORT;
|
---|
| 97 | }
|
---|
| 98 | }
|
---|
| 99 |
|
---|
[aadf01e] | 100 | int ip_client_prepare_packet(packet_t packet, ip_protocol_t protocol, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment, size_t ipopt_length){
|
---|
| 101 | ip_header_ref header;
|
---|
| 102 | uint8_t * data;
|
---|
| 103 | size_t padding;
|
---|
[21580dd] | 104 |
|
---|
[a64c64d] | 105 | // compute the padding if IP options are set
|
---|
| 106 | // multiple of 4 bytes
|
---|
[21580dd] | 107 | padding = ipopt_length % 4;
|
---|
[aadf01e] | 108 | if(padding){
|
---|
[21580dd] | 109 | padding = 4 - padding;
|
---|
| 110 | ipopt_length += padding;
|
---|
| 111 | }
|
---|
[a64c64d] | 112 |
|
---|
| 113 | // prefix the header
|
---|
[aadf01e] | 114 | data = (uint8_t *) packet_prefix(packet, sizeof(ip_header_t) + padding);
|
---|
| 115 | if(! data){
|
---|
| 116 | return ENOMEM;
|
---|
| 117 | }
|
---|
[a64c64d] | 118 |
|
---|
| 119 | // add the padding
|
---|
[aadf01e] | 120 | while(padding --){
|
---|
| 121 | data[sizeof(ip_header_t) + padding] = IPOPT_NOOP;
|
---|
| 122 | }
|
---|
[a64c64d] | 123 |
|
---|
| 124 | // set the header
|
---|
[aadf01e] | 125 | header = (ip_header_ref) data;
|
---|
| 126 | header->header_length = IP_COMPUTE_HEADER_LENGTH(sizeof(ip_header_t) + ipopt_length);
|
---|
| 127 | header->ttl = (ttl ? ttl : IPDEFTTL); //(((ttl) <= MAXTTL) ? ttl : MAXTTL) : IPDEFTTL;
|
---|
[21580dd] | 128 | header->tos = tos;
|
---|
| 129 | header->protocol = protocol;
|
---|
[a64c64d] | 130 |
|
---|
[aadf01e] | 131 | if(dont_fragment){
|
---|
| 132 | header->flags = IPFLAG_DONT_FRAGMENT;
|
---|
| 133 | }
|
---|
[21580dd] | 134 | return EOK;
|
---|
| 135 | }
|
---|
| 136 |
|
---|
[aadf01e] | 137 | int ip_client_process_packet(packet_t packet, ip_protocol_t * protocol, ip_ttl_t * ttl, ip_tos_t * tos, int * dont_fragment, size_t * ipopt_length){
|
---|
| 138 | ip_header_ref header;
|
---|
[21580dd] | 139 |
|
---|
[aadf01e] | 140 | header = (ip_header_ref) packet_get_data(packet);
|
---|
| 141 | if((! header)
|
---|
| 142 | || (packet_get_data_length(packet) < sizeof(ip_header_t))){
|
---|
[21580dd] | 143 | return ENOMEM;
|
---|
| 144 | }
|
---|
[a64c64d] | 145 |
|
---|
[aadf01e] | 146 | if(protocol){
|
---|
| 147 | *protocol = header->protocol;
|
---|
| 148 | }
|
---|
| 149 | if(ttl){
|
---|
| 150 | *ttl = header->ttl;
|
---|
| 151 | }
|
---|
| 152 | if(tos){
|
---|
| 153 | *tos = header->tos;
|
---|
| 154 | }
|
---|
| 155 | if(dont_fragment){
|
---|
| 156 | *dont_fragment = header->flags &IPFLAG_DONT_FRAGMENT;
|
---|
| 157 | }
|
---|
| 158 | if(ipopt_length){
|
---|
| 159 | *ipopt_length = IP_HEADER_LENGTH(header) - sizeof(ip_header_t);
|
---|
| 160 | return sizeof(ip_header_t);
|
---|
[21580dd] | 161 | }else{
|
---|
[aadf01e] | 162 | return IP_HEADER_LENGTH(header);
|
---|
[21580dd] | 163 | }
|
---|
| 164 | }
|
---|
| 165 |
|
---|
[14f1db0] | 166 | int ip_client_set_pseudo_header_data_length(void *header, size_t headerlen, size_t data_length){
|
---|
[aadf01e] | 167 | ipv4_pseudo_header_ref header_in;
|
---|
[21580dd] | 168 |
|
---|
[aadf01e] | 169 | if(! header){
|
---|
| 170 | return EBADMEM;
|
---|
| 171 | }
|
---|
[a64c64d] | 172 |
|
---|
[aadf01e] | 173 | if(headerlen == sizeof(ipv4_pseudo_header_t)){
|
---|
| 174 | header_in = (ipv4_pseudo_header_ref) header;
|
---|
| 175 | header_in->data_length = htons(data_length);
|
---|
[21580dd] | 176 | return EOK;
|
---|
[a64c64d] | 177 | // TODO IPv6
|
---|
[21580dd] | 178 | }else{
|
---|
| 179 | return EINVAL;
|
---|
| 180 | }
|
---|
| 181 | }
|
---|
| 182 |
|
---|
| 183 | /** @}
|
---|
| 184 | */
|
---|