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