18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* 28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright (c) 1982, 1986, 1988, 1990, 1993 38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * The Regents of the University of California. All rights reserved. 48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Redistribution and use in source and binary forms, with or without 68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * modification, are permitted provided that the following conditions 78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * are met: 88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 1. Redistributions of source code must retain the above copyright 98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * notice, this list of conditions and the following disclaimer. 108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright 118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * notice, this list of conditions and the following disclaimer in the 128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * documentation and/or other materials provided with the distribution. 135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * 3. Neither the name of the University nor the names of its contributors 148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * may be used to endorse or promote products derived from this software 158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * without specific prior written permission. 168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * SUCH DAMAGE. 288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * ip_output.c,v 1.9 1994/11/16 10:17:10 jkh Exp 318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* 348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Changes and additions relating to SLiRP are 358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright (c) 1995 Danny Gasparovski. 368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * 378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Please read the file COPYRIGHT for the 388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * terms and conditions of the copyright. 398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <slirp.h> 428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectu_int16_t ip_id; 448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* Number of packets queued before we start sending 465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * (to prevent allocing too many mbufs) */ 475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define IF_THRESH 10 485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* 508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * IP output. The packet in mbuf chain m contains a skeletal IP 518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * header (with len, off, ttl, proto, tos, src, dst). 528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * The mbuf chain containing the packet will be freed. 538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * The mbuf opt, if present, will not be freed. 548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint 565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerip_output(struct socket *so, struct mbuf *m0) 578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project register struct ip *ip; 595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner register struct mbuf *m = m0; 608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project register int hlen = sizeof(struct ip ); 618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int len, off, error = 0; 628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_CALL("ip_output"); 648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_ARG("so = %lx", (long)so); 658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project DEBUG_ARG("m0 = %lx", (long)m0); 665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* We do no options */ 688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* if (opt) { 698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * m = ip_insertoptions(m, opt, &len); 708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * hlen = len; 718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * } 728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner ip = mtod(m, struct ip *); 748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* 758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Fill in IP header. 768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_v = IPVERSION; 788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_off &= IP_DF; 798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_id = htons(ip_id++); 808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_hl = hlen >> 2; 815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner STAT(ipstat.ips_localout++); 828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* 848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Verify that we have any chance at all of being able to queue 858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * the packet or packet fragments 868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* XXX Hmmm... */ 885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* if (if_queued > IF_THRESH && towrite <= 0) { 898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * error = ENOBUFS; 908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * goto bad; 918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * } 928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* 958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * If small enough for interface, can just send directly. 968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if ((u_int16_t)ip->ip_len <= IF_MTU) { 988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_len = htons((u_int16_t)ip->ip_len); 998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_off = htons((u_int16_t)ip->ip_off); 1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_sum = 0; 1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_sum = cksum(m, hlen); 1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if_output(so, m); 1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto done; 1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* 1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Too large for interface; fragment if possible. 1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Must be able to put at least 8 bytes per fragment. 1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (ip->ip_off & IP_DF) { 1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project error = -1; 1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner STAT(ipstat.ips_cantfrag++); 1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad; 1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner len = (IF_MTU - hlen) &~ 7; /* ip databytes per packet */ 1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (len < 8) { 1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project error = -1; 1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto bad; 1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int mhlen, firstlen = len; 1255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner struct mbuf **mnext = &m->m_nextpkt; 1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* 1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Loop through length of segment after first fragment, 1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * make new header and copy data of each part and link onto chain. 1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m0 = m; 1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mhlen = sizeof (struct ip); 1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (off = hlen + len; off < (u_int16_t)ip->ip_len; off += len) { 1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project register struct ip *mhip; 1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner m = m_get(); 1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (m == NULL) { 1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project error = -1; 1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner STAT(ipstat.ips_odropped++); 1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto sendorfree; 1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner m->m_data += IF_MAXLINKHDR; 1425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner mhip = mtod(m, struct ip *); 1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *mhip = *ip; 1445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* No options */ 1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* if (hlen > sizeof (struct ip)) { 1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); 1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * mhip->ip_hl = mhlen >> 2; 1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * } 1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m->m_len = mhlen; 1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); 1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (ip->ip_off & IP_MF) 1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mhip->ip_off |= IP_MF; 1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (off + len >= (u_int16_t)ip->ip_len) 1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project len = (u_int16_t)ip->ip_len - off; 1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner else 1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mhip->ip_off |= IP_MF; 1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mhip->ip_len = htons((u_int16_t)(len + mhlen)); 1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner if (m_copy(m, m0, off, len) < 0) { 1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project error = -1; 1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto sendorfree; 1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner 1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mhip->ip_off = htons((u_int16_t)mhip->ip_off); 1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mhip->ip_sum = 0; 1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mhip->ip_sum = cksum(m, mhlen); 1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *mnext = m; 1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project mnext = &m->m_nextpkt; 1715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner STAT(ipstat.ips_ofragments++); 1728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* 1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Update first fragment by trimming what's been copied out 1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * and updating header, then send each fragment (in order). 1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */ 1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m = m0; 1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner m_adj(m, hlen + firstlen - (u_int16_t)ip->ip_len); 1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_len = htons((u_int16_t)m->m_len); 1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_off = htons((u_int16_t)(ip->ip_off | IP_MF)); 1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_sum = 0; 1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project ip->ip_sum = cksum(m, hlen); 1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectsendorfree: 1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for (m = m0; m; m = m0) { 1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project m0 = m->m_nextpkt; 1865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner m->m_nextpkt = NULL; 1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (error == 0) 1888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if_output(so, m); 1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project else 1905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner m_freem(m); 1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (error == 0) 1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner STAT(ipstat.ips_fragmented++); 1958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectdone: 1988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return (error); 1998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 2008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectbad: 2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner m_freem(m0); 2028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto done; 2038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 204