File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libnet / src / libnet_build_tcp.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:14:23 2012 UTC (12 years, 5 months ago) by misho
Branches: libnet, MAIN
CVS tags: v1_1_2_1, HEAD
libnet

    1: /*
    2:  *  $Id: libnet_build_tcp.c,v 1.1.1.1 2012/02/21 22:14:23 misho Exp $
    3:  *
    4:  *  libnet
    5:  *  libnet_build_tcp.c - TCP packet assembler
    6:  *
    7:  *  Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
    8:  *  All rights reserved.
    9:  *
   10:  * Redistribution and use in source and binary forms, with or without
   11:  * modification, are permitted provided that the following conditions
   12:  * are met:
   13:  * 1. Redistributions of source code must retain the above copyright
   14:  *    notice, this list of conditions and the following disclaimer.
   15:  * 2. Redistributions in binary form must reproduce the above copyright
   16:  *    notice, this list of conditions and the following disclaimer in the
   17:  *    documentation and/or other materials provided with the distribution.
   18:  *
   19:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   20:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   23:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29:  * SUCH DAMAGE.
   30:  *
   31:  */
   32: 
   33: #if (HAVE_CONFIG_H)
   34: #include "../include/config.h"
   35: #endif
   36: #if (!(_WIN32) || (__CYGWIN__)) 
   37: #include "../include/libnet.h"
   38: #else
   39: #include "../include/win32/libnet.h"
   40: #endif
   41: 
   42: libnet_ptag_t
   43: libnet_build_tcp(u_int16_t sp, u_int16_t dp, u_int32_t seq, u_int32_t ack,
   44: u_int8_t control, u_int16_t win, u_int16_t sum, u_int16_t urg, u_int16_t len,
   45: u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
   46: {
   47:     int n, offset;
   48:     u_int32_t i, j;
   49:     libnet_pblock_t *p, *p_data, *p_temp;
   50:     libnet_ptag_t ptag_hold, ptag_data;
   51:     struct libnet_tcp_hdr tcp_hdr;
   52:     struct libnet_ipv4_hdr *ip_hdr;
   53: 
   54:     if (l == NULL)
   55:     { 
   56:         return (-1);
   57:     } 
   58: 
   59:     ptag_data = 0;                      /* for possible options */
   60: 
   61:     /*
   62:      *  Find the existing protocol block if a ptag is specified, or create
   63:      *  a new one.
   64:      */
   65:     p = libnet_pblock_probe(l, ptag, LIBNET_TCP_H, LIBNET_PBLOCK_TCP_H);
   66:     if (p == NULL)
   67:     {
   68:         return (-1);
   69:     }
   70: 
   71:     memset(&tcp_hdr, 0, sizeof(tcp_hdr));
   72:     tcp_hdr.th_sport   = htons(sp);    /* source port */
   73:     tcp_hdr.th_dport   = htons(dp);    /* destination port */
   74:     tcp_hdr.th_seq     = htonl(seq);   /* sequence number */
   75:     tcp_hdr.th_ack     = htonl(ack);   /* acknowledgement number */
   76:     tcp_hdr.th_flags   = control;      /* control flags */
   77:     tcp_hdr.th_x2      = 0;            /* UNUSED */
   78:     tcp_hdr.th_off     = 5;            /* 20 byte header */
   79: 
   80:     /* check to see if there are TCP options to include */
   81:     if (p->prev)
   82:     {
   83:         p_temp = p->prev;
   84:         while ((p_temp->prev) && (p_temp->type != LIBNET_PBLOCK_TCPO_H))
   85:         {
   86:             p_temp = p_temp->prev;
   87:         }
   88:         if (p_temp->type == LIBNET_PBLOCK_TCPO_H)
   89:         {
   90:             /*
   91:              *  Count up number of 32-bit words in options list, padding if
   92:              *  neccessary.
   93:              */
   94:             for (i = 0, j = 0; i < p_temp->b_len; i++)
   95:             {
   96:                 (i % 4) ? j : j++;
   97:             }
   98:             tcp_hdr.th_off += j;
   99:         }
  100:     }
  101: 
  102:     tcp_hdr.th_win     = htons(win);   /* window size */
  103:     tcp_hdr.th_sum     = (sum ? htons(sum) : 0);   /* checksum */ 
  104:     tcp_hdr.th_urp     = htons(urg);          /* urgent pointer */
  105: 
  106:     n = libnet_pblock_append(l, p, (u_int8_t *)&tcp_hdr, LIBNET_TCP_H);
  107:     if (n == -1)
  108:     {
  109:         goto bad;
  110:     }
  111: 
  112:     ptag_hold = ptag;
  113:     if (ptag == LIBNET_PTAG_INITIALIZER)
  114:     {
  115:         ptag = libnet_pblock_update(l, p, len, LIBNET_PBLOCK_TCP_H);
  116:     }
  117: 
  118:     /* find and set the appropriate ptag, or else use the default of 0 */
  119:     offset = payload_s;
  120:     if (ptag_hold && p->prev)
  121:     {
  122:         p_temp = p->prev;
  123:         while (p_temp->prev &&
  124:               (p_temp->type != LIBNET_PBLOCK_TCPDATA) &&
  125:               (p_temp->type != LIBNET_PBLOCK_TCP_H))
  126:         {
  127:            p_temp = p_temp->prev;
  128:         }
  129: 
  130:         if (p_temp->type == LIBNET_PBLOCK_TCPDATA)
  131:         {
  132:             ptag_data = p_temp->ptag;
  133:             offset -=  p_temp->b_len;
  134:             p->h_len += offset;
  135:         }
  136:         else
  137:         {
  138:             snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  139: 				    "%s(): TCP data pblock not found\n", __func__);
  140:         }
  141:      }
  142: 
  143:     /* update ip_len if present */
  144:     if (ptag_hold && p->next)
  145:     {
  146:         p_temp = p->next;
  147:         while (p_temp->next && (p_temp->type != LIBNET_PBLOCK_IPV4_H))
  148:         {
  149:             p_temp = p_temp->next;
  150:         }
  151:         if (p_temp->type == LIBNET_PBLOCK_IPV4_H)
  152:         {
  153:             ip_hdr = (struct libnet_ipv4_hdr *)p_temp->buf;
  154:             n = ntohs(ip_hdr->ip_len) + offset;
  155:             ip_hdr->ip_len = htons(n);
  156:         }
  157:     }
  158: 
  159:     if ((payload && !payload_s) || (!payload && payload_s))
  160:     {
  161:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  162: 			    "%s(): payload inconsistency\n", __func__);
  163:         goto bad;
  164:     }
  165: 
  166:     /* if there is a payload, add it in the context */
  167:     if (payload && payload_s)
  168:     {
  169:         /* update ptag_data with the new payload */
  170:         p_data = libnet_pblock_probe(l, ptag_data, payload_s,
  171:                 LIBNET_PBLOCK_TCPDATA);
  172:         if (p_data == NULL) 
  173:         {
  174:             return (-1);
  175:         }
  176: 
  177:         if (libnet_pblock_append(l, p_data, payload, payload_s) == -1)
  178:         {
  179:             goto bad;
  180:         }
  181: 
  182:         if (ptag_data == LIBNET_PTAG_INITIALIZER)
  183:         {
  184:             if (p_data->prev->type == LIBNET_PBLOCK_TCP_H)
  185:             {
  186:                 libnet_pblock_update(l, p_data, payload_s,
  187:                         LIBNET_PBLOCK_TCPDATA);
  188:                 /* swap pblocks to correct the protocol order */
  189:                 libnet_pblock_swap(l, p->ptag, p_data->ptag);
  190:             }
  191:             else
  192:             {
  193:                 /* update without setting this as the final pblock */
  194:                 p_data->type  =  LIBNET_PBLOCK_TCPDATA;
  195:                 p_data->ptag  =  ++(l->ptag_state);
  196:                 p_data->h_len =  payload_s;
  197: 
  198:                 /* Adjust h_len for checksum. */
  199:                 p->h_len += payload_s;
  200: 
  201:                 /* data was added after the initial construction */
  202:                 for (p_temp = l->protocol_blocks;
  203:                         p_temp->type == LIBNET_PBLOCK_TCP_H ||
  204:                         p_temp->type == LIBNET_PBLOCK_TCPO_H;
  205:                         p_temp = p_temp->next)
  206:                 {
  207:                     libnet_pblock_insert_before(l, p_temp->ptag, p_data->ptag);
  208:                     break;
  209:                 }
  210:                 /* The end block needs to have its next pointer cleared. */
  211:                 l->pblock_end->next = NULL;
  212:             }
  213: 
  214:             if (p_data->prev && p_data->prev->type == LIBNET_PBLOCK_TCPO_H)
  215:             {
  216:                 libnet_pblock_swap(l, p_data->prev->ptag, p_data->ptag);
  217:             }
  218:         }
  219:     }
  220:     else
  221:     {
  222:         p_data = libnet_pblock_find(l, ptag_data);
  223:         if (p_data) 
  224:         {
  225:             libnet_pblock_delete(l, p_data);
  226:         }
  227:     }
  228: 
  229:     if (sum == 0)
  230:     {
  231:         /*
  232:          *  If checksum is zero, by default libnet will compute a checksum
  233:          *  for the user.  The programmer can override this by calling
  234:          *  libnet_toggle_checksum(l, ptag, 1);
  235:          */
  236:         libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM);
  237:     }
  238:     return (ptag);
  239: bad:
  240:     libnet_pblock_delete(l, p);
  241:     return (-1);
  242: }
  243: 
  244: 
  245: libnet_ptag_t
  246: libnet_build_tcp_options(u_int8_t *options, u_int32_t options_s, libnet_t *l, 
  247: libnet_ptag_t ptag)
  248: {
  249:     int offset, underflow;
  250:     u_int32_t i, j, n, adj_size;
  251:     libnet_pblock_t *p, *p_temp;
  252:     struct libnet_ipv4_hdr *ip_hdr;
  253:     struct libnet_tcp_hdr *tcp_hdr;
  254: 
  255:     if (l == NULL)
  256:     { 
  257:         return (-1);
  258:     }
  259: 
  260:     underflow = 0;
  261:     offset = 0;
  262: 
  263:     /* check options list size */
  264:     if (options_s > LIBNET_MAXOPTION_SIZE)
  265:     {
  266:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  267:             "%s(): options list is too large %d\n", __func__, options_s);
  268:         return (-1);
  269:     }
  270: 
  271:     adj_size = options_s;
  272:     if (adj_size % 4)
  273:     {
  274:         /* size of memory block with padding */
  275:         adj_size += 4 - (options_s % 4);
  276:     }
  277: 
  278:     /* if this pblock already exists, determine if there is a size diff */
  279:     if (ptag)
  280:     {
  281:         p_temp = libnet_pblock_find(l, ptag);
  282:         if (p_temp)
  283:         {
  284:             if (adj_size >= p_temp->b_len)
  285:             {
  286:                 offset = adj_size - p_temp->b_len;
  287:             }
  288:             else
  289:             {
  290:                 offset = p_temp->b_len - adj_size;
  291:                 underflow = 1;
  292:             }
  293:         }
  294:     }
  295: 
  296:     /*
  297:      *  Find the existing protocol block if a ptag is specified, or create
  298:      *  a new one.
  299:      */
  300:     p = libnet_pblock_probe(l, ptag, adj_size, LIBNET_PBLOCK_TCPO_H);
  301:     if (p == NULL)
  302:     {
  303:         return (-1);
  304:     }
  305: 	
  306:     n = libnet_pblock_append(l, p, options, adj_size);
  307:     if (n == -1)
  308:     {
  309:         goto bad;
  310:     }
  311: 	
  312:     if (ptag && p->next)
  313:     {
  314:         p_temp = p->next;
  315:         while ((p_temp->next) && (p_temp->type != LIBNET_PBLOCK_TCP_H))
  316:         {
  317:            p_temp = p_temp->next;
  318:         }
  319:         if (p_temp->type == LIBNET_PBLOCK_TCP_H)
  320:         {
  321:             /*
  322:              *  Count up number of 32-bit words in options list, padding if
  323:              *  neccessary.
  324:              */
  325:             for (i = 0, j = 0; i < p->b_len; i++)
  326:             {
  327:                 (i % 4) ? j : j++;
  328:             }
  329:             tcp_hdr = (struct libnet_tcp_hdr *)p_temp->buf;
  330:             tcp_hdr->th_off = j + 5;
  331:             if (!underflow)
  332:             {
  333:                 p_temp->h_len += offset;
  334:             }
  335:             else
  336:             {
  337:                 p_temp->h_len -= offset;
  338:             }
  339:         }
  340:         while ((p_temp->next) && (p_temp->type != LIBNET_PBLOCK_IPV4_H))
  341:         {
  342:             p_temp = p_temp->next;
  343:         }
  344:         if (p_temp->type == LIBNET_PBLOCK_IPV4_H)
  345:         {
  346:             ip_hdr = (struct libnet_ipv4_hdr *)p_temp->buf;
  347:             if (!underflow)
  348:             {
  349:                 ip_hdr->ip_len += htons(offset);
  350:             }
  351:             else
  352:             {
  353:                 ip_hdr->ip_len -= htons(offset);
  354:             }
  355:         }
  356:     }
  357: 
  358:     return (ptag ? ptag : libnet_pblock_update(l, p, adj_size,
  359:             LIBNET_PBLOCK_TCPO_H));
  360: bad:
  361:     libnet_pblock_delete(l, p);
  362:     return (-1);
  363: }
  364: 
  365: /* EOF */

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