Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /*- |
2 | * Copyright (c) 1991 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | * | |
43371f85 | 33 | * from: @(#)tp_inet.c 7.8 (Berkeley) 5/6/91 |
fde1aeb2 | 34 | * $Id: tp_inet.c,v 1.3 1993/11/25 01:36:03 wollman Exp $ |
15637ed4 RG |
35 | */ |
36 | ||
37 | /*********************************************************** | |
38 | Copyright IBM Corporation 1987 | |
39 | ||
40 | All Rights Reserved | |
41 | ||
42 | Permission to use, copy, modify, and distribute this software and its | |
43 | documentation for any purpose and without fee is hereby granted, | |
44 | provided that the above copyright notice appear in all copies and that | |
45 | both that copyright notice and this permission notice appear in | |
46 | supporting documentation, and that the name of IBM not be | |
47 | used in advertising or publicity pertaining to distribution of the | |
48 | software without specific, written prior permission. | |
49 | ||
50 | IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |
51 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | |
52 | IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |
53 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
54 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
55 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
56 | SOFTWARE. | |
57 | ||
58 | ******************************************************************/ | |
59 | ||
60 | /* | |
61 | * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison | |
62 | */ | |
43371f85 | 63 | |
15637ed4 RG |
64 | /* |
65 | * ARGO TP | |
15637ed4 RG |
66 | * |
67 | * Here is where you find the inet-dependent code. We've tried | |
68 | * keep all net-level and (primarily) address-family-dependent stuff | |
69 | * out of the tp source, and everthing here is reached indirectly | |
70 | * through a switch table (struct nl_protosw *) tpcb->tp_nlproto | |
71 | * (see tp_pcb.c). | |
72 | * The routines here are: | |
73 | * in_getsufx: gets transport suffix out of an inpcb structure. | |
74 | * in_putsufx: put transport suffix into an inpcb structure. | |
75 | * in_putnetaddr: put a whole net addr into an inpcb. | |
76 | * in_getnetaddr: get a whole net addr from an inpcb. | |
77 | * in_cmpnetaddr: compare a whole net addr from an isopcb. | |
78 | * in_recycle_suffix: clear suffix for reuse in inpcb | |
79 | * tpip_mtu: figure out what size tpdu to use | |
80 | * tpip_input: take a pkt from ip, strip off its ip header, give to tp | |
81 | * tpip_output_dg: package a pkt for ip given 2 addresses & some data | |
82 | * tpip_output: package a pkt for ip given an inpcb & some data | |
83 | */ | |
84 | ||
85 | #ifdef INET | |
86 | ||
87 | #include "param.h" | |
fde1aeb2 | 88 | #include "systm.h" |
15637ed4 RG |
89 | #include "socket.h" |
90 | #include "socketvar.h" | |
91 | #include "mbuf.h" | |
92 | #include "errno.h" | |
93 | #include "time.h" | |
94 | #include "../net/if.h" | |
95 | #include "tp_param.h" | |
96 | #include "argo_debug.h" | |
97 | #include "tp_stat.h" | |
98 | #include "tp_ip.h" | |
99 | #include "tp_pcb.h" | |
100 | #include "tp_trace.h" | |
101 | #include "tp_stat.h" | |
102 | #include "tp_tpdu.h" | |
103 | #include "../netinet/in_var.h" | |
104 | ||
105 | #ifndef ISO | |
106 | #include "iso_chksum.c" | |
107 | #endif | |
108 | ||
4c45483e GW |
109 | static void tpin_abort(struct inpcb *, int); |
110 | ||
15637ed4 RG |
111 | /* |
112 | * NAME: in_getsufx() | |
113 | ||
114 | * CALLED FROM: pr_usrreq() on PRU_BIND, | |
115 | * PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR | |
116 | * | |
117 | * FUNCTION, ARGUMENTS, and RETURN VALUE: | |
118 | * Get a transport suffix from an inpcb structure (inp). | |
119 | * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. | |
120 | * | |
121 | * RETURNS: internet port / transport suffix | |
122 | * (CAST TO AN INT) | |
123 | * | |
124 | * SIDE EFFECTS: | |
125 | * | |
126 | * NOTES: | |
127 | */ | |
4c45483e | 128 | void |
15637ed4 RG |
129 | in_getsufx(inp, lenp, data_out, which) |
130 | struct inpcb *inp; | |
131 | u_short *lenp; | |
132 | caddr_t data_out; | |
133 | int which; | |
134 | { | |
135 | *lenp = sizeof(u_short); | |
136 | switch (which) { | |
137 | case TP_LOCAL: | |
138 | *(u_short *)data_out = inp->inp_lport; | |
139 | return; | |
140 | ||
141 | case TP_FOREIGN: | |
142 | *(u_short *)data_out = inp->inp_fport; | |
143 | } | |
144 | ||
145 | } | |
146 | ||
147 | /* | |
148 | * NAME: in_putsufx() | |
149 | * | |
150 | * CALLED FROM: tp_newsocket(); i.e., when a connection | |
151 | * is being established by an incoming CR_TPDU. | |
152 | * | |
153 | * FUNCTION, ARGUMENTS: | |
154 | * Put a transport suffix (found in name) into an inpcb structure (inp). | |
155 | * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. | |
156 | * | |
157 | * RETURNS: Nada | |
158 | * | |
159 | * SIDE EFFECTS: | |
160 | * | |
161 | * NOTES: | |
162 | */ | |
163 | /*ARGSUSED*/ | |
164 | void | |
165 | in_putsufx(inp, sufxloc, sufxlen, which) | |
166 | struct inpcb *inp; | |
167 | caddr_t sufxloc; | |
4c45483e | 168 | int sufxlen; |
15637ed4 RG |
169 | int which; |
170 | { | |
171 | if (which == TP_FOREIGN) { | |
172 | bcopy(sufxloc, (caddr_t)&inp->inp_fport, sizeof(inp->inp_fport)); | |
173 | } | |
174 | } | |
175 | ||
176 | /* | |
177 | * NAME: in_recycle_tsuffix() | |
178 | * | |
179 | * CALLED FROM: tp.trans whenever we go into REFWAIT state. | |
180 | * | |
181 | * FUNCTION and ARGUMENT: | |
182 | * Called when a ref is frozen, to allow the suffix to be reused. | |
183 | * (inp) is the net level pcb. | |
184 | * | |
185 | * RETURNS: Nada | |
186 | * | |
187 | * SIDE EFFECTS: | |
188 | * | |
189 | * NOTES: This really shouldn't have to be done in a NET level pcb | |
190 | * but... for the internet world that just the way it is done in BSD... | |
191 | * The alternative is to have the port unusable until the reference | |
192 | * timer goes off. | |
193 | */ | |
194 | void | |
195 | in_recycle_tsuffix(inp) | |
196 | struct inpcb *inp; | |
197 | { | |
198 | inp->inp_fport = inp->inp_lport = 0; | |
199 | } | |
200 | ||
201 | /* | |
202 | * NAME: in_putnetaddr() | |
203 | * | |
204 | * CALLED FROM: | |
205 | * tp_newsocket(); i.e., when a connection is being established by an | |
206 | * incoming CR_TPDU. | |
207 | * | |
208 | * FUNCTION and ARGUMENTS: | |
209 | * Copy a whole net addr from a struct sockaddr (name). | |
210 | * into an inpcb (inp). | |
211 | * The argument (which) takes values TP_LOCAL or TP_FOREIGN | |
212 | * | |
213 | * RETURNS: Nada | |
214 | * | |
215 | * SIDE EFFECTS: | |
216 | * | |
217 | * NOTES: | |
218 | */ | |
219 | void | |
220 | in_putnetaddr(inp, name, which) | |
221 | register struct inpcb *inp; | |
222 | struct sockaddr_in *name; | |
223 | int which; | |
224 | { | |
225 | switch (which) { | |
226 | case TP_LOCAL: | |
227 | bcopy((caddr_t)&name->sin_addr, | |
228 | (caddr_t)&inp->inp_laddr, sizeof(struct in_addr)); | |
229 | /* won't work if the dst address (name) is INADDR_ANY */ | |
230 | ||
231 | break; | |
232 | case TP_FOREIGN: | |
233 | if( name != (struct sockaddr_in *)0 ) { | |
234 | bcopy((caddr_t)&name->sin_addr, | |
235 | (caddr_t)&inp->inp_faddr, sizeof(struct in_addr)); | |
236 | } | |
237 | } | |
238 | } | |
239 | ||
240 | /* | |
241 | * NAME: in_putnetaddr() | |
242 | * | |
243 | * CALLED FROM: | |
244 | * tp_input() when a connection is being established by an | |
245 | * incoming CR_TPDU, and considered for interception. | |
246 | * | |
247 | * FUNCTION and ARGUMENTS: | |
248 | * Compare a whole net addr from a struct sockaddr (name), | |
249 | * with that implicitly stored in an inpcb (inp). | |
250 | * The argument (which) takes values TP_LOCAL or TP_FOREIGN | |
251 | * | |
252 | * RETURNS: Nada | |
253 | * | |
254 | * SIDE EFFECTS: | |
255 | * | |
256 | * NOTES: | |
257 | */ | |
4c45483e | 258 | int |
15637ed4 RG |
259 | in_cmpnetaddr(inp, name, which) |
260 | register struct inpcb *inp; | |
261 | register struct sockaddr_in *name; | |
262 | int which; | |
263 | { | |
264 | if (which == TP_LOCAL) { | |
265 | if (name->sin_port && name->sin_port != inp->inp_lport) | |
266 | return 0; | |
267 | return (name->sin_addr.s_addr == inp->inp_laddr.s_addr); | |
268 | } | |
269 | if (name->sin_port && name->sin_port != inp->inp_fport) | |
270 | return 0; | |
271 | return (name->sin_addr.s_addr == inp->inp_faddr.s_addr); | |
272 | } | |
273 | ||
274 | /* | |
275 | * NAME: in_getnetaddr() | |
276 | * | |
277 | * CALLED FROM: | |
278 | * pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR | |
279 | * FUNCTION and ARGUMENTS: | |
280 | * Copy a whole net addr from an inpcb (inp) into | |
281 | * an mbuf (name); | |
282 | * The argument (which) takes values TP_LOCAL or TP_FOREIGN. | |
283 | * | |
284 | * RETURNS: Nada | |
285 | * | |
286 | * SIDE EFFECTS: | |
287 | * | |
288 | * NOTES: | |
289 | */ | |
290 | ||
291 | void | |
292 | in_getnetaddr( inp, name, which) | |
293 | register struct mbuf *name; | |
294 | struct inpcb *inp; | |
295 | int which; | |
296 | { | |
297 | register struct sockaddr_in *sin = mtod(name, struct sockaddr_in *); | |
298 | bzero((caddr_t)sin, sizeof(*sin)); | |
299 | switch (which) { | |
300 | case TP_LOCAL: | |
301 | sin->sin_addr = inp->inp_laddr; | |
302 | sin->sin_port = inp->inp_lport; | |
303 | break; | |
304 | case TP_FOREIGN: | |
305 | sin->sin_addr = inp->inp_faddr; | |
306 | sin->sin_port = inp->inp_fport; | |
307 | break; | |
308 | default: | |
309 | return; | |
310 | } | |
311 | name->m_len = sin->sin_len = sizeof (*sin); | |
312 | sin->sin_family = AF_INET; | |
313 | } | |
314 | ||
315 | /* | |
316 | * NAME: tpip_mtu() | |
317 | * | |
318 | * CALLED FROM: | |
319 | * tp_input() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT | |
320 | * | |
321 | * FUNCTION, ARGUMENTS, and RETURN VALUE: | |
322 | * | |
323 | * Determine the proper maximum transmission unit, i.e., MTU, to use, given | |
324 | * a) the header size for the network protocol and the max transmission | |
325 | * unit on the subnet interface, determined from the information in (inp), | |
326 | * b) the max size negotiated so far (negot) | |
327 | * c) the window size used by the tp connection (found in so), | |
328 | * | |
329 | * The result is put in the integer *size in its integer form and in | |
330 | * *negot in its logarithmic form. | |
331 | * | |
332 | * The rules are: | |
333 | * a) can only negotiate down from the value found in *negot. | |
334 | * b) the MTU must be < the windowsize, | |
335 | * c) If src and dest are on the same net, | |
336 | * we will negotiate the closest size larger than MTU but really USE | |
337 | * the actual device mtu - ll hdr sizes. | |
338 | * otherwise we negotiate the closest size smaller than MTU - ll hdr sizes. | |
339 | * | |
340 | * SIDE EFFECTS: | |
341 | * changes the values addressed by the arguments (size) and (negot) | |
342 | * and | |
343 | * when the peer is not on one of our directly connected subnets, it | |
344 | * looks up a route, leaving the route in the inpcb addressed by (inp) | |
345 | * | |
346 | * NOTES: | |
347 | */ | |
348 | ||
349 | void | |
350 | tpip_mtu(so, inp, size, negot) | |
351 | struct socket *so; | |
352 | struct inpcb *inp; | |
353 | int *size; | |
354 | u_char *negot; | |
355 | { | |
356 | register struct ifnet *ifp; | |
357 | struct ifnet *tpip_route(); | |
358 | struct in_ifaddr *ia; | |
359 | register int i; | |
360 | int windowsize = so->so_rcv.sb_hiwat; | |
361 | ||
362 | IFDEBUG(D_CONN) | |
363 | printf("tpip_mtu(0x%x,0x%x,0x%x,0x%x)\n", | |
364 | so, inp, size, negot); | |
365 | printf("tpip_mtu routing to addr 0x%x\n", inp->inp_faddr); | |
366 | ENDDEBUG | |
367 | IFTRACE(D_CONN) | |
368 | tptrace(TPPTmisc, "ENTER GET MTU: size negot \n",*size, *negot, 0, 0); | |
369 | ENDTRACE | |
370 | ||
371 | *size = 1 << *negot; | |
372 | ||
373 | if( *size > windowsize ) { | |
374 | *size = windowsize; | |
375 | } | |
376 | ||
377 | ia = in_iaonnetof(in_netof(inp->inp_faddr)); | |
378 | if ( ia == (struct in_ifaddr *)0 ) { | |
379 | ifp = tpip_route(&inp->inp_faddr); | |
380 | if( ifp == (struct ifnet *)0 ) | |
381 | return ; | |
382 | } else | |
383 | ifp = ia->ia_ifp; | |
384 | ||
385 | ||
386 | /**************************************************************** | |
387 | * TODO - make this indirect off the socket structure to the | |
388 | * network layer to get headersize | |
389 | * After all, who knows what lies below the IP layer? | |
390 | * Who knows how big the NL header will be? | |
391 | ***************************************************************/ | |
392 | ||
393 | if( *size > ifp->if_mtu - sizeof(struct ip)) { | |
394 | *size = ifp->if_mtu - sizeof(struct ip); | |
395 | } | |
396 | for(i=TP_MIN_TPDUSIZE; (i<TP_MAX_TPDUSIZE && ((1<<i)<*size)) ; i++) | |
397 | ; | |
398 | i--; | |
399 | ||
400 | if (in_netof(inp->inp_laddr) != in_netof(inp->inp_faddr)) { | |
401 | i++; | |
402 | } else { | |
403 | *size = 1<<i; | |
404 | } | |
405 | *negot = i; | |
406 | ||
407 | IFDEBUG(D_CONN) | |
408 | printf("GET MTU RETURNS: ifp %s size 0x%x negot 0x%x\n", | |
409 | ifp->if_name, *size, *negot); | |
410 | ENDDEBUG | |
411 | IFTRACE(D_CONN) | |
412 | tptrace(TPPTmisc, "EXIT GET MTU: tpcb size negot \n", | |
413 | *size, *negot, 0, 0); | |
414 | ENDTRACE | |
415 | ||
416 | } | |
417 | ||
418 | /* | |
419 | * NAME: tpip_output() | |
420 | * | |
421 | * CALLED FROM: tp_emit() | |
422 | * | |
423 | * FUNCTION and ARGUMENTS: | |
424 | * Take a packet(m0) from tp and package it so that ip will accept it. | |
425 | * This means prepending space for the ip header and filling in a few | |
426 | * of the fields. | |
427 | * inp is the inpcb structure; datalen is the length of the data in the | |
428 | * mbuf string m0. | |
429 | * RETURNS: | |
430 | * whatever (E*) is returned form the net layer output routine. | |
431 | * | |
432 | * SIDE EFFECTS: | |
433 | * | |
434 | * NOTES: | |
435 | */ | |
436 | ||
437 | int | |
438 | tpip_output(inp, m0, datalen, nochksum) | |
439 | struct inpcb *inp; | |
440 | struct mbuf *m0; | |
441 | int datalen; | |
442 | int nochksum; | |
443 | { | |
444 | return tpip_output_dg( &inp->inp_laddr, &inp->inp_faddr, m0, datalen, | |
445 | &inp->inp_route, nochksum); | |
446 | } | |
447 | ||
448 | /* | |
449 | * NAME: tpip_output_dg() | |
450 | * | |
451 | * CALLED FROM: tp_error_emit() | |
452 | * | |
453 | * FUNCTION and ARGUMENTS: | |
454 | * This is a copy of tpip_output that takes the addresses | |
455 | * instead of a pcb. It's used by the tp_error_emit, when we | |
456 | * don't have an in_pcb with which to call the normal output rtn. | |
457 | * | |
458 | * RETURNS: ENOBUFS or whatever (E*) is | |
459 | * returned form the net layer output routine. | |
460 | * | |
461 | * SIDE EFFECTS: | |
462 | * | |
463 | * NOTES: | |
464 | */ | |
465 | ||
466 | /*ARGSUSED*/ | |
467 | int | |
468 | tpip_output_dg(laddr, faddr, m0, datalen, ro, nochksum) | |
469 | struct in_addr *laddr, *faddr; | |
470 | struct mbuf *m0; | |
471 | int datalen; | |
472 | struct route *ro; | |
473 | int nochksum; | |
474 | { | |
475 | register struct mbuf *m; | |
476 | register struct ip *ip; | |
477 | int error; | |
478 | ||
479 | IFDEBUG(D_EMIT) | |
480 | printf("tpip_output_dg datalen 0x%x m0 0x%x\n", datalen, m0); | |
481 | ENDDEBUG | |
482 | ||
483 | ||
484 | MGETHDR(m, M_DONTWAIT, TPMT_IPHDR); | |
485 | if (m == 0) { | |
486 | error = ENOBUFS; | |
487 | goto bad; | |
488 | } | |
489 | m->m_next = m0; | |
490 | MH_ALIGN(m, sizeof(struct ip)); | |
491 | m->m_len = sizeof(struct ip); | |
492 | ||
493 | ip = mtod(m, struct ip *); | |
494 | bzero((caddr_t)ip, sizeof *ip); | |
495 | ||
496 | ip->ip_p = IPPROTO_TP; | |
497 | m->m_pkthdr.len = ip->ip_len = sizeof(struct ip) + datalen; | |
498 | ip->ip_ttl = MAXTTL; | |
499 | /* don't know why you need to set ttl; | |
500 | * overlay doesn't even make this available | |
501 | */ | |
502 | ||
503 | ip->ip_src = *laddr; | |
504 | ip->ip_dst = *faddr; | |
505 | ||
506 | IncStat(ts_tpdu_sent); | |
507 | IFDEBUG(D_EMIT) | |
508 | dump_mbuf(m, "tpip_output_dg before ip_output\n"); | |
509 | ENDDEBUG | |
510 | ||
511 | error = ip_output(m, (struct mbuf *)0, ro, IP_ALLOWBROADCAST); | |
512 | ||
513 | IFDEBUG(D_EMIT) | |
514 | printf("tpip_output_dg after ip_output\n"); | |
515 | ENDDEBUG | |
516 | ||
517 | return error; | |
518 | ||
519 | bad: | |
520 | m_freem(m); | |
521 | IncStat(ts_send_drop); | |
522 | return error; | |
523 | } | |
524 | ||
525 | /* | |
526 | * NAME: tpip_input() | |
527 | * | |
528 | * CALLED FROM: | |
529 | * ip's input routine, indirectly through the protosw. | |
530 | * | |
531 | * FUNCTION and ARGUMENTS: | |
532 | * Take a packet (m) from ip, strip off the ip header and give it to tp | |
533 | * | |
534 | * RETURNS: No return value. | |
535 | * | |
536 | * SIDE EFFECTS: | |
537 | * | |
538 | * NOTES: | |
539 | */ | |
540 | ProtoHook | |
541 | tpip_input(m, iplen) | |
542 | struct mbuf *m; | |
543 | int iplen; | |
544 | { | |
545 | struct sockaddr_in src, dst; | |
546 | register struct ip *ip; | |
547 | int s = splnet(), hdrlen; | |
548 | ||
549 | IncStat(ts_pkt_rcvd); | |
550 | ||
551 | /* | |
552 | * IP layer has already pulled up the IP header, | |
553 | * but the first byte after the IP header may not be there, | |
554 | * e.g. if you came in via loopback, so you have to do an | |
555 | * m_pullup to before you can even look to see how much you | |
556 | * really need. The good news is that m_pullup will round | |
557 | * up to almost the next mbuf's worth. | |
558 | */ | |
559 | ||
560 | ||
561 | if((m = m_pullup(m, iplen + 1)) == MNULL) | |
562 | goto discard; | |
563 | CHANGE_MTYPE(m, TPMT_DATA); | |
564 | ||
565 | /* | |
566 | * Now pull up the whole tp header: | |
567 | * Unfortunately, there may be IP options to skip past so we | |
568 | * just fetch it as an unsigned char. | |
569 | */ | |
570 | hdrlen = iplen + 1 + mtod(m, u_char *)[iplen]; | |
571 | ||
572 | if( m->m_len < hdrlen ) { | |
573 | if((m = m_pullup(m, hdrlen)) == MNULL){ | |
574 | IFDEBUG(D_TPINPUT) | |
575 | printf("tp_input, pullup 2!\n"); | |
576 | ENDDEBUG | |
577 | goto discard; | |
578 | } | |
579 | } | |
580 | /* | |
581 | * cannot use tp_inputprep() here 'cause you don't | |
582 | * have quite the same situation | |
583 | */ | |
584 | ||
585 | IFDEBUG(D_TPINPUT) | |
586 | dump_mbuf(m, "after tpip_input both pullups"); | |
587 | ENDDEBUG | |
588 | /* | |
589 | * m_pullup may have returned a different mbuf | |
590 | */ | |
591 | ip = mtod(m, struct ip *); | |
592 | ||
593 | /* | |
594 | * drop the ip header from the front of the mbuf | |
595 | * this is necessary for the tp checksum | |
596 | */ | |
597 | m->m_len -= iplen; | |
598 | m->m_data += iplen; | |
599 | ||
600 | src.sin_addr = *(struct in_addr *)&(ip->ip_src); | |
601 | src.sin_family = AF_INET; | |
602 | src.sin_len = sizeof(src); | |
603 | dst.sin_addr = *(struct in_addr *)&(ip->ip_dst); | |
604 | dst.sin_family = AF_INET; | |
605 | dst.sin_len = sizeof(dst); | |
606 | ||
607 | (void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst, | |
608 | 0, tpip_output_dg, 0); | |
609 | return 0; | |
610 | ||
611 | discard: | |
612 | IFDEBUG(D_TPINPUT) | |
613 | printf("tpip_input DISCARD\n"); | |
614 | ENDDEBUG | |
615 | IFTRACE(D_TPINPUT) | |
616 | tptrace(TPPTmisc, "tpip_input DISCARD m", m,0,0,0); | |
617 | ENDTRACE | |
618 | m_freem(m); | |
619 | IncStat(ts_recv_drop); | |
620 | splx(s); | |
621 | return 0; | |
622 | } | |
623 | ||
624 | ||
625 | #include "protosw.h" | |
626 | #include "../netinet/ip_icmp.h" | |
627 | ||
628 | extern void tp_quench(); | |
629 | /* | |
630 | * NAME: tpin_quench() | |
631 | * | |
632 | * CALLED FROM: tpip_ctlinput() | |
633 | * | |
634 | * FUNCTION and ARGUMENTS: find the tpcb pointer and pass it to tp_quench | |
635 | * | |
636 | * RETURNS: Nada | |
637 | * | |
638 | * SIDE EFFECTS: | |
639 | * | |
640 | * NOTES: | |
641 | */ | |
642 | ||
643 | void | |
644 | tpin_quench(inp) | |
645 | struct inpcb *inp; | |
646 | { | |
647 | tp_quench((struct tp_pcb *)inp->inp_socket->so_tpcb, PRC_QUENCH); | |
648 | } | |
649 | ||
650 | /* | |
651 | * NAME: tpip_ctlinput() | |
652 | * | |
653 | * CALLED FROM: | |
654 | * The network layer through the protosw table. | |
655 | * | |
656 | * FUNCTION and ARGUMENTS: | |
657 | * When clnp gets an ICMP msg this gets called. | |
658 | * It either returns an error status to the user or | |
659 | * causes all connections on this address to be aborted | |
660 | * by calling the appropriate xx_notify() routine. | |
661 | * (cmd) is the type of ICMP error. | |
662 | * (sa) the address of the sender | |
663 | * | |
664 | * RETURNS: Nothing | |
665 | * | |
666 | * SIDE EFFECTS: | |
667 | * | |
668 | * NOTES: | |
669 | */ | |
670 | ProtoHook | |
671 | tpip_ctlinput(cmd, sin) | |
672 | int cmd; | |
673 | struct sockaddr_in *sin; | |
674 | { | |
675 | extern u_char inetctlerrmap[]; | |
15637ed4 RG |
676 | extern struct in_addr zeroin_addr; |
677 | ||
678 | if (sin->sin_family != AF_INET && sin->sin_family != AF_IMPLINK) | |
679 | return 0; | |
680 | if (sin->sin_addr.s_addr == INADDR_ANY) | |
681 | return 0; | |
682 | if (cmd < 0 || cmd > PRC_NCMDS) | |
683 | return 0; | |
684 | switch (cmd) { | |
685 | ||
686 | case PRC_QUENCH: | |
4c45483e GW |
687 | in_pcbnotify(&tp_inpcb, (struct sockaddr *)sin, 0, |
688 | zeroin_addr, 0, cmd, (void (*)())tp_quench); | |
15637ed4 RG |
689 | break; |
690 | ||
691 | case PRC_ROUTEDEAD: | |
692 | case PRC_HOSTUNREACH: | |
693 | case PRC_UNREACH_NET: | |
694 | case PRC_IFDOWN: | |
695 | case PRC_HOSTDEAD: | |
4c45483e | 696 | in_pcbnotify(&tp_inpcb, (struct sockaddr *)sin, 0, |
15637ed4 RG |
697 | zeroin_addr, 0, cmd, in_rtchange); |
698 | break; | |
699 | ||
700 | default: | |
701 | /* | |
702 | case PRC_MSGSIZE: | |
703 | case PRC_UNREACH_HOST: | |
704 | case PRC_UNREACH_PROTOCOL: | |
705 | case PRC_UNREACH_PORT: | |
706 | case PRC_UNREACH_NEEDFRAG: | |
707 | case PRC_UNREACH_SRCFAIL: | |
708 | case PRC_REDIRECT_NET: | |
709 | case PRC_REDIRECT_HOST: | |
710 | case PRC_REDIRECT_TOSNET: | |
711 | case PRC_REDIRECT_TOSHOST: | |
712 | case PRC_TIMXCEED_INTRANS: | |
713 | case PRC_TIMXCEED_REASS: | |
714 | case PRC_PARAMPROB: | |
715 | */ | |
4c45483e | 716 | in_pcbnotify(&tp_inpcb, (struct sockaddr *)sin, 0, zeroin_addr, 0, |
15637ed4 RG |
717 | cmd, tpin_abort); |
718 | } | |
719 | return 0; | |
720 | } | |
721 | ||
722 | /* | |
723 | * NAME: tpin_abort() | |
724 | * | |
725 | * CALLED FROM: | |
726 | * xxx_notify() from tp_ctlinput() when | |
727 | * net level gets some ICMP-equiv. type event. | |
728 | * | |
729 | * FUNCTION and ARGUMENTS: | |
730 | * Cause the connection to be aborted with some sort of error | |
731 | * reason indicating that the network layer caused the abort. | |
732 | * Fakes an ER TPDU so we can go through the driver. | |
733 | * | |
734 | * RETURNS: Nothing | |
735 | * | |
736 | * SIDE EFFECTS: | |
737 | * | |
738 | * NOTES: | |
739 | */ | |
740 | ||
4c45483e GW |
741 | static void |
742 | tpin_abort(inp, errno) | |
15637ed4 | 743 | struct inpcb *inp; |
4c45483e | 744 | int errno; |
15637ed4 RG |
745 | { |
746 | struct tp_event e; | |
747 | ||
748 | e.ev_number = ER_TPDU; | |
749 | e.ATTR(ER_TPDU).e_reason = ENETRESET; | |
750 | (void) tp_driver((struct tp_pcb *)inp->inp_ppcb, &e); | |
15637ed4 RG |
751 | } |
752 | ||
753 | #ifdef ARGO_DEBUG | |
4c45483e | 754 | void |
15637ed4 RG |
755 | dump_inaddr(addr) |
756 | register struct sockaddr_in *addr; | |
757 | { | |
758 | printf("INET: port 0x%x; addr 0x%x\n", addr->sin_port, addr->sin_addr); | |
759 | } | |
4c45483e | 760 | #endif /* ARGO_DEBUG */ |
15637ed4 RG |
761 | |
762 | /* | |
763 | * NAME: tpip_route() | |
764 | * | |
765 | * CALLED FROM: tpip_mtu() | |
766 | * | |
767 | * FUNCTION and ARGUMENTS: given a destination addresss, | |
768 | * find the interface that would be used to send something to this address. | |
769 | * | |
770 | * RETURNS: pointer to an ifnet structure | |
771 | * | |
772 | * SIDE EFFECTS: | |
773 | * | |
774 | * NOTES: | |
775 | */ | |
776 | struct ifnet * | |
777 | tpip_route(dst) | |
778 | struct in_addr *dst; | |
779 | { | |
780 | struct ifnet *ifp = (struct ifnet *)0; | |
781 | struct sockaddr_in insock; | |
782 | struct sockaddr_in *sin = &insock; | |
783 | struct rtentry *rt; | |
784 | struct ifaddr *ia; | |
785 | ||
786 | IFDEBUG(D_CONN) | |
787 | printf("tpip_route: dst is x%x\n", *dst); | |
788 | ENDDEBUG | |
789 | ||
790 | bzero((caddr_t)sin, sizeof (*sin)); | |
791 | sin->sin_family = AF_INET; | |
792 | sin->sin_len = sizeof(*sin); | |
793 | sin->sin_addr = *dst; | |
794 | ||
795 | ia = ifa_ifwithdstaddr((struct sockaddr *)sin); | |
796 | if (ia == 0) | |
797 | ia = ifa_ifwithnet((struct sockaddr *)sin); | |
798 | if (ia != 0) { | |
799 | ifp = ia->ifa_ifp; | |
800 | IFDEBUG(D_CONN) | |
801 | printf("tpip_route: ifp from ia:0x%x\n", ia); | |
802 | ENDDEBUG | |
803 | } else { | |
804 | rt = rtalloc1((struct sockaddr *)sin, 0); | |
805 | if (rt != 0) { | |
806 | ifp = rt->rt_ifp; | |
807 | IFDEBUG(D_CONN) | |
808 | printf("tpip_route: ifp from rentry: 0x%x\n", rt); | |
809 | ENDDEBUG | |
810 | rtfree(rt); | |
811 | } | |
812 | } | |
813 | IFDEBUG(D_CONN) | |
814 | printf("tpip_route: returning 0x%x\n", ifp); | |
815 | if (ifp) | |
816 | printf("tpip_route: if name %s unit 0x%x, mtu 0x%x\n", | |
817 | ifp->if_name, ifp->if_unit, ifp->if_mtu); | |
818 | ENDDEBUG | |
819 | return ifp; | |
820 | } | |
821 | ||
fde1aeb2 | 822 | #endif /* INET */ |