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