Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / netiso / tp_inet.c
blobf37deea459cb3c515c77188264f289795bb2566a
1 /* $NetBSD: tp_inet.c,v 1.38 2009/03/18 17:06:53 cegger Exp $ */
3 /*-
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
9 * are met:
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
29 * SUCH DAMAGE.
31 * @(#)tp_inet.c 8.1 (Berkeley) 6/10/93
34 /***********************************************************
35 Copyright IBM Corporation 1987
37 All Rights Reserved
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
53 SOFTWARE.
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 $");
78 #include "opt_inet.h"
79 #include "opt_iso.h"
81 #ifdef INET
83 #include <sys/param.h>
84 #include <sys/socket.h>
85 #include <sys/socketvar.h>
86 #include <sys/mbuf.h>
87 #include <sys/errno.h>
88 #include <sys/time.h>
89 #include <sys/systm.h>
91 #include <net/if.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>
103 #ifndef ISO
104 #include <netiso/iso_chksum.c>
105 #endif
107 #include <machine/stdarg.h>
110 * NAME: in_getsufx()
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
120 * (CAST TO AN INT)
122 * SIDE EFFECTS:
124 * NOTES:
126 void
127 in_getsufx(void *v, u_short *lenp, void *data_out, int which)
129 struct inpcb *inp = v;
130 *lenp = sizeof(u_short);
131 switch (which) {
132 case TP_LOCAL:
133 *(u_short *) data_out = inp->inp_lport;
134 return;
136 case TP_FOREIGN:
137 *(u_short *) data_out = inp->inp_fport;
143 * NAME: in_putsufx()
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.
152 * RETURNS: Nada
154 * SIDE EFFECTS:
156 * NOTES:
158 /* ARGSUSED */
159 void
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.
177 * RETURNS: Nada
179 * SIDE EFFECTS:
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
184 * timer goes off.
186 void
187 in_recycle_tsuffix(void *v)
189 struct inpcb *inp = v;
190 inp->inp_fport = inp->inp_lport = 0;
194 * NAME: in_putnetaddr()
196 * CALLED FROM:
197 * tp_newsocket(); i.e., when a connection is being established by an
198 * incoming CR_TPDU.
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
205 * RETURNS: Nada
207 * SIDE EFFECTS:
209 * NOTES:
211 void
212 in_putnetaddr(void *v, struct sockaddr *nm, int which)
214 struct inpcb *inp = v;
215 struct sockaddr_in *name = (struct sockaddr_in *) nm;
216 switch (which) {
217 case TP_LOCAL:
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 */
222 break;
223 case TP_FOREIGN:
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()
234 * CALLED FROM:
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
243 * RETURNS: Nada
245 * SIDE EFFECTS:
247 * NOTES:
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)
256 return 0;
257 return (name->sin_addr.s_addr == inp->inp_laddr.s_addr);
259 if (name->sin_port && name->sin_port != inp->inp_fport)
260 return 0;
261 return (name->sin_addr.s_addr == inp->inp_faddr.s_addr);
265 * NAME: in_getnetaddr()
267 * CALLED FROM:
268 * pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
269 * FUNCTION and ARGUMENTS:
270 * Copy a whole net addr from an inpcb (inp) into
271 * an mbuf (name);
272 * The argument (which) takes values TP_LOCAL or TP_FOREIGN.
274 * RETURNS: Nada
276 * SIDE EFFECTS:
278 * NOTES:
281 void
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));
287 switch (which) {
288 case TP_LOCAL:
289 sin->sin_addr = inp->inp_laddr;
290 sin->sin_port = inp->inp_lport;
291 break;
292 case TP_FOREIGN:
293 sin->sin_addr = inp->inp_faddr;
294 sin->sin_port = inp->inp_fport;
295 break;
296 default:
297 return;
299 name->m_len = sin->sin_len = sizeof(*sin);
300 sin->sin_family = AF_INET;
304 * NAME: tpip_mtu()
306 * CALLED FROM:
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
314 * suffices.
316 * SIDE EFFECTS:
317 * Sets tp_route in pcb.
319 * NOTES:
322 tpip_mtu(void *v)
324 struct tp_pcb *tpcb = v;
325 struct inpcb *inp = (struct inpcb *) tpcb->tp_npcb;
327 #ifdef ARGO_DEBUG
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);
332 #endif
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
346 * of the fields.
347 * inp is the inpcb structure; datalen is the length of the data in the
348 * mbuf string m0.
349 * RETURNS:
350 * whatever (E*) is returned form the net layer output routine.
352 * SIDE EFFECTS:
354 * NOTES:
358 tpip_output(struct mbuf *m0, ...)
360 int datalen;
361 struct inpcb *inp;
362 int nochksum;
363 va_list ap;
365 va_start(ap, m0);
366 datalen = va_arg(ap, int);
367 inp = va_arg(ap, struct inpcb *);
368 nochksum = va_arg(ap, int);
369 va_end(ap);
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.
388 * SIDE EFFECTS:
390 * NOTES:
393 /* ARGSUSED */
395 tpip_output_dg(struct mbuf *m0, ...)
397 int datalen;
398 struct in_addr *laddr, *faddr;
399 struct route *ro;
400 int nochksum;
401 struct mbuf *m;
402 struct ip *ip;
403 int error;
404 va_list ap;
406 va_start(ap, m0);
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);
412 va_end(ap);
414 #ifdef ARGO_DEBUG
415 if (argo_debug[D_EMIT]) {
416 printf("tpip_output_dg datalen 0x%x m0 %p\n", datalen, m0);
418 #endif
421 MGETHDR(m, M_DONTWAIT, TPMT_IPHDR);
422 if (m == 0) {
423 error = ENOBUFS;
424 goto bad;
426 m->m_next = m0;
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) {
435 error = EMSGSIZE;
436 goto bad;
438 m->m_pkthdr.len = sizeof(struct ip) + datalen;
439 ip->ip_len = htons(sizeof(struct ip) + datalen);
440 ip->ip_ttl = MAXTTL;
442 * don't know why you need to set ttl; overlay doesn't even make this
443 * available
446 ip->ip_src = *laddr;
447 ip->ip_dst = *faddr;
449 IncStat(ts_tpdu_sent);
450 #ifdef ARGO_DEBUG
451 if (argo_debug[D_EMIT]) {
452 dump_mbuf(m, "tpip_output_dg before ip_output\n");
454 #endif
456 error = ip_output(m, (struct mbuf *) 0, ro, IP_ALLOWBROADCAST,
457 (struct ip_moptions *)NULL, (struct socket *)NULL);
459 #ifdef ARGO_DEBUG
460 if (argo_debug[D_EMIT]) {
461 printf("tpip_output_dg after ip_output\n");
463 #endif
465 return error;
467 bad:
468 m_freem(m);
469 IncStat(ts_send_drop);
470 return error;
474 * NAME: tpip_input()
476 * CALLED FROM:
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.
484 * SIDE EFFECTS:
486 * NOTES:
488 void
489 tpip_input(struct mbuf *m, ...)
491 int iplen;
492 struct sockaddr_in src, dst;
493 struct ip *ip;
494 int s = splsoftnet(), hdrlen;
495 va_list ap;
497 va_start(ap, m);
498 iplen = va_arg(ap, int);
499 va_end(ap);
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)
514 goto discard;
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) {
526 #ifdef ARGO_DEBUG
527 if (argo_debug[D_TPINPUT]) {
528 printf("tp_input, pullup 2!\n");
530 #endif
531 goto discard;
535 * cannot use tp_inputprep() here 'cause you don't have quite the
536 * same situation
539 #ifdef ARGO_DEBUG
540 if (argo_debug[D_TPINPUT]) {
541 dump_mbuf(m, "after tpip_input both pullups");
543 #endif
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
553 m->m_len -= iplen;
554 m->m_data += iplen;
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);
564 return;
566 discard:
567 #ifdef ARGO_DEBUG
568 if (argo_debug[D_TPINPUT]) {
569 printf("tpip_input DISCARD\n");
571 #endif
572 #ifdef TPPT
573 if (tp_traceflags[D_TPINPUT]) {
574 tptrace(TPPTmisc, "tpip_input DISCARD m", m, 0, 0, 0);
576 #endif
577 m_freem(m);
578 IncStat(ts_recv_drop);
579 splx(s);
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
593 * RETURNS: Nada
595 * SIDE EFFECTS:
597 * NOTES:
600 void
601 tpin_quench(struct inpcb *inp, int dummy)
603 tp_quench((struct inpcb *) inp->inp_socket->so_pcb, PRC_QUENCH);
607 * NAME: tpip_ctlinput()
609 * CALLED FROM:
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
620 * RETURNS: Nothing
622 * SIDE EFFECTS:
624 * NOTES:
626 void *
627 tpip_ctlinput(int cmd, const struct sockaddr *sa, void *dummy)
629 void (*notify)(struct inpcb *, int);
630 int errno;
632 if ((unsigned)cmd >= PRC_NCMDS)
633 return NULL;
634 errno = inetctlerrmap[cmd];
635 switch (cmd) {
637 case PRC_QUENCH:
638 notify = tp_quench;
639 break;
641 case PRC_ROUTEDEAD:
642 case PRC_HOSTUNREACH:
643 case PRC_UNREACH_NET:
644 case PRC_IFDOWN:
645 case PRC_HOSTDEAD:
646 notify = in_rtchange;
647 break;
649 default:
651 case PRC_MSGSIZE:
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:
663 case PRC_PARAMPROB:
665 notify = tpin_abort;
666 break;
668 in_pcbnotifyall(&tp_inpcb, satocsin(sa)->sin_addr, errno, notify);
669 return NULL;
673 * NAME: tpin_abort()
675 * CALLED FROM:
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.
684 * RETURNS: Nothing
686 * SIDE EFFECTS:
688 * NOTES:
691 void
692 tpin_abort(struct inpcb *inp, int n)
694 struct tp_event e;
696 e.ev_number = ER_TPDU;
697 e.TPDU_ATTR(ER).e_reason = ENETRESET;
698 tp_driver((struct tp_pcb *) inp->inp_ppcb, &e);
701 #ifdef ARGO_DEBUG
702 void
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 */
708 #endif /* INET */