1993-04-09 16:00:07 +04:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 1991 The Regents of the University of California.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by the University of
|
|
|
|
* California, Berkeley and its contributors.
|
|
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
1993-05-20 09:26:42 +04:00
|
|
|
* from: @(#)tp_inet.c 7.8 (Berkeley) 5/6/91
|
|
|
|
* $Id: tp_inet.c,v 1.2 1993/05/20 05:27:38 cgd Exp $
|
1993-04-09 16:00:07 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
/***********************************************************
|
|
|
|
Copyright IBM Corporation 1987
|
|
|
|
|
|
|
|
All Rights Reserved
|
|
|
|
|
|
|
|
Permission to use, copy, modify, and distribute this software and its
|
|
|
|
documentation for any purpose and without fee is hereby granted,
|
|
|
|
provided that the above copyright notice appear in all copies and that
|
|
|
|
both that copyright notice and this permission notice appear in
|
|
|
|
supporting documentation, and that the name of IBM not be
|
|
|
|
used in advertising or publicity pertaining to distribution of the
|
|
|
|
software without specific, written prior permission.
|
|
|
|
|
|
|
|
IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
|
|
|
|
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
|
|
|
|
IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
|
|
|
|
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
|
|
|
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
|
|
|
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
|
|
|
SOFTWARE.
|
|
|
|
|
|
|
|
******************************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* ARGO TP
|
|
|
|
*
|
|
|
|
* Here is where you find the inet-dependent code. We've tried
|
|
|
|
* keep all net-level and (primarily) address-family-dependent stuff
|
|
|
|
* out of the tp source, and everthing here is reached indirectly
|
|
|
|
* through a switch table (struct nl_protosw *) tpcb->tp_nlproto
|
|
|
|
* (see tp_pcb.c).
|
|
|
|
* The routines here are:
|
|
|
|
* in_getsufx: gets transport suffix out of an inpcb structure.
|
|
|
|
* in_putsufx: put transport suffix into an inpcb structure.
|
|
|
|
* in_putnetaddr: put a whole net addr into an inpcb.
|
|
|
|
* in_getnetaddr: get a whole net addr from an inpcb.
|
|
|
|
* in_cmpnetaddr: compare a whole net addr from an isopcb.
|
|
|
|
* in_recycle_suffix: clear suffix for reuse in inpcb
|
|
|
|
* tpip_mtu: figure out what size tpdu to use
|
|
|
|
* tpip_input: take a pkt from ip, strip off its ip header, give to tp
|
|
|
|
* tpip_output_dg: package a pkt for ip given 2 addresses & some data
|
|
|
|
* tpip_output: package a pkt for ip given an inpcb & some data
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef INET
|
|
|
|
|
|
|
|
#include "param.h"
|
|
|
|
#include "socket.h"
|
|
|
|
#include "socketvar.h"
|
|
|
|
#include "mbuf.h"
|
|
|
|
#include "errno.h"
|
|
|
|
#include "time.h"
|
|
|
|
#include "../net/if.h"
|
|
|
|
#include "tp_param.h"
|
|
|
|
#include "argo_debug.h"
|
|
|
|
#include "tp_stat.h"
|
|
|
|
#include "tp_ip.h"
|
|
|
|
#include "tp_pcb.h"
|
|
|
|
#include "tp_trace.h"
|
|
|
|
#include "tp_stat.h"
|
|
|
|
#include "tp_tpdu.h"
|
|
|
|
#include "../netinet/in_var.h"
|
|
|
|
|
|
|
|
#ifndef ISO
|
|
|
|
#include "iso_chksum.c"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NAME: in_getsufx()
|
|
|
|
|
|
|
|
* CALLED FROM: pr_usrreq() on PRU_BIND,
|
|
|
|
* PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR
|
|
|
|
*
|
|
|
|
* FUNCTION, ARGUMENTS, and RETURN VALUE:
|
|
|
|
* Get a transport suffix from an inpcb structure (inp).
|
|
|
|
* The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
|
|
|
|
*
|
|
|
|
* RETURNS: internet port / transport suffix
|
|
|
|
* (CAST TO AN INT)
|
|
|
|
*
|
|
|
|
* SIDE EFFECTS:
|
|
|
|
*
|
|
|
|
* NOTES:
|
|
|
|
*/
|
|
|
|
in_getsufx(inp, lenp, data_out, which)
|
|
|
|
struct inpcb *inp;
|
|
|
|
u_short *lenp;
|
|
|
|
caddr_t data_out;
|
|
|
|
int which;
|
|
|
|
{
|
|
|
|
*lenp = sizeof(u_short);
|
|
|
|
switch (which) {
|
|
|
|
case TP_LOCAL:
|
|
|
|
*(u_short *)data_out = inp->inp_lport;
|
|
|
|
return;
|
|
|
|
|
|
|
|
case TP_FOREIGN:
|
|
|
|
*(u_short *)data_out = inp->inp_fport;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NAME: in_putsufx()
|
|
|
|
*
|
|
|
|
* CALLED FROM: tp_newsocket(); i.e., when a connection
|
|
|
|
* is being established by an incoming CR_TPDU.
|
|
|
|
*
|
|
|
|
* FUNCTION, ARGUMENTS:
|
|
|
|
* Put a transport suffix (found in name) into an inpcb structure (inp).
|
|
|
|
* The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
|
|
|
|
*
|
|
|
|
* RETURNS: Nada
|
|
|
|
*
|
|
|
|
* SIDE EFFECTS:
|
|
|
|
*
|
|
|
|
* NOTES:
|
|
|
|
*/
|
|
|
|
/*ARGSUSED*/
|
|
|
|
void
|
|
|
|
in_putsufx(inp, sufxloc, sufxlen, which)
|
|
|
|
struct inpcb *inp;
|
|
|
|
caddr_t sufxloc;
|
|
|
|
int which;
|
|
|
|
{
|
|
|
|
if (which == TP_FOREIGN) {
|
|
|
|
bcopy(sufxloc, (caddr_t)&inp->inp_fport, sizeof(inp->inp_fport));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NAME: in_recycle_tsuffix()
|
|
|
|
*
|
|
|
|
* CALLED FROM: tp.trans whenever we go into REFWAIT state.
|
|
|
|
*
|
|
|
|
* FUNCTION and ARGUMENT:
|
|
|
|
* Called when a ref is frozen, to allow the suffix to be reused.
|
|
|
|
* (inp) is the net level pcb.
|
|
|
|
*
|
|
|
|
* RETURNS: Nada
|
|
|
|
*
|
|
|
|
* SIDE EFFECTS:
|
|
|
|
*
|
|
|
|
* NOTES: This really shouldn't have to be done in a NET level pcb
|
|
|
|
* but... for the internet world that just the way it is done in BSD...
|
|
|
|
* The alternative is to have the port unusable until the reference
|
|
|
|
* timer goes off.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
in_recycle_tsuffix(inp)
|
|
|
|
struct inpcb *inp;
|
|
|
|
{
|
|
|
|
inp->inp_fport = inp->inp_lport = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NAME: in_putnetaddr()
|
|
|
|
*
|
|
|
|
* CALLED FROM:
|
|
|
|
* tp_newsocket(); i.e., when a connection is being established by an
|
|
|
|
* incoming CR_TPDU.
|
|
|
|
*
|
|
|
|
* FUNCTION and ARGUMENTS:
|
|
|
|
* Copy a whole net addr from a struct sockaddr (name).
|
|
|
|
* into an inpcb (inp).
|
|
|
|
* The argument (which) takes values TP_LOCAL or TP_FOREIGN
|
|
|
|
*
|
|
|
|
* RETURNS: Nada
|
|
|
|
*
|
|
|
|
* SIDE EFFECTS:
|
|
|
|
*
|
|
|
|
* NOTES:
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
in_putnetaddr(inp, name, which)
|
|
|
|
register struct inpcb *inp;
|
|
|
|
struct sockaddr_in *name;
|
|
|
|
int which;
|
|
|
|
{
|
|
|
|
switch (which) {
|
|
|
|
case TP_LOCAL:
|
|
|
|
bcopy((caddr_t)&name->sin_addr,
|
|
|
|
(caddr_t)&inp->inp_laddr, sizeof(struct in_addr));
|
|
|
|
/* won't work if the dst address (name) is INADDR_ANY */
|
|
|
|
|
|
|
|
break;
|
|
|
|
case TP_FOREIGN:
|
|
|
|
if( name != (struct sockaddr_in *)0 ) {
|
|
|
|
bcopy((caddr_t)&name->sin_addr,
|
|
|
|
(caddr_t)&inp->inp_faddr, sizeof(struct in_addr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NAME: in_putnetaddr()
|
|
|
|
*
|
|
|
|
* CALLED FROM:
|
|
|
|
* tp_input() when a connection is being established by an
|
|
|
|
* incoming CR_TPDU, and considered for interception.
|
|
|
|
*
|
|
|
|
* FUNCTION and ARGUMENTS:
|
|
|
|
* Compare a whole net addr from a struct sockaddr (name),
|
|
|
|
* with that implicitly stored in an inpcb (inp).
|
|
|
|
* The argument (which) takes values TP_LOCAL or TP_FOREIGN
|
|
|
|
*
|
|
|
|
* RETURNS: Nada
|
|
|
|
*
|
|
|
|
* SIDE EFFECTS:
|
|
|
|
*
|
|
|
|
* NOTES:
|
|
|
|
*/
|
|
|
|
in_cmpnetaddr(inp, name, which)
|
|
|
|
register struct inpcb *inp;
|
|
|
|
register struct sockaddr_in *name;
|
|
|
|
int which;
|
|
|
|
{
|
|
|
|
if (which == TP_LOCAL) {
|
|
|
|
if (name->sin_port && name->sin_port != inp->inp_lport)
|
|
|
|
return 0;
|
|
|
|
return (name->sin_addr.s_addr == inp->inp_laddr.s_addr);
|
|
|
|
}
|
|
|
|
if (name->sin_port && name->sin_port != inp->inp_fport)
|
|
|
|
return 0;
|
|
|
|
return (name->sin_addr.s_addr == inp->inp_faddr.s_addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NAME: in_getnetaddr()
|
|
|
|
*
|
|
|
|
* CALLED FROM:
|
|
|
|
* pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
|
|
|
|
* FUNCTION and ARGUMENTS:
|
|
|
|
* Copy a whole net addr from an inpcb (inp) into
|
|
|
|
* an mbuf (name);
|
|
|
|
* The argument (which) takes values TP_LOCAL or TP_FOREIGN.
|
|
|
|
*
|
|
|
|
* RETURNS: Nada
|
|
|
|
*
|
|
|
|
* SIDE EFFECTS:
|
|
|
|
*
|
|
|
|
* NOTES:
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
in_getnetaddr( inp, name, which)
|
|
|
|
register struct mbuf *name;
|
|
|
|
struct inpcb *inp;
|
|
|
|
int which;
|
|
|
|
{
|
|
|
|
register struct sockaddr_in *sin = mtod(name, struct sockaddr_in *);
|
|
|
|
bzero((caddr_t)sin, sizeof(*sin));
|
|
|
|
switch (which) {
|
|
|
|
case TP_LOCAL:
|
|
|
|
sin->sin_addr = inp->inp_laddr;
|
|
|
|
sin->sin_port = inp->inp_lport;
|
|
|
|
break;
|
|
|
|
case TP_FOREIGN:
|
|
|
|
sin->sin_addr = inp->inp_faddr;
|
|
|
|
sin->sin_port = inp->inp_fport;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
name->m_len = sin->sin_len = sizeof (*sin);
|
|
|
|
sin->sin_family = AF_INET;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NAME: tpip_mtu()
|
|
|
|
*
|
|
|
|
* CALLED FROM:
|
|
|
|
* tp_input() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
|
|
|
|
*
|
|
|
|
* FUNCTION, ARGUMENTS, and RETURN VALUE:
|
|
|
|
*
|
|
|
|
* Determine the proper maximum transmission unit, i.e., MTU, to use, given
|
|
|
|
* a) the header size for the network protocol and the max transmission
|
|
|
|
* unit on the subnet interface, determined from the information in (inp),
|
|
|
|
* b) the max size negotiated so far (negot)
|
|
|
|
* c) the window size used by the tp connection (found in so),
|
|
|
|
*
|
|
|
|
* The result is put in the integer *size in its integer form and in
|
|
|
|
* *negot in its logarithmic form.
|
|
|
|
*
|
|
|
|
* The rules are:
|
|
|
|
* a) can only negotiate down from the value found in *negot.
|
|
|
|
* b) the MTU must be < the windowsize,
|
|
|
|
* c) If src and dest are on the same net,
|
|
|
|
* we will negotiate the closest size larger than MTU but really USE
|
|
|
|
* the actual device mtu - ll hdr sizes.
|
|
|
|
* otherwise we negotiate the closest size smaller than MTU - ll hdr sizes.
|
|
|
|
*
|
|
|
|
* SIDE EFFECTS:
|
|
|
|
* changes the values addressed by the arguments (size) and (negot)
|
|
|
|
* and
|
|
|
|
* when the peer is not on one of our directly connected subnets, it
|
|
|
|
* looks up a route, leaving the route in the inpcb addressed by (inp)
|
|
|
|
*
|
|
|
|
* NOTES:
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
tpip_mtu(so, inp, size, negot)
|
|
|
|
struct socket *so;
|
|
|
|
struct inpcb *inp;
|
|
|
|
int *size;
|
|
|
|
u_char *negot;
|
|
|
|
{
|
|
|
|
register struct ifnet *ifp;
|
|
|
|
struct ifnet *tpip_route();
|
|
|
|
struct in_ifaddr *ia;
|
|
|
|
register int i;
|
|
|
|
int windowsize = so->so_rcv.sb_hiwat;
|
|
|
|
|
|
|
|
IFDEBUG(D_CONN)
|
|
|
|
printf("tpip_mtu(0x%x,0x%x,0x%x,0x%x)\n",
|
|
|
|
so, inp, size, negot);
|
|
|
|
printf("tpip_mtu routing to addr 0x%x\n", inp->inp_faddr);
|
|
|
|
ENDDEBUG
|
|
|
|
IFTRACE(D_CONN)
|
|
|
|
tptrace(TPPTmisc, "ENTER GET MTU: size negot \n",*size, *negot, 0, 0);
|
|
|
|
ENDTRACE
|
|
|
|
|
|
|
|
*size = 1 << *negot;
|
|
|
|
|
|
|
|
if( *size > windowsize ) {
|
|
|
|
*size = windowsize;
|
|
|
|
}
|
|
|
|
|
|
|
|
ia = in_iaonnetof(in_netof(inp->inp_faddr));
|
|
|
|
if ( ia == (struct in_ifaddr *)0 ) {
|
|
|
|
ifp = tpip_route(&inp->inp_faddr);
|
|
|
|
if( ifp == (struct ifnet *)0 )
|
|
|
|
return ;
|
|
|
|
} else
|
|
|
|
ifp = ia->ia_ifp;
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************
|
|
|
|
* TODO - make this indirect off the socket structure to the
|
|
|
|
* network layer to get headersize
|
|
|
|
* After all, who knows what lies below the IP layer?
|
|
|
|
* Who knows how big the NL header will be?
|
|
|
|
***************************************************************/
|
|
|
|
|
|
|
|
if( *size > ifp->if_mtu - sizeof(struct ip)) {
|
|
|
|
*size = ifp->if_mtu - sizeof(struct ip);
|
|
|
|
}
|
|
|
|
for(i=TP_MIN_TPDUSIZE; (i<TP_MAX_TPDUSIZE && ((1<<i)<*size)) ; i++)
|
|
|
|
;
|
|
|
|
i--;
|
|
|
|
|
|
|
|
if (in_netof(inp->inp_laddr) != in_netof(inp->inp_faddr)) {
|
|
|
|
i++;
|
|
|
|
} else {
|
|
|
|
*size = 1<<i;
|
|
|
|
}
|
|
|
|
*negot = i;
|
|
|
|
|
|
|
|
IFDEBUG(D_CONN)
|
|
|
|
printf("GET MTU RETURNS: ifp %s size 0x%x negot 0x%x\n",
|
|
|
|
ifp->if_name, *size, *negot);
|
|
|
|
ENDDEBUG
|
|
|
|
IFTRACE(D_CONN)
|
|
|
|
tptrace(TPPTmisc, "EXIT GET MTU: tpcb size negot \n",
|
|
|
|
*size, *negot, 0, 0);
|
|
|
|
ENDTRACE
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NAME: tpip_output()
|
|
|
|
*
|
|
|
|
* CALLED FROM: tp_emit()
|
|
|
|
*
|
|
|
|
* FUNCTION and ARGUMENTS:
|
|
|
|
* Take a packet(m0) from tp and package it so that ip will accept it.
|
|
|
|
* This means prepending space for the ip header and filling in a few
|
|
|
|
* of the fields.
|
|
|
|
* inp is the inpcb structure; datalen is the length of the data in the
|
|
|
|
* mbuf string m0.
|
|
|
|
* RETURNS:
|
|
|
|
* whatever (E*) is returned form the net layer output routine.
|
|
|
|
*
|
|
|
|
* SIDE EFFECTS:
|
|
|
|
*
|
|
|
|
* NOTES:
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
tpip_output(inp, m0, datalen, nochksum)
|
|
|
|
struct inpcb *inp;
|
|
|
|
struct mbuf *m0;
|
|
|
|
int datalen;
|
|
|
|
int nochksum;
|
|
|
|
{
|
|
|
|
return tpip_output_dg( &inp->inp_laddr, &inp->inp_faddr, m0, datalen,
|
|
|
|
&inp->inp_route, nochksum);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NAME: tpip_output_dg()
|
|
|
|
*
|
|
|
|
* CALLED FROM: tp_error_emit()
|
|
|
|
*
|
|
|
|
* FUNCTION and ARGUMENTS:
|
|
|
|
* This is a copy of tpip_output that takes the addresses
|
|
|
|
* instead of a pcb. It's used by the tp_error_emit, when we
|
|
|
|
* don't have an in_pcb with which to call the normal output rtn.
|
|
|
|
*
|
|
|
|
* RETURNS: ENOBUFS or whatever (E*) is
|
|
|
|
* returned form the net layer output routine.
|
|
|
|
*
|
|
|
|
* SIDE EFFECTS:
|
|
|
|
*
|
|
|
|
* NOTES:
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*ARGSUSED*/
|
|
|
|
int
|
|
|
|
tpip_output_dg(laddr, faddr, m0, datalen, ro, nochksum)
|
|
|
|
struct in_addr *laddr, *faddr;
|
|
|
|
struct mbuf *m0;
|
|
|
|
int datalen;
|
|
|
|
struct route *ro;
|
|
|
|
int nochksum;
|
|
|
|
{
|
|
|
|
register struct mbuf *m;
|
|
|
|
register struct ip *ip;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
IFDEBUG(D_EMIT)
|
|
|
|
printf("tpip_output_dg datalen 0x%x m0 0x%x\n", datalen, m0);
|
|
|
|
ENDDEBUG
|
|
|
|
|
|
|
|
|
|
|
|
MGETHDR(m, M_DONTWAIT, TPMT_IPHDR);
|
|
|
|
if (m == 0) {
|
|
|
|
error = ENOBUFS;
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
m->m_next = m0;
|
|
|
|
MH_ALIGN(m, sizeof(struct ip));
|
|
|
|
m->m_len = sizeof(struct ip);
|
|
|
|
|
|
|
|
ip = mtod(m, struct ip *);
|
|
|
|
bzero((caddr_t)ip, sizeof *ip);
|
|
|
|
|
|
|
|
ip->ip_p = IPPROTO_TP;
|
|
|
|
m->m_pkthdr.len = ip->ip_len = sizeof(struct ip) + datalen;
|
|
|
|
ip->ip_ttl = MAXTTL;
|
|
|
|
/* don't know why you need to set ttl;
|
|
|
|
* overlay doesn't even make this available
|
|
|
|
*/
|
|
|
|
|
|
|
|
ip->ip_src = *laddr;
|
|
|
|
ip->ip_dst = *faddr;
|
|
|
|
|
|
|
|
IncStat(ts_tpdu_sent);
|
|
|
|
IFDEBUG(D_EMIT)
|
|
|
|
dump_mbuf(m, "tpip_output_dg before ip_output\n");
|
|
|
|
ENDDEBUG
|
|
|
|
|
|
|
|
error = ip_output(m, (struct mbuf *)0, ro, IP_ALLOWBROADCAST);
|
|
|
|
|
|
|
|
IFDEBUG(D_EMIT)
|
|
|
|
printf("tpip_output_dg after ip_output\n");
|
|
|
|
ENDDEBUG
|
|
|
|
|
|
|
|
return error;
|
|
|
|
|
|
|
|
bad:
|
|
|
|
m_freem(m);
|
|
|
|
IncStat(ts_send_drop);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NAME: tpip_input()
|
|
|
|
*
|
|
|
|
* CALLED FROM:
|
|
|
|
* ip's input routine, indirectly through the protosw.
|
|
|
|
*
|
|
|
|
* FUNCTION and ARGUMENTS:
|
|
|
|
* Take a packet (m) from ip, strip off the ip header and give it to tp
|
|
|
|
*
|
|
|
|
* RETURNS: No return value.
|
|
|
|
*
|
|
|
|
* SIDE EFFECTS:
|
|
|
|
*
|
|
|
|
* NOTES:
|
|
|
|
*/
|
|
|
|
ProtoHook
|
|
|
|
tpip_input(m, iplen)
|
|
|
|
struct mbuf *m;
|
|
|
|
int iplen;
|
|
|
|
{
|
|
|
|
struct sockaddr_in src, dst;
|
|
|
|
register struct ip *ip;
|
|
|
|
int s = splnet(), hdrlen;
|
|
|
|
|
|
|
|
IncStat(ts_pkt_rcvd);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* IP layer has already pulled up the IP header,
|
|
|
|
* but the first byte after the IP header may not be there,
|
|
|
|
* e.g. if you came in via loopback, so you have to do an
|
|
|
|
* m_pullup to before you can even look to see how much you
|
|
|
|
* really need. The good news is that m_pullup will round
|
|
|
|
* up to almost the next mbuf's worth.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
if((m = m_pullup(m, iplen + 1)) == MNULL)
|
|
|
|
goto discard;
|
|
|
|
CHANGE_MTYPE(m, TPMT_DATA);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now pull up the whole tp header:
|
|
|
|
* Unfortunately, there may be IP options to skip past so we
|
|
|
|
* just fetch it as an unsigned char.
|
|
|
|
*/
|
|
|
|
hdrlen = iplen + 1 + mtod(m, u_char *)[iplen];
|
|
|
|
|
|
|
|
if( m->m_len < hdrlen ) {
|
|
|
|
if((m = m_pullup(m, hdrlen)) == MNULL){
|
|
|
|
IFDEBUG(D_TPINPUT)
|
|
|
|
printf("tp_input, pullup 2!\n");
|
|
|
|
ENDDEBUG
|
|
|
|
goto discard;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* cannot use tp_inputprep() here 'cause you don't
|
|
|
|
* have quite the same situation
|
|
|
|
*/
|
|
|
|
|
|
|
|
IFDEBUG(D_TPINPUT)
|
|
|
|
dump_mbuf(m, "after tpip_input both pullups");
|
|
|
|
ENDDEBUG
|
|
|
|
/*
|
|
|
|
* m_pullup may have returned a different mbuf
|
|
|
|
*/
|
|
|
|
ip = mtod(m, struct ip *);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* drop the ip header from the front of the mbuf
|
|
|
|
* this is necessary for the tp checksum
|
|
|
|
*/
|
|
|
|
m->m_len -= iplen;
|
|
|
|
m->m_data += iplen;
|
|
|
|
|
|
|
|
src.sin_addr = *(struct in_addr *)&(ip->ip_src);
|
|
|
|
src.sin_family = AF_INET;
|
|
|
|
src.sin_len = sizeof(src);
|
|
|
|
dst.sin_addr = *(struct in_addr *)&(ip->ip_dst);
|
|
|
|
dst.sin_family = AF_INET;
|
|
|
|
dst.sin_len = sizeof(dst);
|
|
|
|
|
|
|
|
(void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst,
|
|
|
|
0, tpip_output_dg, 0);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
discard:
|
|
|
|
IFDEBUG(D_TPINPUT)
|
|
|
|
printf("tpip_input DISCARD\n");
|
|
|
|
ENDDEBUG
|
|
|
|
IFTRACE(D_TPINPUT)
|
|
|
|
tptrace(TPPTmisc, "tpip_input DISCARD m", m,0,0,0);
|
|
|
|
ENDTRACE
|
|
|
|
m_freem(m);
|
|
|
|
IncStat(ts_recv_drop);
|
|
|
|
splx(s);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#include "protosw.h"
|
|
|
|
#include "../netinet/ip_icmp.h"
|
|
|
|
|
|
|
|
extern void tp_quench();
|
|
|
|
/*
|
|
|
|
* NAME: tpin_quench()
|
|
|
|
*
|
|
|
|
* CALLED FROM: tpip_ctlinput()
|
|
|
|
*
|
|
|
|
* FUNCTION and ARGUMENTS: find the tpcb pointer and pass it to tp_quench
|
|
|
|
*
|
|
|
|
* RETURNS: Nada
|
|
|
|
*
|
|
|
|
* SIDE EFFECTS:
|
|
|
|
*
|
|
|
|
* NOTES:
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
tpin_quench(inp)
|
|
|
|
struct inpcb *inp;
|
|
|
|
{
|
|
|
|
tp_quench((struct tp_pcb *)inp->inp_socket->so_tpcb, PRC_QUENCH);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NAME: tpip_ctlinput()
|
|
|
|
*
|
|
|
|
* CALLED FROM:
|
|
|
|
* The network layer through the protosw table.
|
|
|
|
*
|
|
|
|
* FUNCTION and ARGUMENTS:
|
|
|
|
* When clnp gets an ICMP msg this gets called.
|
|
|
|
* It either returns an error status to the user or
|
|
|
|
* causes all connections on this address to be aborted
|
|
|
|
* by calling the appropriate xx_notify() routine.
|
|
|
|
* (cmd) is the type of ICMP error.
|
|
|
|
* (sa) the address of the sender
|
|
|
|
*
|
|
|
|
* RETURNS: Nothing
|
|
|
|
*
|
|
|
|
* SIDE EFFECTS:
|
|
|
|
*
|
|
|
|
* NOTES:
|
|
|
|
*/
|
|
|
|
ProtoHook
|
|
|
|
tpip_ctlinput(cmd, sin)
|
|
|
|
int cmd;
|
|
|
|
struct sockaddr_in *sin;
|
|
|
|
{
|
|
|
|
extern u_char inetctlerrmap[];
|
|
|
|
extern ProtoHook tpin_abort();
|
|
|
|
extern ProtoHook in_rtchange();
|
|
|
|
extern struct in_addr zeroin_addr;
|
|
|
|
|
|
|
|
if (sin->sin_family != AF_INET && sin->sin_family != AF_IMPLINK)
|
|
|
|
return 0;
|
|
|
|
if (sin->sin_addr.s_addr == INADDR_ANY)
|
|
|
|
return 0;
|
|
|
|
if (cmd < 0 || cmd > PRC_NCMDS)
|
|
|
|
return 0;
|
|
|
|
switch (cmd) {
|
|
|
|
|
|
|
|
case PRC_QUENCH:
|
|
|
|
in_pcbnotify(&tp_inpcb, sin, 0,
|
|
|
|
zeroin_addr, 0, cmd, (int (*)())tp_quench);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PRC_ROUTEDEAD:
|
|
|
|
case PRC_HOSTUNREACH:
|
|
|
|
case PRC_UNREACH_NET:
|
|
|
|
case PRC_IFDOWN:
|
|
|
|
case PRC_HOSTDEAD:
|
|
|
|
in_pcbnotify(&tp_inpcb, sin, 0,
|
|
|
|
zeroin_addr, 0, cmd, in_rtchange);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/*
|
|
|
|
case PRC_MSGSIZE:
|
|
|
|
case PRC_UNREACH_HOST:
|
|
|
|
case PRC_UNREACH_PROTOCOL:
|
|
|
|
case PRC_UNREACH_PORT:
|
|
|
|
case PRC_UNREACH_NEEDFRAG:
|
|
|
|
case PRC_UNREACH_SRCFAIL:
|
|
|
|
case PRC_REDIRECT_NET:
|
|
|
|
case PRC_REDIRECT_HOST:
|
|
|
|
case PRC_REDIRECT_TOSNET:
|
|
|
|
case PRC_REDIRECT_TOSHOST:
|
|
|
|
case PRC_TIMXCEED_INTRANS:
|
|
|
|
case PRC_TIMXCEED_REASS:
|
|
|
|
case PRC_PARAMPROB:
|
|
|
|
*/
|
|
|
|
in_pcbnotify(&tp_inpcb, sin, 0, zeroin_addr, 0,
|
|
|
|
cmd, tpin_abort);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NAME: tpin_abort()
|
|
|
|
*
|
|
|
|
* CALLED FROM:
|
|
|
|
* xxx_notify() from tp_ctlinput() when
|
|
|
|
* net level gets some ICMP-equiv. type event.
|
|
|
|
*
|
|
|
|
* FUNCTION and ARGUMENTS:
|
|
|
|
* Cause the connection to be aborted with some sort of error
|
|
|
|
* reason indicating that the network layer caused the abort.
|
|
|
|
* Fakes an ER TPDU so we can go through the driver.
|
|
|
|
*
|
|
|
|
* RETURNS: Nothing
|
|
|
|
*
|
|
|
|
* SIDE EFFECTS:
|
|
|
|
*
|
|
|
|
* NOTES:
|
|
|
|
*/
|
|
|
|
|
|
|
|
ProtoHook
|
|
|
|
tpin_abort(inp)
|
|
|
|
struct inpcb *inp;
|
|
|
|
{
|
|
|
|
struct tp_event e;
|
|
|
|
|
|
|
|
e.ev_number = ER_TPDU;
|
|
|
|
e.ATTR(ER_TPDU).e_reason = ENETRESET;
|
|
|
|
(void) tp_driver((struct tp_pcb *)inp->inp_ppcb, &e);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ARGO_DEBUG
|
|
|
|
dump_inaddr(addr)
|
|
|
|
register struct sockaddr_in *addr;
|
|
|
|
{
|
|
|
|
printf("INET: port 0x%x; addr 0x%x\n", addr->sin_port, addr->sin_addr);
|
|
|
|
}
|
|
|
|
#endif ARGO_DEBUG
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NAME: tpip_route()
|
|
|
|
*
|
|
|
|
* CALLED FROM: tpip_mtu()
|
|
|
|
*
|
|
|
|
* FUNCTION and ARGUMENTS: given a destination addresss,
|
|
|
|
* find the interface that would be used to send something to this address.
|
|
|
|
*
|
|
|
|
* RETURNS: pointer to an ifnet structure
|
|
|
|
*
|
|
|
|
* SIDE EFFECTS:
|
|
|
|
*
|
|
|
|
* NOTES:
|
|
|
|
*/
|
|
|
|
struct ifnet *
|
|
|
|
tpip_route(dst)
|
|
|
|
struct in_addr *dst;
|
|
|
|
{
|
|
|
|
struct ifnet *ifp = (struct ifnet *)0;
|
|
|
|
struct sockaddr_in insock;
|
|
|
|
struct sockaddr_in *sin = &insock;
|
|
|
|
struct rtentry *rt;
|
|
|
|
struct ifaddr *ia;
|
|
|
|
|
|
|
|
IFDEBUG(D_CONN)
|
|
|
|
printf("tpip_route: dst is x%x\n", *dst);
|
|
|
|
ENDDEBUG
|
|
|
|
|
|
|
|
bzero((caddr_t)sin, sizeof (*sin));
|
|
|
|
sin->sin_family = AF_INET;
|
|
|
|
sin->sin_len = sizeof(*sin);
|
|
|
|
sin->sin_addr = *dst;
|
|
|
|
|
|
|
|
ia = ifa_ifwithdstaddr((struct sockaddr *)sin);
|
|
|
|
if (ia == 0)
|
|
|
|
ia = ifa_ifwithnet((struct sockaddr *)sin);
|
|
|
|
if (ia != 0) {
|
|
|
|
ifp = ia->ifa_ifp;
|
|
|
|
IFDEBUG(D_CONN)
|
|
|
|
printf("tpip_route: ifp from ia:0x%x\n", ia);
|
|
|
|
ENDDEBUG
|
|
|
|
} else {
|
|
|
|
rt = rtalloc1((struct sockaddr *)sin, 0);
|
|
|
|
if (rt != 0) {
|
|
|
|
ifp = rt->rt_ifp;
|
|
|
|
IFDEBUG(D_CONN)
|
|
|
|
printf("tpip_route: ifp from rentry: 0x%x\n", rt);
|
|
|
|
ENDDEBUG
|
|
|
|
rtfree(rt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
IFDEBUG(D_CONN)
|
|
|
|
printf("tpip_route: returning 0x%x\n", ifp);
|
|
|
|
if (ifp)
|
|
|
|
printf("tpip_route: if name %s unit 0x%x, mtu 0x%x\n",
|
|
|
|
ifp->if_name, ifp->if_unit, ifp->if_mtu);
|
|
|
|
ENDDEBUG
|
|
|
|
return ifp;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif INET
|