1 /* $NetBSD: tp_inet.c,v 1.38 2009/03/18 17:06:53 cegger Exp $ */
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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
31 * @(#)tp_inet.c 8.1 (Berkeley) 6/10/93
34 /***********************************************************
35 Copyright IBM Corporation 1987
39 Permission to use, copy, modify, and distribute this software and its
40 documentation for any purpose and without fee is hereby granted,
41 provided that the above copyright notice appear in all copies and that
42 both that copyright notice and this permission notice appear in
43 supporting documentation, and that the name of IBM not be
44 used in advertising or publicity pertaining to distribution of the
45 software without specific, written prior permission.
47 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
48 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
49 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
50 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
51 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
52 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
55 ******************************************************************/
58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
61 * Here is where you find the inet-dependent code. We've tried keep all
62 * net-level and (primarily) address-family-dependent stuff out of the tp
63 * source, and everthing here is reached indirectly through a switch table
64 * (struct nl_protosw *) tpcb->tp_nlproto (see tp_pcb.c). The routines here
65 * are: in_getsufx: gets transport suffix out of an inpcb structure.
66 * in_putsufx: put transport suffix into an inpcb structure. in_putnetaddr:
67 * put a whole net addr into an inpcb. in_getnetaddr: get a whole net addr
68 * from an inpcb. in_cmpnetaddr: compare a whole net addr from an isopcb.
69 * in_recycle_suffix: clear suffix for reuse in inpcb tpip_mtu: figure out
70 * what size tpdu to use tpip_input: take a pkt from ip, strip off its ip
71 * header, give to tp tpip_output_dg: package a pkt for ip given 2 addresses
72 * & some data tpip_output: package a pkt for ip given an inpcb & some data
75 #include <sys/cdefs.h>
76 __KERNEL_RCSID(0, "$NetBSD: tp_inet.c,v 1.38 2009/03/18 17:06:53 cegger Exp $");
83 #include <sys/param.h>
84 #include <sys/socket.h>
85 #include <sys/socketvar.h>
87 #include <sys/errno.h>
89 #include <sys/systm.h>
93 #include <netiso/tp_param.h>
94 #include <netiso/argo_debug.h>
95 #include <netiso/tp_stat.h>
96 #include <netiso/tp_ip.h>
97 #include <netiso/tp_pcb.h>
98 #include <netiso/tp_trace.h>
99 #include <netiso/tp_tpdu.h>
100 #include <netiso/tp_var.h>
101 #include <netinet/in_var.h>
104 #include <netiso/iso_chksum.c>
107 #include <machine/stdarg.h>
112 * CALLED FROM: pr_usrreq() on PRU_BIND,
113 * PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR
115 * FUNCTION, ARGUMENTS, and RETURN VALUE:
116 * Get a transport suffix from an inpcb structure (inp).
117 * The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
119 * RETURNS: internet port / transport suffix
127 in_getsufx(void *v
, u_short
*lenp
, void *data_out
, int which
)
129 struct inpcb
*inp
= v
;
130 *lenp
= sizeof(u_short
);
133 *(u_short
*) data_out
= inp
->inp_lport
;
137 *(u_short
*) data_out
= inp
->inp_fport
;
145 * CALLED FROM: tp_newsocket(); i.e., when a connection
146 * is being established by an incoming CR_TPDU.
148 * FUNCTION, ARGUMENTS:
149 * Put a transport suffix (found in name) into an inpcb structure (inp).
150 * The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
160 in_putsufx(void *v
, void *sufxloc
, int sufxlen
, int which
)
162 struct inpcb
*inp
= v
;
163 if (which
== TP_FOREIGN
) {
164 memcpy((void *) & inp
->inp_fport
, sufxloc
, sizeof(inp
->inp_fport
));
169 * NAME: in_recycle_tsuffix()
171 * CALLED FROM: tp.trans whenever we go into REFWAIT state.
173 * FUNCTION and ARGUMENT:
174 * Called when a ref is frozen, to allow the suffix to be reused.
175 * (inp) is the net level pcb.
181 * NOTES: This really shouldn't have to be done in a NET level pcb
182 * but... for the internet world that just the way it is done in BSD...
183 * The alternative is to have the port unusable until the reference
187 in_recycle_tsuffix(void *v
)
189 struct inpcb
*inp
= v
;
190 inp
->inp_fport
= inp
->inp_lport
= 0;
194 * NAME: in_putnetaddr()
197 * tp_newsocket(); i.e., when a connection is being established by an
200 * FUNCTION and ARGUMENTS:
201 * Copy a whole net addr from a struct sockaddr (name).
202 * into an inpcb (inp).
203 * The argument (which) takes values TP_LOCAL or TP_FOREIGN
212 in_putnetaddr(void *v
, struct sockaddr
*nm
, int which
)
214 struct inpcb
*inp
= v
;
215 struct sockaddr_in
*name
= (struct sockaddr_in
*) nm
;
218 bcopy((void *) & name
->sin_addr
,
219 (void *) & inp
->inp_laddr
, sizeof(struct in_addr
));
220 /* won't work if the dst address (name) is INADDR_ANY */
224 if (name
!= (struct sockaddr_in
*) 0) {
225 bcopy((void *) & name
->sin_addr
,
226 (void *) & inp
->inp_faddr
, sizeof(struct in_addr
));
232 * NAME: in_cmpnetaddr()
235 * tp_input() when a connection is being established by an
236 * incoming CR_TPDU, and considered for interception.
238 * FUNCTION and ARGUMENTS:
239 * Compare a whole net addr from a struct sockaddr (name),
240 * with that implicitly stored in an inpcb (inp).
241 * The argument (which) takes values TP_LOCAL or TP_FOREIGN
250 in_cmpnetaddr(void *v
, struct sockaddr
*nm
, int which
)
252 struct inpcb
*inp
= v
;
253 struct sockaddr_in
*name
= (struct sockaddr_in
*) nm
;
254 if (which
== TP_LOCAL
) {
255 if (name
->sin_port
&& name
->sin_port
!= inp
->inp_lport
)
257 return (name
->sin_addr
.s_addr
== inp
->inp_laddr
.s_addr
);
259 if (name
->sin_port
&& name
->sin_port
!= inp
->inp_fport
)
261 return (name
->sin_addr
.s_addr
== inp
->inp_faddr
.s_addr
);
265 * NAME: in_getnetaddr()
268 * pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
269 * FUNCTION and ARGUMENTS:
270 * Copy a whole net addr from an inpcb (inp) into
272 * The argument (which) takes values TP_LOCAL or TP_FOREIGN.
282 in_getnetaddr(void *v
, struct mbuf
*name
, int which
)
284 struct inpcb
*inp
= v
;
285 struct sockaddr_in
*sin
= mtod(name
, struct sockaddr_in
*);
286 memset((void *) sin
, 0, sizeof(*sin
));
289 sin
->sin_addr
= inp
->inp_laddr
;
290 sin
->sin_port
= inp
->inp_lport
;
293 sin
->sin_addr
= inp
->inp_faddr
;
294 sin
->sin_port
= inp
->inp_fport
;
299 name
->m_len
= sin
->sin_len
= sizeof(*sin
);
300 sin
->sin_family
= AF_INET
;
307 * tp_route_to() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
309 * FUNCTION, ARGUMENTS, and RETURN VALUE:
311 * Perform subnetwork dependent part of determining MTU information.
312 * It appears that setting a double pointer to the rtentry associated with
313 * the destination, and returning the header size for the network protocol
317 * Sets tp_route in pcb.
324 struct tp_pcb
*tpcb
= v
;
325 struct inpcb
*inp
= (struct inpcb
*) tpcb
->tp_npcb
;
328 if (argo_debug
[D_CONN
]) {
329 printf("tpip_mtu(tpcb %p)\n", tpcb
);
330 printf("tpip_mtu routing to addr 0x%x\n", inp
->inp_faddr
.s_addr
);
333 tpcb
->tp_routep
= &inp
->inp_route
;
334 return sizeof(struct ip
);
339 * NAME: tpip_output()
341 * CALLED FROM: tp_emit()
343 * FUNCTION and ARGUMENTS:
344 * Take a packet(m0) from tp and package it so that ip will accept it.
345 * This means prepending space for the ip header and filling in a few
347 * inp is the inpcb structure; datalen is the length of the data in the
350 * whatever (E*) is returned form the net layer output routine.
358 tpip_output(struct mbuf
*m0
, ...)
366 datalen
= va_arg(ap
, int);
367 inp
= va_arg(ap
, struct inpcb
*);
368 nochksum
= va_arg(ap
, int);
371 return tpip_output_dg(m0
, datalen
, &inp
->inp_laddr
, &inp
->inp_faddr
,
372 &inp
->inp_route
, nochksum
);
376 * NAME: tpip_output_dg()
378 * CALLED FROM: tp_error_emit()
380 * FUNCTION and ARGUMENTS:
381 * This is a copy of tpip_output that takes the addresses
382 * instead of a pcb. It's used by the tp_error_emit, when we
383 * don't have an in_pcb with which to call the normal output rtn.
385 * RETURNS: ENOBUFS or whatever (E*) is
386 * returned form the net layer output routine.
395 tpip_output_dg(struct mbuf
*m0
, ...)
398 struct in_addr
*laddr
, *faddr
;
407 datalen
= va_arg(ap
, int);
408 laddr
= va_arg(ap
, struct in_addr
*);
409 faddr
= va_arg(ap
, struct in_addr
*);
410 ro
= va_arg(ap
, struct route
*);
411 nochksum
= va_arg(ap
, int);
415 if (argo_debug
[D_EMIT
]) {
416 printf("tpip_output_dg datalen 0x%x m0 %p\n", datalen
, m0
);
421 MGETHDR(m
, M_DONTWAIT
, TPMT_IPHDR
);
427 MH_ALIGN(m
, sizeof(struct ip
));
428 m
->m_len
= sizeof(struct ip
);
430 ip
= mtod(m
, struct ip
*);
431 memset((void *) ip
, 0, sizeof *ip
);
433 ip
->ip_p
= IPPROTO_TP
;
434 if (sizeof(struct ip
) + datalen
> IP_MAXPACKET
) {
438 m
->m_pkthdr
.len
= sizeof(struct ip
) + datalen
;
439 ip
->ip_len
= htons(sizeof(struct ip
) + datalen
);
442 * don't know why you need to set ttl; overlay doesn't even make this
449 IncStat(ts_tpdu_sent
);
451 if (argo_debug
[D_EMIT
]) {
452 dump_mbuf(m
, "tpip_output_dg before ip_output\n");
456 error
= ip_output(m
, (struct mbuf
*) 0, ro
, IP_ALLOWBROADCAST
,
457 (struct ip_moptions
*)NULL
, (struct socket
*)NULL
);
460 if (argo_debug
[D_EMIT
]) {
461 printf("tpip_output_dg after ip_output\n");
469 IncStat(ts_send_drop
);
477 * ip's input routine, indirectly through the protosw.
479 * FUNCTION and ARGUMENTS:
480 * Take a packet (m) from ip, strip off the ip header and give it to tp
482 * RETURNS: No return value.
489 tpip_input(struct mbuf
*m
, ...)
492 struct sockaddr_in src
, dst
;
494 int s
= splsoftnet(), hdrlen
;
498 iplen
= va_arg(ap
, int);
501 IncStat(ts_pkt_rcvd
);
504 * IP layer has already pulled up the IP header,
505 * but the first byte after the IP header may not be there,
506 * e.g. if you came in via loopback, so you have to do an
507 * m_pullup to before you can even look to see how much you
508 * really need. The good news is that m_pullup will round
509 * up to almost the next mbuf's worth.
513 if ((m
= m_pullup(m
, iplen
+ 1)) == NULL
)
515 CHANGE_MTYPE(m
, TPMT_DATA
);
518 * Now pull up the whole tp header:
519 * Unfortunately, there may be IP options to skip past so we
520 * just fetch it as an unsigned char.
522 hdrlen
= iplen
+ 1 + mtod(m
, u_char
*)[iplen
];
524 if (m
->m_len
< hdrlen
) {
525 if ((m
= m_pullup(m
, hdrlen
)) == NULL
) {
527 if (argo_debug
[D_TPINPUT
]) {
528 printf("tp_input, pullup 2!\n");
535 * cannot use tp_inputprep() here 'cause you don't have quite the
540 if (argo_debug
[D_TPINPUT
]) {
541 dump_mbuf(m
, "after tpip_input both pullups");
545 * m_pullup may have returned a different mbuf
547 ip
= mtod(m
, struct ip
*);
550 * drop the ip header from the front of the mbuf
551 * this is necessary for the tp checksum
556 src
.sin_addr
= *(struct in_addr
*) & (ip
->ip_src
);
557 src
.sin_family
= AF_INET
;
558 src
.sin_len
= sizeof(src
);
559 dst
.sin_addr
= *(struct in_addr
*) & (ip
->ip_dst
);
560 dst
.sin_family
= AF_INET
;
561 dst
.sin_len
= sizeof(dst
);
563 tp_input(m
, sintosa(&src
), sintosa(&dst
), 0, tpip_output_dg
, 0);
568 if (argo_debug
[D_TPINPUT
]) {
569 printf("tpip_input DISCARD\n");
573 if (tp_traceflags
[D_TPINPUT
]) {
574 tptrace(TPPTmisc
, "tpip_input DISCARD m", m
, 0, 0, 0);
578 IncStat(ts_recv_drop
);
583 #include <sys/protosw.h>
584 #include <netinet/ip_icmp.h>
587 * NAME: tpin_quench()
589 * CALLED FROM: tpip_ctlinput()
591 * FUNCTION and ARGUMENTS: find the tpcb pointer and pass it to tp_quench
601 tpin_quench(struct inpcb
*inp
, int dummy
)
603 tp_quench((struct inpcb
*) inp
->inp_socket
->so_pcb
, PRC_QUENCH
);
607 * NAME: tpip_ctlinput()
610 * The network layer through the protosw table.
612 * FUNCTION and ARGUMENTS:
613 * When clnp gets an ICMP msg this gets called.
614 * It either returns an error status to the user or
615 * causes all connections on this address to be aborted
616 * by calling the appropriate xx_notify() routine.
617 * (cmd) is the type of ICMP error.
618 * (sa) the address of the sender
627 tpip_ctlinput(int cmd
, const struct sockaddr
*sa
, void *dummy
)
629 void (*notify
)(struct inpcb
*, int);
632 if ((unsigned)cmd
>= PRC_NCMDS
)
634 errno
= inetctlerrmap
[cmd
];
642 case PRC_HOSTUNREACH
:
643 case PRC_UNREACH_NET
:
646 notify
= in_rtchange
;
652 case PRC_UNREACH_HOST:
653 case PRC_UNREACH_PROTOCOL:
654 case PRC_UNREACH_PORT:
655 case PRC_UNREACH_NEEDFRAG:
656 case PRC_UNREACH_SRCFAIL:
657 case PRC_REDIRECT_NET:
658 case PRC_REDIRECT_HOST:
659 case PRC_REDIRECT_TOSNET:
660 case PRC_REDIRECT_TOSHOST:
661 case PRC_TIMXCEED_INTRANS:
662 case PRC_TIMXCEED_REASS:
668 in_pcbnotifyall(&tp_inpcb
, satocsin(sa
)->sin_addr
, errno
, notify
);
676 * xxx_notify() from tp_ctlinput() when
677 * net level gets some ICMP-equiv. type event.
679 * FUNCTION and ARGUMENTS:
680 * Cause the connection to be aborted with some sort of error
681 * reason indicating that the network layer caused the abort.
682 * Fakes an ER TPDU so we can go through the driver.
692 tpin_abort(struct inpcb
*inp
, int n
)
696 e
.ev_number
= ER_TPDU
;
697 e
.TPDU_ATTR(ER
).e_reason
= ENETRESET
;
698 tp_driver((struct tp_pcb
*) inp
->inp_ppcb
, &e
);
703 dump_inaddr(struct sockaddr_in
*addr
)
705 printf("INET: port 0x%x; addr 0x%x\n", addr
->sin_port
, addr
->sin_addr
.s_addr
);
707 #endif /* ARGO_DEBUG */