Commit | Line | Data |
---|---|---|
3b1d357b 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 | * $Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $ | |
29 | * $Source: /usr/argo/sys/netiso/RCS/if_cons.c,v $ | |
30 | * | |
31 | * cons.c - Connection Oriented Network Service: | |
32 | * including support for a) user transport-level service, | |
33 | * b) COSNS below CLNP, and c) CONS below TP. | |
34 | */ | |
35 | ||
36 | #ifndef lint | |
37 | static char *rcsid = "$Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $"; | |
38 | #endif lint | |
39 | ||
40 | #ifdef ARGO_DEBUG | |
41 | #define Static | |
42 | unsigned LAST_CALL_PCB; | |
43 | #else ARGO_DEBUG | |
44 | #define Static static | |
45 | #endif ARGO_DEBUG | |
46 | ||
47 | #include "ecn.h" | |
48 | #include "argoxtwentyfive.h" | |
49 | ||
50 | #if NARGOXTWENTYFIVE > 0 | |
51 | ||
52 | #ifdef KERNEL | |
53 | ||
54 | #include "param.h" | |
55 | #include "systm.h" | |
56 | #include "mbuf.h" | |
57 | #include "protosw.h" | |
58 | #include "socket.h" | |
59 | #include "socketvar.h" | |
60 | #include "errno.h" | |
61 | #include "ioctl.h" | |
c3e97825 | 62 | #include "tsleep.h" |
3b1d357b KS |
63 | |
64 | #include "../net/if.h" | |
65 | #include "../net/netisr.h" | |
66 | #include "../net/route.h" | |
67 | ||
68 | #include "../netiso/iso_errno.h" | |
69 | #include "../netiso/argo_debug.h" | |
70 | #include "../netiso/tp_trace.h" | |
71 | #include "../netiso/iso.h" | |
72 | #include "../netiso/cons.h" | |
73 | #include "../netiso/iso_pcb.h" | |
74 | #include "../netiso/cons_pcb.h" | |
75 | #include "../caif/eicon.h" | |
76 | ||
77 | #ifdef ARGO_DEBUG | |
78 | #define MT_XCONN 0x50 | |
79 | #define MT_XCLOSE 0x51 | |
80 | #define MT_XCONFIRM 0x52 | |
81 | #define MT_XDATA 0x53 | |
82 | #define MT_XHEADER 0x54 | |
83 | #else | |
84 | #define MT_XCONN MT_DATA | |
85 | #define MT_XCLOSE MT_DATA | |
86 | #define MT_XCONFIRM MT_DATA | |
87 | #define MT_XDATA MT_DATA | |
88 | #define MT_XHEADER MT_HEADER | |
89 | #endif ARGO_DEBUG | |
90 | ||
91 | #define DONTCLEAR -1 | |
92 | ||
93 | /********************************************************************* | |
94 | * cons.c - CONS interface to the eicon adapter | |
95 | * Includes connection manager - for (TP, CLNP)/x.25 | |
96 | * | |
97 | * TODO: figure out what resources we might run out of besides mbufs. | |
98 | * If we run out of any of them (including mbufs) close and recycle | |
99 | * lru x% of the connections, for some parameter x. | |
100 | * | |
101 | * There are 4 interfaces from above: | |
102 | * 0) from CLNP: | |
103 | * cons is an interface driver - CLNP calls | |
104 | * cosns_output(ifp, m, dst), a device-type interface output routine | |
105 | * that does some connection management stuff and queues a | |
106 | * request on the eicon driver queue by calling ifp->if_output. | |
107 | * The eicon's ifp structure contains cosns_output as its output routine | |
108 | * rather than ifp_>if_output! Kludge, but we don't have much choice... | |
109 | * X25 connections created in this manner may always be multiplexed | |
110 | * but only with their own kind (not with connections servicing TP | |
111 | * directly.) | |
112 | * co_flags & CONSF_DGM | |
113 | * 1) from TP0: | |
114 | * cons CO network service | |
115 | * TP associates a transport connection with a network connection. | |
116 | * cons_output( isop, m, len, isdgm==0 ) | |
117 | * co_flags == 0 | |
118 | * 2) from TP 4: | |
119 | * It's a datagram service, like clnp is. - even though it calls | |
120 | * cons_output( isop, m, len, isdgm==1 ) | |
121 | * it eventually goes through | |
122 | * cosns_output(ifp, m, dst). | |
123 | * TP4 permits multiplexing (reuse, possibly simultaneously) of the | |
124 | * network connections. | |
125 | * This means that many sockets (many tpcbs) may be associated with | |
126 | * this cons_pcb, hence cannot have a back ptr from cons_pcb to a tpcb. | |
127 | * co_flags & CONSF_DGM | |
128 | * co_socket is null since there may be many sockets that use this copcb. | |
129 | * 3) from user: cons_usrreq(), cons_ctloutput() | |
130 | * cons is a standard transport service interface. | |
131 | * There is a 1-1 correspondence between net connections and sockets. | |
132 | * co_socket points to a socket. | |
133 | * | |
134 | NOTE: | |
135 | streams would really be nice. sigh. | |
136 | NOTE: | |
137 | eicon <--> cons interface: the first mbuf (the ecn_request structure) | |
138 | had better NOT be a cluster. | |
139 | NOTE: | |
140 | PVCs could be handled by config-ing a cons with an address and with the | |
141 | IFF_POINTTOPOINT flag on. This code would then have to skip the | |
142 | connection setup stuff for pt-to-pt links. | |
143 | NOTE: | |
144 | We keep track of the ifp for each connection. Right now this is | |
145 | unnecessary, but just in case someone comes up with some kind | |
146 | of a kludge to allow > 1 eicon to be attached at a time, | |
147 | (i.e., some meaningful netof( a type 37 address ) ), | |
148 | we do keep track of this. | |
149 | ||
150 | ||
151 | *********************************************************************/ | |
152 | ||
153 | #define touch(copcb) copcb->co_ttl = copcb->co_init_ttl | |
154 | ||
155 | #define CONS_IFQMAXLEN 5 | |
156 | ||
157 | #define SET_CHANMASK( isop, chan )\ | |
158 | if( (u_int)(chan) < 32 ) \ | |
159 | (isop)->isop_chanmask = (1<<((chan)-1));\ | |
160 | else \ | |
161 | (isop)->isop_negchanmask = (1<<((256-(chan))-1)) | |
162 | ||
163 | #define ADD_CHANMASK( isop, chan )\ | |
164 | if( (u_int)(chan) < 32 ) \ | |
165 | (isop)->isop_chanmask |= (1<<((chan)-1));\ | |
166 | else \ | |
167 | (isop)->isop_negchanmask |= (1<<((256-(chan))-1)) | |
168 | ||
169 | struct ifnet *consif; /* TO BE REMOVED */ | |
170 | Static int consinit(), consioctl(), consattach(); | |
171 | ||
172 | /* protosw pointers for getting to higher layer */ | |
173 | Static struct protosw *CLNP_proto; | |
174 | Static struct protosw *TP_proto; | |
175 | Static struct protosw *X25_proto; | |
176 | Static int issue_clear_req(); | |
177 | ||
178 | #ifndef PHASEONE | |
179 | extern struct ifaddr *ifa_ifwithnet(); | |
180 | #endif PHASEONE | |
181 | ||
182 | extern struct ifaddr *ifa_ifwithaddr(); | |
183 | ||
184 | Static struct socket dummysocket; /* for use by cosns */ | |
185 | ||
186 | extern struct isopcb tp_isopcb; /* chain of all TP pcbs */ | |
187 | struct isopcb cons_isopcb; /* chain of all cons pcbs */ | |
188 | struct isopcb tp_incoming_pending; /* incoming connections | |
189 | for TP, pending */ | |
190 | ||
191 | struct isopcb *Xpcblist[] = { | |
192 | &cons_isopcb, | |
193 | &tp_incoming_pending, | |
194 | &tp_isopcb, | |
195 | (struct isopcb *)0 | |
196 | }; | |
197 | ||
198 | Static int parse_facil(), NSAPtoDTE(), make_partial_x25_packet(); | |
199 | Static int FACILtoNSAP(), DTEtoNSAP(); | |
200 | Static struct cons_pcb *cons_chan_to_pcb(); | |
201 | ||
202 | #define HIGH_NIBBLE 1 | |
203 | #define LOW_NIBBLE 0 | |
204 | ||
205 | /* | |
206 | * NAME: nibble_copy() | |
207 | * FUNCTION and ARGUMENTS: | |
208 | * copies (len) nibbles from (src_octet), high or low nibble | |
209 | * to (dst_octet), high or low nibble, | |
210 | * src_nibble & dst_nibble should be: | |
211 | * HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble | |
212 | * LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble | |
213 | * RETURNS: VOID | |
214 | */ | |
215 | void | |
216 | nibble_copy( src_octet, src_nibble, dst_octet, dst_nibble, len) | |
217 | register char *src_octet; | |
218 | register char *dst_octet; | |
219 | register unsigned src_nibble; | |
220 | register unsigned dst_nibble; | |
221 | int len; | |
222 | { | |
223 | ||
224 | register i; | |
225 | register unsigned dshift, sshift; | |
226 | ||
227 | IFDEBUG(D_CADDR) | |
228 | printf("nibble_copy ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", | |
229 | src_octet, src_nibble, dst_octet, dst_nibble, len); | |
230 | ENDDEBUG | |
231 | #define SHIFT 0x4 | |
232 | ||
233 | dshift = dst_nibble << 2; | |
234 | sshift = src_nibble << 2; | |
235 | ||
236 | for (i=0; i<len; i++) { | |
237 | /* clear dst_nibble */ | |
238 | *dst_octet &= ~(0xf<< dshift); | |
239 | ||
240 | /* set dst nibble */ | |
241 | *dst_octet |= ( 0xf & (*src_octet >> sshift))<< dshift; | |
242 | ||
243 | dshift ^= SHIFT; | |
244 | sshift ^= SHIFT; | |
245 | src_nibble = 1-src_nibble; | |
246 | dst_nibble = 1-dst_nibble; | |
247 | src_octet += src_nibble; | |
248 | dst_octet += dst_nibble; | |
249 | } | |
250 | IFDEBUG(D_CADDR) | |
251 | printf("nibble_copy DONE\n"); | |
252 | ENDDEBUG | |
253 | } | |
254 | ||
255 | /* | |
256 | * NAME: nibble_match() | |
257 | * FUNCTION and ARGUMENTS: | |
258 | * compares src_octet/src_nibble and dst_octet/dst_nibble for len nibbles. | |
259 | * RETURNS: 0 if they differ, 1 if they are the same. | |
260 | */ | |
261 | int | |
262 | nibble_match( src_octet, src_nibble, dst_octet, dst_nibble, len) | |
263 | register char *src_octet; | |
264 | register char *dst_octet; | |
265 | register unsigned src_nibble; | |
266 | register unsigned dst_nibble; | |
267 | int len; | |
268 | { | |
269 | ||
270 | register i; | |
271 | register unsigned dshift, sshift; | |
272 | u_char nibble_a, nibble_b; | |
273 | ||
274 | IFDEBUG(D_CADDR) | |
275 | printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", | |
276 | src_octet, src_nibble, dst_octet, dst_nibble, len); | |
277 | ENDDEBUG | |
278 | #define SHIFT 0x4 | |
279 | ||
280 | dshift = dst_nibble << 2; | |
281 | sshift = src_nibble << 2; | |
282 | ||
283 | for (i=0; i<len; i++) { | |
284 | nibble_b = ((*dst_octet)>>dshift) & 0xf; | |
285 | nibble_a = ( 0xf & (*src_octet >> sshift)); | |
286 | if( nibble_b != nibble_a ) | |
287 | return 0; | |
288 | ||
289 | dshift ^= SHIFT; | |
290 | sshift ^= SHIFT; | |
291 | src_nibble = 1-src_nibble; | |
292 | dst_nibble = 1-dst_nibble; | |
293 | src_octet += src_nibble; | |
294 | dst_octet += dst_nibble; | |
295 | } | |
296 | IFDEBUG(D_CADDR) | |
297 | printf("nibble_match DONE\n"); | |
298 | ENDDEBUG | |
299 | return 1; | |
300 | } | |
301 | ||
302 | #ifdef ARGO_DEBUG | |
303 | ||
304 | Static | |
305 | dump_copcb(copcb, str) | |
306 | char * str; | |
307 | register struct cons_pcb *copcb; | |
308 | { | |
309 | printf("XPCB DUMP %s\n", str); | |
310 | if (copcb) { | |
311 | printf("\t copcb 0x%x next 0x%x head 0x%x socket 0x%x ifp 0x%x\n", | |
312 | copcb, copcb->co_next, copcb->co_head, copcb->co_socket, copcb->co_ifp); | |
313 | printf("\t channel 0x%x state 0x%x flags 0x%x proto 0x%x\n", | |
314 | copcb->co_channel, copcb->co_state, copcb->co_flags, copcb->co_proto); | |
315 | printf("\t laddr :\n"); | |
316 | dump_isoaddr(&copcb->co_laddr); | |
317 | printf("\t faddr :\n"); | |
318 | dump_isoaddr(&copcb->co_faddr); | |
319 | printf("\tttl 0x%x init_ttl 0x%x pending: %d\n", | |
320 | copcb->co_ttl, copcb->co_init_ttl, copcb->co_pending.ifq_len); | |
321 | } | |
322 | printf("END DUMP\n"); | |
323 | } | |
324 | #endif ARGO_DEBUG | |
325 | ||
326 | /* | |
327 | * FUNCTION : choose_output - chooses between the eicon and loopback. | |
328 | * This MUST be here because the ifp->if_output routine is cosns_output | |
329 | * -- due to our need to look like a device driver for CLNP. sigh. | |
330 | * ARGUMENTS & PURPOSE: (copcb) ptr to a protocol control block for | |
331 | * x.25, (m) is an mbuf ptr. *m is a request destined either | |
332 | * for the eicon driver or for the loopback driver. | |
333 | * RETURNS : whatever error value the 2I or loopback returns. | |
334 | */ | |
335 | Static int | |
336 | choose_output( ifp, m, loop) | |
337 | struct ifnet *ifp; | |
338 | struct mbuf *m; | |
339 | int loop; | |
340 | { | |
341 | int error; | |
342 | ||
343 | if( !m ) | |
344 | return 0; | |
345 | ASSERT(m->m_len != 0); | |
346 | if( loop != 0) | |
347 | error = lpboutput( ifp, m ); | |
348 | else | |
349 | error = ecnoutput( ifp, m ); | |
350 | ||
351 | if (error == 0) | |
352 | ifp->if_opackets ++; | |
353 | else { | |
354 | ifp->if_oerrors ++; | |
355 | IFTRACE(D_CDATA) | |
356 | tptrace( TPPTmisc, | |
357 | "choose_output: ifp m error loop\n", | |
358 | ifp, m, error, loop); | |
359 | ENDTRACE | |
360 | } | |
361 | IFDEBUG(D_CCONS) | |
362 | printf("choose_output returns 0x%x\n", error ); | |
363 | ENDDEBUG | |
364 | return error; | |
365 | } | |
366 | ||
367 | /* | |
368 | **************************** NET PROTOCOL cons *************************** | |
369 | */ | |
370 | ||
371 | /* | |
372 | * NAME: cons_init() | |
373 | * CALLED FROM: | |
374 | * autoconf | |
375 | * FUNCTION: | |
376 | * initialize the protocol | |
377 | */ | |
378 | cons_init() | |
379 | { | |
380 | init_lpb(); | |
381 | consattach(); | |
382 | ||
383 | /* protocol init stuff */ | |
384 | ||
385 | consintrq.ifq_maxlen = IFQ_MAXLEN; | |
386 | consintrq.ifq_head = consintrq.ifq_tail = (struct mbuf *)0; | |
387 | ||
388 | CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM); | |
389 | X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM); | |
390 | TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET); | |
391 | IFDEBUG(D_CCONS) | |
392 | printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n", | |
393 | CLNP_proto, X25_proto, TP_proto); | |
394 | ENDDEBUG | |
395 | ||
396 | cons_isopcb.isop_next = cons_isopcb.isop_prev = &cons_isopcb; | |
397 | tp_incoming_pending.isop_next = tp_incoming_pending.isop_prev = | |
398 | &tp_incoming_pending; | |
399 | } | |
400 | ||
401 | #ifdef notdef | |
402 | ||
403 | /* | |
404 | * NAME: cons_free_lru() | |
405 | * some day CALLED FROM: | |
406 | * wherever we run out of mbufs (not used right yet) | |
407 | * FUNCTION: | |
408 | * get rid of the num least recently used connections and | |
409 | * recycle their mbufs. | |
410 | * NOTE: GROTESQUELY INEFFICIENT needs to be written nicely | |
411 | */ | |
412 | ||
413 | Static | |
414 | cons_free_lru(qty) | |
415 | int qty; | |
416 | { | |
417 | register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist; | |
418 | register struct cons_pcb *copcb; | |
419 | struct cons_pcb Lru; | |
420 | struct cons_pcb *lru; | |
421 | ||
422 | IFDEBUG(D_CCONS) | |
423 | printf("cons_free_lru( 0x%x )\n", qty); | |
424 | ENDDEBUG | |
425 | ||
426 | Lru.co_ttl = X25_TTL; | |
427 | lru = &Lru; | |
428 | ||
429 | while (qty > 1) { /* GROT */ | |
430 | cons_free_lru( 1 ); | |
431 | qty -- ; | |
432 | } | |
433 | ||
434 | for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) { | |
435 | copcb = (struct cons_pcb *)copcb->co_next; | |
436 | while (copcb != *copcblist) { | |
437 | if( copcb->co_ttl < lru->co_ttl ) | |
438 | lru = copcb; | |
439 | copcb = (struct cons_pcb *)copcb->co_next; | |
440 | } | |
441 | } | |
442 | ||
443 | if(lru->co_socket) { | |
444 | soisdisconnected(lru->co_socket); | |
445 | sohasoutofband(lru->co_socket); /* signal */ | |
446 | } | |
447 | ||
448 | cons_clear_and_detach( lru, E_CO_HLI_RESYNC, PRC_TIMXCEED_REASS); | |
449 | } | |
450 | #endif notdef | |
451 | ||
452 | /* | |
453 | * NAME: cons_slowtimo() | |
454 | * CALLED FROM: | |
455 | * the clock | |
456 | * FUNCTION: | |
457 | * get rid of any timed-out cons connections | |
458 | * cons connections get "touched" with every use, meaning the | |
459 | * time-to-live gets reset to its max value w/ every use. | |
460 | * The slowtimo() rtn decrements the time-to-live for each | |
461 | * cons connection. If one of them hits zero ---> zap the connection. | |
462 | * This really only applies to those used for CLNP and TP4. | |
463 | * TP4 keeps the connections open with keepalive. | |
464 | * TODO: | |
465 | * Have this happen ONLY for international connections since | |
466 | * there's no connect time charge for domestic calls. | |
467 | * Make default 5 min; make a user option to change it. | |
468 | * TODO: | |
469 | * Maybe if the ttl gets lower than a certain threshold, move this | |
470 | * copcb to the END of its queue so it doesn't slow down the others. | |
471 | */ | |
472 | ||
473 | cons_slowtimo() | |
474 | { | |
475 | register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist; | |
476 | register struct cons_pcb *copcb; | |
477 | int s = splnet(); | |
478 | int qlen = 0; | |
479 | int qdrops = 0; | |
480 | int nvisited = 0; | |
481 | ||
482 | #ifdef ARGO_DEBUG | |
483 | Static int count; | |
484 | ||
485 | count = 0; | |
486 | #endif ARGO_DEBUG | |
487 | ||
488 | IncStat(co_slowtimo); | |
489 | for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) { | |
490 | #ifdef ARGO_DEBUG | |
491 | if( copcb == (struct cons_pcb *)0 ) { | |
492 | ASSERT( 0 ); | |
493 | panic("TURNING OFF cons_slowtimo()!!! \n"); | |
494 | } | |
495 | #endif ARGO_DEBUG | |
496 | copcb = (struct cons_pcb *)copcb->co_next; | |
497 | while (copcb != *copcblist) { | |
498 | #ifdef ARGO_DEBUG | |
499 | if(++count >50 ) { | |
500 | printf("cons PANIC: slowtimo LOOP\n"); | |
501 | splx(s); | |
502 | return; | |
503 | } | |
504 | #endif ARGO_DEBUG | |
505 | #ifdef notdef | |
506 | if( copcb->co_init_ttl == 0 ) { | |
507 | ASSERT( (struct isopcb *)(*copcblist)==(struct isopcb *)&tp_isopcb ); | |
508 | copcb = (struct cons_pcb *)copcb->co_next; | |
509 | continue; | |
510 | } | |
511 | #endif notdef | |
512 | nvisited ++; | |
513 | ASSERT( copcb != (struct cons_pcb *)0 ); | |
514 | qlen += copcb->co_pending.ifq_len; | |
515 | qdrops += copcb->co_pending.ifq_drops; | |
516 | ||
517 | if( copcb->co_socket) { | |
518 | /* don't want XTS, TP0 connections to be subject to time out */ | |
519 | copcb = (struct cons_pcb *)copcb->co_next; | |
520 | continue; | |
521 | } | |
522 | ||
523 | if( -- (copcb->co_ttl) > 0 ) { | |
524 | copcb = (struct cons_pcb *)copcb->co_next; | |
525 | continue; | |
526 | } | |
527 | ||
528 | IncStat(co_timedout); | |
529 | ||
530 | IFDEBUG(D_CCONN) | |
531 | printf("TIMING OUT chan 0x%x copcb 0x%x flags 0x%x\n", | |
532 | copcb->co_channel, copcb, copcb->co_flags ); | |
533 | ENDDEBUG | |
534 | ||
535 | { | |
536 | register struct cons_pcb * next = | |
537 | (struct cons_pcb *)copcb->co_next; | |
538 | cons_clear_and_detach(copcb, | |
539 | E_CO_HLI_RESYNC, PRC_TIMXCEED_REASS); | |
540 | copcb = next; | |
541 | } | |
542 | } | |
543 | } | |
544 | if(nvisited) { | |
545 | cons_stat.co_avg_qlen = qlen / nvisited; | |
546 | cons_stat.co_avg_qdrop = qdrops / nvisited; | |
547 | cons_stat.co_active = nvisited; | |
548 | } | |
549 | done: | |
550 | splx(s); | |
551 | } | |
552 | ||
553 | DUMP_PCBLIST() | |
554 | { | |
555 | register int i=0; | |
556 | register struct cons_pcb *copcb; | |
557 | register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist; | |
558 | ||
559 | for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) { | |
560 | printf("FOR %d: 0x%x ", ++i, copcb); | |
561 | copcb = (struct cons_pcb *)copcb->co_next; | |
562 | printf(" next 0x%x, *copcblist 0x%x\n", copcb, *copcblist); | |
563 | while (copcb != *copcblist) { | |
564 | ASSERT( copcb != (struct cons_pcb *)0 ); | |
565 | printf("\tCOPCB 0x%x\n", copcb); | |
566 | if( copcb ) | |
567 | dump_buf(copcb, sizeof( *copcb)); | |
568 | else | |
569 | break; | |
570 | copcb = (struct cons_pcb *)copcb->co_next; | |
571 | } | |
572 | } | |
573 | } | |
574 | ||
575 | /* | |
576 | * NAME: cons_pcballoc() | |
577 | * CALLED FROM: | |
578 | * cons_usrreq() when doing PRU_ATTACH, | |
579 | * cons_incoming() when opening a new connection. | |
580 | * FUNCTION and ARGUMENTS: | |
581 | * Allocates a new pcb. | |
582 | * The flags and proto arguments are stashed into the new pcb. | |
583 | * RETURN VALUE: | |
584 | * E* if error, 0 if ok | |
585 | */ | |
586 | Static int | |
587 | cons_pcballoc(so, head, flags, proto, dest) | |
588 | struct socket *so; | |
589 | struct isopcb *head; | |
590 | u_short flags; | |
591 | struct protosw *proto; | |
592 | struct cons_pcb **dest; | |
593 | { | |
594 | int error; | |
595 | register struct cons_pcb *copcb; | |
596 | ||
597 | IFDEBUG(D_CCONN) | |
598 | printf("cons_pcballoc (0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", | |
599 | so, head, flags, proto, dest); | |
600 | ENDDEBUG | |
601 | if(proto == (struct protosw *)0) | |
602 | return EPROTONOSUPPORT; | |
603 | ||
604 | if( ( error = iso_pcballoc(so, head) ) == EOK ) { | |
605 | /* Have allocated a cleared mbuf */ | |
606 | ||
607 | copcb = (struct cons_pcb *)so->so_pcb; | |
608 | copcb->co_ttl = copcb->co_init_ttl = X25_TTL; | |
609 | copcb->co_flags = flags; | |
610 | copcb->co_proto = proto; | |
611 | copcb->co_pending.ifq_maxlen = CONS_IFQMAXLEN; | |
612 | copcb->co_myself = copcb; | |
613 | ||
614 | if (so == &dummysocket) | |
615 | copcb->co_socket = (struct socket *)0; | |
616 | ||
617 | *dest = copcb; | |
618 | } | |
619 | done: | |
620 | IFDEBUG(D_CCONN) | |
621 | printf("cons_pcballoc returns 0x%x: DUMP\n", copcb); | |
622 | dump_buf( copcb, sizeof(*copcb)); | |
623 | ENDDEBUG | |
624 | if( (flags & CONSF_ICRE) == 0) { | |
625 | struct dte_addr *dtea = &(*dest)->co_peer_dte; | |
626 | int len; | |
627 | ||
628 | error = iso_8208snparesolve(&(*dest)->co_faddr, dtea, &len); | |
629 | ASSERT(error == 0); | |
630 | ASSERT(len == sizeof(struct dte_addr)); | |
631 | } | |
632 | ||
633 | return error; | |
634 | } | |
635 | ||
636 | /* | |
637 | * NAME: cons_connect() | |
638 | * CALLED FROM: | |
639 | * cons_usrreq() when opening a new connection. | |
640 | * FUNCTION anD ARGUMENTS: | |
641 | * Figures out which device to use, finding a route if one doesn't | |
642 | * already exist. | |
643 | * Builds an eicon connection request and gives it to the device. | |
644 | * RETURN VALUE: | |
645 | * returns E* | |
646 | */ | |
647 | Static int | |
648 | cons_connect( copcb ) | |
649 | register struct cons_pcb *copcb; | |
650 | { | |
651 | register struct eicon_request *ecnrq; | |
652 | register struct mbuf *m; | |
653 | int error = 0; | |
654 | struct ifaddr *ifa; | |
655 | ||
656 | IFDEBUG(D_CCONN) | |
657 | printf("cons_connect( 0x%x ) : ifp 0x%x\npeer: ", copcb, copcb->co_ifp); | |
658 | dump_isoaddr(&copcb->co_faddr); | |
659 | printf("\nmyaddr: "); | |
660 | dump_isoaddr(&copcb->co_laddr); | |
661 | printf("\n" ); | |
662 | ENDDEBUG | |
663 | ||
664 | /* PHASE 2: this call is OK */ | |
665 | if( ifa = ifa_ifwithaddr(&copcb->co_faddr ) ) { | |
666 | /* foreign address is me */ | |
667 | copcb->co_ifp = ifa->ifa_ifp; | |
668 | IFDEBUG(D_CCONN) | |
669 | printf("cons_connect: after if_withaddr copcb->co_ifp 0x%x\n", | |
670 | copcb->co_ifp); | |
671 | ENDDEBUG | |
672 | ||
673 | if( (ifa->ifa_ifp->if_flags&(IFF_LOOPBACK|IFF_UP)) == | |
674 | (IFF_LOOPBACK|IFF_UP)) { | |
675 | copcb->co_flags |= CONSF_LOOPBACK; | |
676 | } | |
677 | bcopy((caddr_t)&ifa->ifa_addr, (caddr_t)&copcb->co_laddr, | |
678 | sizeof(struct sockaddr)); | |
679 | } | |
680 | IFDEBUG(D_CCONN) | |
681 | printf("cons_connect: co_flags 0x%x\n", copcb->co_flags); | |
682 | if( ifa ) { | |
683 | printf(" cons_connect withaddr returns %s\n", | |
684 | copcb->co_ifp->if_name); | |
685 | } | |
686 | ENDDEBUG | |
687 | else if ( copcb->co_ifp == (struct ifnet *)0 ) { | |
688 | #ifdef PHASEONE | |
689 | /* | |
690 | * We need to get the local nsap address. | |
691 | * First, route to the destination. This will provide us with | |
692 | * an ifp. Second, determine which local address linked on | |
693 | * that ifp is appropriate | |
694 | */ | |
695 | struct sockaddr_iso *first_hop; /* filled by clnp_route */ | |
696 | struct iso_addr *localaddr, *clnp_srcaddr(); | |
697 | ||
698 | if (error = clnp_route(&copcb->co_faddr, | |
699 | &((struct isopcb *)copcb)->isop_route, /* flags */0, | |
700 | &first_hop, &copcb->co_ifp)) | |
701 | goto bad; | |
702 | ||
703 | /* determine local address based upon ifp */ | |
704 | if ((localaddr = clnp_srcaddr(copcb->co_ifp, | |
705 | &first_hop->siso_addr)) == NULL) { | |
706 | error = ENETUNREACH; | |
707 | goto bad; | |
708 | } | |
709 | copcb->co_laddr.siso_family = AF_ISO; | |
710 | copcb->co_laddr.siso_addr = *localaddr; | |
711 | #else | |
712 | /* Foreign addr isn't me (lpb). If still don't have an ifp or have | |
713 | * an ifp but don't know its address, look for a route | |
714 | */ | |
715 | if( ifa = ifa_ifwithnet(&copcb->co_faddr) ) { | |
716 | copcb->co_ifp = ifa->ifa_ifp; | |
717 | IFDEBUG(D_CCONN) | |
718 | printf(" cons_connect withnet returns %s\n", | |
719 | copcb->co_ifp->if_name); | |
720 | ENDDEBUG | |
721 | } else { | |
722 | printf("cons PANIC: connect: can't find SNPA \n"); | |
723 | error = ENETUNREACH; | |
724 | goto bad; | |
725 | } | |
726 | #endif PHASEONE | |
727 | } | |
728 | #ifndef PHASEONE | |
729 | if( ifa == (struct ifaddr *)0 ) { | |
730 | struct ifaddr * iso_ifwithidi(); | |
731 | ||
732 | if( ifa = iso_ifwithidi(&copcb->co_faddr) ) { | |
733 | copcb->co_ifp = ifa->ifa_ifp; | |
734 | IFDEBUG(D_CCONN) | |
735 | printf(" cons_connect withnet returns %s\n", | |
736 | copcb->co_ifp->if_name); | |
737 | ENDDEBUG | |
738 | } else { | |
739 | printf("cons PANIC: connect: can't find SNPA \n"); | |
740 | error = ENETUNREACH; | |
741 | goto bad; | |
742 | } | |
743 | } | |
744 | bcopy((caddr_t)&ifa->ifa_addr, (caddr_t)&copcb->co_laddr, | |
745 | sizeof(struct sockaddr)); | |
746 | #endif PHASEONE | |
747 | ||
748 | copcb->co_state = CONNECTING; | |
749 | ||
750 | ASSERT( copcb->co_ifp != (struct ifnet *) 0); | |
751 | if ( copcb->co_ifp == (struct ifnet *)0 ) { | |
752 | error = ENETUNREACH; | |
753 | goto bad; | |
754 | } | |
755 | ||
756 | m = m_getclr(M_DONTWAIT, MT_XCONN); | |
757 | if( !m ) { | |
758 | copcb->co_ifp->if_oerrors ++; | |
759 | error = ENOBUFS; | |
760 | goto bad; | |
761 | } | |
762 | m->m_len = sizeof(struct eicon_request); | |
763 | ||
764 | ecnrq = mtod(m, struct eicon_request *); | |
765 | ||
766 | copcb->co_myself = copcb; | |
767 | ecnrq->e_pcb = (caddr_t)copcb; | |
768 | #ifdef ARGO_DEBUG | |
769 | LAST_CALL_PCB = (unsigned) ecnrq->e_pcb; | |
770 | #endif ARGO_DEBUG | |
771 | ecnrq->e_cmd = ECN_CALL; | |
772 | ecnrq->e_vc = 0; /* mbz ? */ | |
773 | ecnrq->e_info = 0; /* mbz */ | |
774 | ||
775 | /* get data buffer */ | |
776 | { struct mbuf *n; | |
777 | ||
778 | MGET(n, M_DONTWAIT, MT_XCONN); | |
779 | if( n==MNULL ) { | |
780 | copcb->co_ifp->if_oerrors ++; | |
781 | error = ENOBUFS; | |
782 | goto bad; | |
783 | } | |
784 | e_data(ecnrq) = n; /* e_data is really dtom(ecnrq)->m_next */ | |
785 | } | |
786 | ||
787 | IFDEBUG(D_CCONN) | |
788 | printf( | |
789 | "calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", | |
790 | &copcb->co_laddr, &copcb->co_faddr, | |
791 | copcb->co_proto->pr_protocol, | |
792 | e_data(ecnrq), | |
793 | copcb->co_flags & CONSF_XTS); | |
794 | ENDDEBUG | |
795 | if( error = make_partial_x25_packet( copcb, e_data(ecnrq)) ) { | |
796 | copcb->co_ifp->if_oerrors ++; | |
797 | m_freem(m); | |
798 | goto bad; | |
799 | } | |
800 | ||
801 | IncStat(co_call); | |
802 | ||
803 | IFDEBUG(D_CDUMP_REQ) | |
804 | printf("cons_connect ecnrq:\n"); | |
805 | dump_buf(ecnrq, sizeof(*ecnrq)); | |
806 | ENDDEBUG | |
807 | ||
808 | ASSERT( copcb->co_channel == 0); | |
809 | if( copcb->co_channel != 0) { | |
810 | printf("cons_connect PANIC: channel is 0x%x\n", copcb->co_channel); | |
811 | } | |
812 | ||
813 | error = choose_output(copcb->co_ifp, m, copcb->co_flags & CONSF_LOOPBACK); | |
814 | ||
815 | switch( error ) { | |
816 | case 0: /* ok */ | |
817 | break; | |
818 | default: /* problem */ | |
819 | printf("cons: PANIC: if_output returns 0x%x\n", error); | |
820 | cons_clear_and_detach( copcb, DONTCLEAR, PRC_ROUTEDEAD); | |
821 | } | |
822 | ||
823 | bad: | |
824 | IFTRACE(D_CDATA) | |
825 | tptrace( TPPTmisc, | |
826 | "cons_connect: choose (copcb m) returned error\n", | |
827 | copcb, m, error, 0); | |
828 | ENDTRACE | |
829 | return error; | |
830 | } | |
831 | ||
832 | /* | |
833 | * NAME: cons_find() | |
834 | * CALLED FROM: | |
835 | * cosns_output1() thus: | |
836 | * cons_find( CONSF_DGM, dst, proto, 0, 0) where | |
837 | * proto is one of { TP_proto, CLNP_proto } | |
838 | * FUNCTION and ARGUMENTS: | |
839 | * Looks through list of connections for the destination, | |
840 | * for one marked for the use indicated by flags. | |
841 | * If none found, opens up a new connection. | |
842 | * These connections will be eliminated by : | |
843 | * a) slowtimo timer, or | |
844 | * b) the need for a new connection, when we've run out of resources. | |
845 | * The argument flags describes the type of pcb we want - may | |
846 | * specify multiplexing-ok, datagram use, etc. | |
847 | * The argument proto points the the higher layer protocol that | |
848 | * will be using this connection. | |
849 | * RETURN VALUE: | |
850 | * returns a ptr to a pcb whose characteristics match those | |
851 | * described by (flags, proto) | |
852 | */ | |
853 | ||
854 | Static struct cons_pcb * | |
855 | cons_find(flags, dst, proto, addl_criteria, mask) | |
856 | u_int flags, mask; | |
857 | struct sockaddr_iso *dst; | |
858 | struct protosw *proto; | |
859 | int (*addl_criteria)(); | |
860 | { | |
861 | register struct cons_pcb *copcb; | |
862 | register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist; | |
863 | int s = splnet(); /* or whatever, for the device! */ | |
864 | struct dte_addr dest_dte; | |
865 | int dummy; | |
866 | ||
867 | struct copcb_descriptor { | |
868 | int xd_qlen; | |
869 | struct cons_pcb *xd_pcb; | |
870 | } next_best = { | |
871 | 0, (struct cons_pcb *)0 | |
872 | }; | |
873 | ||
874 | IFDEBUG(D_CFIND) | |
875 | printf("cons_find( flags 0x%x proto 0x%x) ", flags, proto); | |
876 | ENDDEBUG | |
877 | ||
878 | if ( iso_8208snparesolve(dst, &dest_dte, &dummy)) { | |
879 | ASSERT(0); | |
880 | return (struct cons_pcb *)0; /* error */ | |
881 | } | |
882 | ASSERT(dummy == sizeof(struct dte_addr)); | |
883 | ||
884 | for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) { | |
885 | copcb = (struct cons_pcb *)copcb->co_next; | |
886 | while (copcb != *copcblist) { | |
887 | IFDEBUG(D_CFIND) | |
888 | printf( | |
889 | "cons_find: chan 0x%x flags 0x%x proto 0x%x state 0x%x \n", | |
890 | copcb->co_channel, copcb->co_flags, copcb->co_proto, | |
891 | copcb->co_state); | |
892 | ENDDEBUG | |
893 | /* | |
894 | * if flags is a subset of the bits in co_flags, it will suffice | |
895 | */ | |
896 | if( ((copcb->co_flags & flags) == flags ) && | |
897 | /* PHASE2: where do we get the mask if we use nsaps ???? | |
898 | * If dte addresses are used, then use | |
899 | * nibble compare otherwise...??? | |
900 | */ | |
901 | #ifdef notdef | |
902 | iso_addrmatch1(&(copcb->co_faddr.siso_addr), &(dst->siso_addr)) | |
903 | #else | |
904 | dest_dte.dtea_niblen == copcb->co_peer_dte.dtea_niblen && | |
905 | nibble_match( (char *)&(copcb->co_peer_dte.dtea_addr), | |
906 | HIGH_NIBBLE, (char *)dest_dte.dtea_addr, | |
907 | HIGH_NIBBLE, dest_dte.dtea_niblen) | |
908 | #endif notdef | |
909 | && | |
910 | (copcb->co_proto == proto) && | |
911 | (copcb->co_state >= MIN_USABLE_STATE)) { | |
912 | IFDEBUG(D_CFIND) | |
913 | printf( | |
914 | "cons_find: add'l criteria...\n" ); | |
915 | ENDDEBUG | |
916 | if((copcb->co_state != OPEN) && | |
917 | (next_best.xd_qlen > copcb->co_pending.ifq_len)) { | |
918 | next_best.xd_pcb = copcb; | |
919 | next_best.xd_qlen = copcb->co_pending.ifq_len; | |
920 | } | |
921 | if( !addl_criteria || (*addl_criteria)(copcb, mask) ) { | |
922 | goto found; /* have to break out of 2 loops */ | |
923 | } | |
924 | } | |
925 | copcb = (struct cons_pcb *)copcb->co_next ; | |
926 | } | |
927 | } | |
928 | #ifdef notdef | |
929 | /* TODO: | |
930 | * have a limit of the number of calls per desitination. | |
931 | * If we didn't find one already open AND our limit for this | |
932 | * destination hasn't been reached, return 0 'cause | |
933 | * then the caller will open a new one. | |
934 | * Otherwise return next_best. | |
935 | * To do this we need some sort of per-destination info. | |
936 | * Could go into the directory service. Oh, grotesque. | |
937 | */ | |
938 | #endif notdef | |
939 | if( copcb == (struct cons_pcb *)0 ) { | |
940 | copcb = next_best.xd_pcb; /* may be zero too */ | |
941 | IFDEBUG(D_CFIND) | |
942 | printf("NEXT_BEST! \n"); | |
943 | dump_copcb(copcb, "find: next_best"); | |
944 | ENDDEBUG | |
945 | } | |
946 | found: | |
947 | ||
948 | splx(s); | |
949 | ||
950 | IFDEBUG(D_CFIND) | |
951 | printf("returns 0x%x \n", copcb); | |
952 | ENDDEBUG | |
953 | return copcb; | |
954 | } | |
955 | ||
956 | ||
957 | /* | |
958 | * NAME: issue_clear_req() | |
959 | * CALLED FROM: | |
960 | * cons_clear() and wherever we get an error from x.25 that makes us | |
961 | * want to close the vc on which it came, but don't have | |
962 | * a copcb assoc. with that vc. | |
963 | * FUNCTION and ARGUMENTS: | |
964 | * Creates an eicon_request for a clear request, returns it in an mbuf. | |
965 | * (chan) is the channel on which to do the clear, (reason) is the | |
966 | * clear reason(diagnostic). | |
967 | * RETURN VALUE: | |
968 | * returns E* | |
969 | */ | |
970 | Static int | |
971 | issue_clear_req(chan, reason, ifp, loop) | |
972 | u_char chan, reason; | |
973 | struct ifnet *ifp; | |
974 | int loop; | |
975 | { | |
976 | register struct mbuf *m; | |
977 | register struct mbuf *cdm; | |
978 | register struct eicon_request *ecnrq; | |
979 | struct e_clear_data *ecd; | |
980 | ||
981 | IFDEBUG(D_CCONN) | |
982 | printf("issue_clear_req(0x%x, 0x%x, 0x%x, 0x%x)\n", | |
983 | chan, reason, ifp, loop); | |
984 | ENDDEBUG | |
985 | m = m_getclr(M_DONTWAIT, MT_XCLOSE); | |
986 | if( !m ) { | |
987 | return ENOBUFS; | |
988 | } | |
989 | m->m_len = sizeof(struct eicon_request); | |
990 | ecnrq = mtod(m, struct eicon_request *); | |
991 | ecnrq->e_cmd = ECN_CLEAR; | |
992 | ecnrq->e_vc = chan & 0xff; | |
993 | /* | |
994 | * see p. 149 of 8208 for reasons (diagnostic codes) | |
995 | */ | |
996 | MGET(cdm, M_DONTWAIT, MT_XCLOSE); | |
997 | if( !cdm ) { | |
998 | m_freem(m); | |
999 | return ENOBUFS; | |
1000 | } | |
1001 | cdm->m_len = sizeof(struct e_clear_data); /* cause, diagnostic */ | |
1002 | e_data(ecnrq) = cdm; | |
1003 | ||
1004 | ecd = mtod(cdm, struct e_clear_data *); | |
1005 | ecd->ecd_cause = 0x0; /* DTE initiated, diagnostic tells more */ | |
1006 | ecd->ecd_diagnostic = (u_char)reason; | |
1007 | ||
1008 | IncStat(co_clear_out); | |
1009 | return choose_output(ifp, m, loop); | |
1010 | } | |
1011 | ||
1012 | ||
1013 | /* | |
1014 | * NAME: cons_clear() | |
1015 | * CALLED FROM: | |
1016 | * cons_usrreq(), PRU_DISCONNECT, | |
1017 | * cons_slowtimo(), cons_free_lru() | |
1018 | * FUNCTION and ARGUMENTS: | |
1019 | * Builds a clear request for the connection represented by copcb, | |
1020 | * gives it to the device. | |
1021 | * ECN_CLEAR(request) takes e_vc only, returns adr_status. | |
1022 | * RETURN VALUE: | |
1023 | */ | |
1024 | ||
1025 | Static int | |
1026 | cons_clear( copcb, reason) | |
1027 | register struct cons_pcb *copcb; | |
1028 | u_char reason; | |
1029 | { | |
1030 | register struct mbuf *m; | |
1031 | int error; | |
1032 | ||
1033 | IFDEBUG(D_CCONN) | |
1034 | printf("cons_clear(0x%x, 0x%x)\n", copcb, reason); | |
1035 | ENDDEBUG | |
1036 | if( !copcb) { | |
1037 | printf("cons PANIC: clear: No copcb\n"); | |
1038 | return 0; | |
1039 | } | |
1040 | while( copcb->co_pending.ifq_len > 0 ) { | |
1041 | register int s = splimp(); | |
1042 | ||
1043 | IF_DEQUEUE( &copcb->co_pending, m ); | |
1044 | splx(s); | |
1045 | m_freem(m); | |
1046 | } | |
1047 | if( (copcb->co_state == CLOSED) || (copcb->co_state == CLOSING) ) | |
1048 | return 0; | |
1049 | ||
1050 | #ifdef ARGO_DEBUG | |
1051 | if( copcb->co_state == CONNECTING) { | |
1052 | IFDEBUG(D_CCONN) | |
1053 | dump_copcb(copcb, "clear"); | |
1054 | ENDDEBUG | |
1055 | } else if( (copcb->co_channel == 0) || (copcb->co_channel == X_NOCHANNEL) ) { | |
1056 | IFDEBUG(D_CCONN) | |
1057 | dump_copcb(copcb, "clear"); | |
1058 | ENDDEBUG | |
1059 | } | |
1060 | #endif ARGO_DEBUG | |
1061 | ||
1062 | copcb->co_state = CLOSING; | |
1063 | ||
1064 | IFDEBUG(D_CCONN) | |
1065 | printf("cons_clear: channel 0x%x copcb 0x%x dst: ", | |
1066 | copcb->co_channel, copcb); | |
1067 | dump_isoaddr(&copcb->co_faddr); | |
1068 | dump_copcb(copcb, "clear"); | |
1069 | ENDDEBUG | |
1070 | ||
1071 | error = issue_clear_req(copcb->co_channel, reason, copcb->co_ifp, | |
1072 | copcb->co_flags & CONSF_LOOPBACK); | |
1073 | copcb->co_channel = X_NOCHANNEL; | |
1074 | copcb->co_state = CLOSED; | |
1075 | return error; | |
1076 | } | |
1077 | ||
1078 | ||
1079 | /* | |
1080 | * NAME: cons_senddata() | |
1081 | * CALLED FROM: | |
1082 | * cons_output(), consoutput(), consintr() | |
1083 | * FUNCTION and ARGUMENTS: | |
1084 | * issued a data (write) command - if the device isn't ready, | |
1085 | * it enqueues the command on a per-connection queue. | |
1086 | * RETURN VALUE: | |
1087 | * ENOBUFS | |
1088 | * Is responsible for freeing m0! | |
1089 | * | |
1090 | * ECN_SEND (write) | |
1091 | */ | |
1092 | ||
1093 | Static int | |
1094 | cons_senddata(copcb, m0) | |
1095 | register struct cons_pcb *copcb; | |
1096 | struct mbuf *m0; | |
1097 | { | |
1098 | register struct mbuf *m; | |
1099 | register struct eicon_request *ecnrq; | |
1100 | int s; | |
1101 | ||
1102 | IFDEBUG(D_CDATA) | |
1103 | printf("cons_senddata( 0x%x, m 0x%x ) chan 0x%x", | |
1104 | copcb, m0, copcb->co_channel ); | |
1105 | printf(" co_lport 0x%x\n", copcb->co_lport); | |
1106 | ENDDEBUG | |
1107 | if( m0 == MNULL ) | |
1108 | return; | |
1109 | ASSERT( m0->m_len > 0); | |
1110 | if( m0->m_len <= 0) { | |
1111 | printf("cons_senddata : BAD MLEN? 0x%x", m0->m_len); | |
1112 | } | |
1113 | ||
1114 | touch(copcb); | |
1115 | ||
1116 | if( (copcb->co_state == CONNECTING) || (copcb->co_state == ACKWAIT) ) { | |
1117 | IFDEBUG(D_CDATA) | |
1118 | printf("senddata PUTTING ON PENDING Q copcb 0x%x state 0x%x\n", | |
1119 | copcb, copcb->co_state); | |
1120 | ENDDEBUG | |
1121 | s = splimp(); | |
1122 | if (IF_QFULL(&copcb->co_pending)) { | |
1123 | IFDEBUG(D_CDATA) | |
1124 | printf("senddata DROPPING m0 0x%x\n", m0); | |
1125 | ENDDEBUG | |
1126 | IF_DROP(&copcb->co_pending); | |
1127 | if(copcb->co_ifp) { | |
1128 | copcb->co_ifp->if_snd.ifq_drops ++; | |
1129 | } | |
1130 | IncStat(co_Xdrops); | |
1131 | copcb->co_ifp->if_oerrors ++; | |
1132 | splx(s); | |
1133 | m_freem (m0); | |
1134 | ||
1135 | if( copcb->co_proto && copcb->co_proto->pr_ctlinput ) { | |
1136 | (*copcb->co_proto->pr_ctlinput)(PRC_QUENCH, | |
1137 | (struct sockaddr_iso *)&copcb->co_faddr, | |
1138 | (caddr_t)copcb); | |
1139 | ||
1140 | return 0; | |
1141 | } else | |
1142 | return E_CO_QFULL; | |
1143 | } | |
1144 | IFDEBUG(D_CDATA) | |
1145 | printf("Putting 0x%x on 0x%x->pending Q\n", m0, copcb); | |
1146 | ENDDEBUG | |
1147 | IF_ENQUEUE( &copcb->co_pending, m0 ); | |
1148 | splx(s); | |
1149 | return 0; | |
1150 | } | |
1151 | if(copcb->co_channel == 0 ) { | |
1152 | return E_CO_CHAN; | |
1153 | } | |
1154 | ASSERT( copcb->co_state == OPEN); | |
1155 | ||
1156 | m = m_getclr(M_DONTWAIT, MT_XDATA); | |
1157 | if( !m ) { | |
1158 | copcb->co_ifp->if_oerrors ++; | |
1159 | m_freem (m0); | |
1160 | return ENOBUFS; | |
1161 | } | |
1162 | m->m_len = sizeof(struct eicon_request); | |
1163 | ecnrq = mtod(m, struct eicon_request *); | |
1164 | ecnrq->e_pcb = (caddr_t)copcb; | |
1165 | if( copcb->co_myself != copcb ) { | |
1166 | struct mbuf *mm; | |
1167 | /* TODO: REMOVE THIS DEBUGGING HACK */ | |
1168 | ASSERT(0); | |
1169 | printf("BAD e_pcb from HL (0x%x,0x%x)\n", copcb, copcb->co_myself); | |
1170 | mm = dtom( copcb ); | |
1171 | if(mm->m_type == MT_FREE) | |
1172 | printf("FREED MBUF!\n"); | |
1173 | return ENETDOWN; | |
1174 | } | |
1175 | ASSERT( copcb->co_channel != 0); | |
1176 | ASSERT( copcb->co_channel != X_NOCHANNEL); | |
1177 | ecnrq->e_vc = (copcb->co_channel & 0xff); | |
1178 | ecnrq->e_cmd = ECN_SEND; | |
1179 | e_data(ecnrq) = m0; | |
1180 | { | |
1181 | /* TODO: REMOVE THIS DEBUGGING HACK */ | |
1182 | struct mbuf *thedata = e_data(ecnrq); | |
1183 | u_int *firstint = mtod( thedata, u_int *); | |
1184 | ||
1185 | if( (*firstint & 0xff000000) != 0x81000000 ) { | |
1186 | /* not clnp */ | |
1187 | switch( ((*firstint) & 0x00ff0000) >> 20 ) { | |
1188 | case 0x1: | |
1189 | case 0x2: | |
1190 | case 0x3: | |
1191 | case 0x6: | |
1192 | case 0x7: | |
1193 | case 0x8: | |
1194 | case 0xc: | |
1195 | case 0xd: | |
1196 | case 0xe: | |
1197 | case 0xf: | |
1198 | break; | |
1199 | default: | |
1200 | printf(" ECN_SEND! BAD DATA\n" ); | |
1201 | dump_buf( thedata, 20 + 12 ); | |
1202 | m_freem( m0 ); | |
1203 | return ENETDOWN; | |
1204 | } | |
1205 | } | |
1206 | } | |
1207 | ||
1208 | ecnrq->e_info = 0; | |
1209 | ||
1210 | IFDEBUG(D_CDUMP_REQ) | |
1211 | printf("senddata ecnrq\n"); | |
1212 | ENDDEBUG | |
1213 | IncStat(co_send); | |
1214 | ||
1215 | ASSERT( copcb->co_state == OPEN ); | |
1216 | copcb->co_state = ACKWAIT; | |
1217 | ||
1218 | if( copcb->co_myself != copcb ) { | |
1219 | struct mbuf *mm; | |
1220 | /* TODO: REMOVE this and all mention of co_myself */ | |
1221 | ASSERT(0); | |
1222 | printf("BAD e_pcb TO THE BOARD ecn (0x%x) cmd 0x%x\n", | |
1223 | ecnrq->e_pcb, ecnrq->e_cmd); | |
1224 | mm = dtom( copcb ); | |
1225 | if(mm->m_type == MT_FREE) | |
1226 | printf("FREED MBUF!\n"); | |
1227 | dump_buf (ecnrq, sizeof (*ecnrq)); | |
1228 | return ENETDOWN; | |
1229 | } | |
1230 | ||
1231 | return | |
1232 | choose_output(copcb->co_ifp, dtom(ecnrq), copcb->co_flags&CONSF_LOOPBACK); | |
1233 | } | |
1234 | ||
1235 | /* | |
1236 | * NAME: cons_send_on_vc() | |
1237 | * CALLED FROM: | |
1238 | * tp_error_emit() | |
1239 | * FUNCTION and ARGUMENTS: | |
1240 | * Take a packet(m0), of length (datalen) from tp and | |
1241 | * send it on the channel (chan). | |
1242 | * | |
1243 | * RETURN VALUE: | |
1244 | * whatever (E*) is returned form the net layer output routine. | |
1245 | */ | |
1246 | int | |
1247 | cons_send_on_vc(chan, m, datalen) | |
1248 | int chan; | |
1249 | struct mbuf *m; | |
1250 | int datalen; | |
1251 | { | |
1252 | struct cons_pcb *copcb = (struct cons_pcb *)0; | |
1253 | ||
1254 | if(m == MNULL) | |
1255 | return; | |
1256 | ||
1257 | if((copcb = | |
1258 | #ifdef ARGO_DEBUG | |
1259 | cons_chan_to_pcb( chan, __LINE__ ) | |
1260 | #else ARGO_DEBUG | |
1261 | cons_chan_to_pcb( chan ) | |
1262 | #endif ARGO_DEBUG | |
1263 | ) == (struct cons_pcb *)0 ) | |
1264 | return E_CO_CHAN; | |
1265 | IFDEBUG(D_CCONS) | |
1266 | printf("cons_send_on_vc m 0x%x m_len 0x%x\n", m, m->m_len); | |
1267 | ENDDEBUG | |
1268 | return cons_senddata( copcb, m); | |
1269 | } | |
1270 | ||
1271 | /* | |
1272 | * NAME: cons_output() | |
1273 | * CALLED FROM: | |
1274 | * tpiso_output(), can have whatever interface we want it to... | |
1275 | * tpiso_output() decides whether to give a packet to CLNP or to | |
1276 | * cons; if the latter, it calls this routine. | |
1277 | * FUNCTION and ARGUMENTS: | |
1278 | * tp has alloc-ed a pcb - but it may not be open. | |
1279 | * some classes of tp may allow multiplexing, in which | |
1280 | * case, you may choose to send the data on ANOTHER cons connection. | |
1281 | * This decides which net connection to use, opens one if necessary. | |
1282 | * Then it sends the data. | |
1283 | */ | |
1284 | ||
1285 | cons_output(isop, m, len, isdgm) | |
1286 | struct isopcb *isop; | |
1287 | struct mbuf *m; | |
1288 | int len; | |
1289 | int isdgm; | |
1290 | { | |
1291 | struct cons_pcb *copcb = (struct cons_pcb *)0; | |
1292 | int error; | |
1293 | int s = splnet(); | |
1294 | ||
1295 | IFDEBUG(D_CCONS) | |
1296 | printf("cons_output( isop 0x%x, m 0x%x, len 0x%x, dgm 0x%x )\n", | |
1297 | isop,m,len, isdgm); | |
1298 | ENDDEBUG | |
1299 | ||
1300 | if( m == MNULL ) | |
1301 | return 0; | |
1302 | ASSERT(m->m_len > 0); | |
1303 | if( isdgm ) { | |
1304 | error = cosns_output1(0, m, &isop->isop_faddr, TP_proto, isop); | |
1305 | IFDEBUG(D_CDATA) | |
1306 | if(error) | |
1307 | printf("cosns_output1 RETURNS ERROR 0x%x\n", error); | |
1308 | ENDDEBUG | |
1309 | return error; | |
1310 | } | |
1311 | ||
1312 | if( isop->isop_chanmask || isop->isop_negchanmask) { | |
1313 | register int mask = isop->isop_chanmask; | |
1314 | register int chan = 1; | |
1315 | ||
1316 | if( mask == 0) | |
1317 | mask = isop->isop_negchanmask; | |
1318 | ||
1319 | for ( chan=1; (mask & 1)==0; chan++,mask>>=1 ) ; | |
1320 | ||
1321 | if( isop->isop_chanmask == 0 ) | |
1322 | chan = -chan; | |
1323 | ||
1324 | IFDEBUG(D_CCONS) | |
1325 | printf( | |
1326 | "cons_output: isop 0x%x cmask 0x%x negmask 0x%x, chan 0x%x\n", | |
1327 | isop, isop->isop_chanmask, isop->isop_negchanmask, chan); | |
1328 | ENDDEBUG | |
1329 | ASSERT( chan != 0); | |
1330 | #ifdef ARGO_DEBUG | |
1331 | copcb = cons_chan_to_pcb( chan, __LINE__ ); | |
1332 | #else ARGO_DEBUG | |
1333 | copcb = cons_chan_to_pcb( chan ); | |
1334 | #endif ARGO_DEBUG | |
1335 | } | |
1336 | if( copcb == (struct cons_pcb *)0 ) { | |
1337 | /* get a new one */ | |
1338 | ||
1339 | if(( error = cons_pcballoc(&dummysocket, &cons_isopcb, CONSF_OCRE, | |
1340 | TP_proto, &copcb)) != EOK ) { | |
1341 | IFDEBUG(D_CCONS) | |
1342 | printf("cosns_output: no copcb; returns 0x%x\n", error); | |
1343 | ENDDEBUG | |
1344 | (void) m_freem (m); | |
1345 | splx(s); | |
1346 | return error ; | |
1347 | } | |
1348 | ||
1349 | /* abbreviated form of iso_pcbconnect(): */ | |
1350 | bcopy((caddr_t)&isop->isop_faddr, (caddr_t)&copcb->co_faddr, | |
1351 | sizeof(struct sockaddr_iso)); | |
1352 | ||
1353 | if ( error = cons_connect( copcb ) ) { /* if it doesn't work */ | |
1354 | /* oh, dear, throw packet away */ | |
1355 | remque((struct isopcb *)copcb); | |
1356 | (void) m_free(dtom(copcb)); | |
1357 | (void) m_freem( m ); | |
1358 | splx(s); | |
1359 | return error; | |
1360 | } | |
1361 | ||
1362 | if( copcb->co_socket ) { | |
1363 | while( (copcb->co_state != OPEN) && | |
1364 | !(error = copcb->co_socket->so_error) ) { | |
1365 | IFDEBUG(D_CCONS) | |
1366 | printf( | |
1367 | "SLEEP1 copcb 0x%x isop 0x%x state 0x%x chan 0x%x mask 0x%x neg 0x%x\n", | |
1368 | copcb, isop, copcb->co_state, copcb->co_channel, | |
1369 | ((struct isopcb *)isop)->isop_chanmask, | |
1370 | ((struct isopcb *)isop)->isop_negchanmask | |
1371 | ); | |
1372 | ENDDEBUG | |
c3e97825 MT |
1373 | tsleep( (caddr_t)&copcb->co_state, PZERO+1, |
1374 | SLP_ISO_CONSOUT, 0); | |
3b1d357b KS |
1375 | IFDEBUG(D_CCONS) |
1376 | printf("AFTER SLEEP 1 chan 0x%x chanmask 0x%x negchanmask 0x%x\n", | |
1377 | copcb->co_channel, isop->isop_chanmask, | |
1378 | isop->isop_negchanmask); | |
1379 | ENDDEBUG | |
1380 | } | |
1381 | if( !error ) | |
1382 | SET_CHANMASK( isop, copcb->co_channel); | |
1383 | } | |
1384 | ||
1385 | } | |
1386 | ||
1387 | IFDEBUG(D_CDATA) | |
1388 | printf("cons_output calling senddata(0x%x 0x%x)\n", copcb, m); | |
1389 | ASSERT(m != MNULL); | |
1390 | ASSERT(m->m_len != 0); | |
1391 | ENDDEBUG | |
1392 | ||
1393 | if( !error ) | |
1394 | error = cons_senddata( copcb, m); | |
1395 | splx(s); | |
1396 | return error; | |
1397 | } | |
1398 | ||
1399 | /* | |
1400 | * NAME: cons_openvc() | |
1401 | * CALLED FROM: | |
1402 | * TP when it decides to open a VC for TP 0 | |
1403 | * FUNCTION: | |
1404 | * opens a connection and stashes the pcb info in the socket | |
1405 | * substitute for iso_pcbconnect/ in_pcbconnect for the class 0 case | |
1406 | * only. | |
1407 | */ | |
1408 | int | |
1409 | cons_openvc(copcb, faddr, so) | |
1410 | struct cons_pcb *copcb; | |
1411 | struct sockaddr_iso *faddr; | |
1412 | struct socket *so; | |
1413 | { | |
1414 | int error = 0; | |
1415 | int s = splnet(); | |
1416 | struct cons_pcb *cons_chan_to_pcb(); | |
1417 | ||
1418 | ||
1419 | ASSERT( copcb->co_socket == so ); | |
1420 | IFTRACE(D_CCONN) | |
1421 | tptrace(TPPTmisc, "cons_openvc( copcb so )\n", copcb, so, 0, 0); | |
1422 | ENDTRACE | |
1423 | IFDEBUG(D_CCONN) | |
1424 | printf("cons_openvc( copcb 0x%x, so 0x%x )\n", copcb,so); | |
1425 | ENDDEBUG | |
1426 | /* | |
1427 | * initialize the copcb part of the isopcb | |
1428 | */ | |
1429 | copcb->co_ttl = copcb->co_init_ttl = X25_TTL; | |
1430 | copcb->co_flags = CONSF_OCRE; | |
1431 | copcb->co_proto = TP_proto; | |
1432 | copcb->co_pending.ifq_maxlen = CONS_IFQMAXLEN; | |
1433 | ||
1434 | /* abbreviated form of iso_pcbconnect(): */ | |
1435 | bcopy((caddr_t)faddr, (caddr_t)&copcb->co_faddr, | |
1436 | sizeof(struct sockaddr_iso)); | |
1437 | ||
1438 | ASSERT( copcb->co_socket == so ); | |
1439 | if( error = cons_connect( copcb ) ) | |
1440 | goto done; | |
1441 | while( (copcb->co_state != OPEN) && !(error = so->so_error) ) { | |
1442 | IFDEBUG(D_CCONS) | |
1443 | printf( | |
1444 | "SLEEP2 copcb 0x%x state 0x%x chan 0x%x mask 0x%x neg 0x%x\n", | |
1445 | copcb, copcb->co_state, copcb->co_channel, | |
1446 | copcb->co_chanmask, | |
1447 | copcb->co_negchanmask | |
1448 | ); | |
1449 | ENDDEBUG | |
c3e97825 | 1450 | tsleep((caddr_t)&copcb->co_state, PZERO+2, SLP_ISO_CONSCONN, 0); |
3b1d357b KS |
1451 | IFDEBUG(D_CCONS) |
1452 | printf("AFTER SLEEP2 chan 0x%x chanmask 0x%x negchanmask 0x%x\n", | |
1453 | copcb->co_channel, copcb->co_chanmask, | |
1454 | copcb->co_negchanmask); | |
1455 | ENDDEBUG | |
1456 | } | |
1457 | if( !error ) | |
1458 | SET_CHANMASK( (struct isopcb *)copcb, copcb->co_channel); | |
1459 | done: | |
1460 | ASSERT( copcb->co_socket == so ); | |
1461 | splx(s); | |
1462 | ||
1463 | IFDEBUG(D_CCONN) | |
1464 | printf("cons_openvc: copcb 0x%x error 0x%x\n", copcb, error ); | |
1465 | ENDDEBUG | |
1466 | return error; | |
1467 | } | |
1468 | ||
1469 | /* | |
1470 | * NAME: cons_netcmd() | |
1471 | * CALLED FROM: | |
1472 | * tp_route_to() when it decides to accept or reject an incoming | |
1473 | * connection it calls this. | |
1474 | * FUNCTION: | |
1475 | * either closes the cons connection named by (channel) | |
1476 | * or associates the copcb with the channel #. | |
1477 | * and removes the old copcb from the tp_incoming_pending list. | |
1478 | */ | |
1479 | int | |
1480 | cons_netcmd(cmd, isop, channel, isdgm) | |
1481 | int cmd; | |
1482 | struct isopcb *isop; | |
1483 | int channel; | |
1484 | { | |
1485 | int s = splnet(); | |
1486 | int error = 0; | |
1487 | struct cons_pcb *copcb = (struct cons_pcb *)0; | |
1488 | struct cons_pcb *cons_chan_to_pcb(); | |
1489 | ||
1490 | IFTRACE(D_CCONN) | |
1491 | tptrace(TPPTmisc, "cons_netcmd( cmd isopcb channel isdgm)\n", | |
1492 | cmd,isop,channel, isdgm); | |
1493 | ENDTRACE | |
1494 | IFDEBUG(D_CCONN) | |
1495 | printf("cons_netcmd( cmd 0x%x, isop 0x%x, channel 0x%x, isdgm 0x%x)\n", | |
1496 | cmd,isop,channel, isdgm); | |
1497 | if( isop ) | |
1498 | printf("cons_netcmd: isop->socket 0x%x\n", | |
1499 | isop->isop_socket); | |
1500 | ENDDEBUG | |
1501 | ASSERT(cmd != CONN_OPEN); | |
1502 | ||
1503 | /* Can we find a cons-level pcb based on channel? */ | |
1504 | if(channel) { | |
1505 | if((copcb = | |
1506 | #ifdef ARGO_DEBUG | |
1507 | cons_chan_to_pcb( channel, __LINE__ ) | |
1508 | #else ARGO_DEBUG | |
1509 | cons_chan_to_pcb( channel) | |
1510 | #endif ARGO_DEBUG | |
1511 | ) == (struct cons_pcb *)0) { | |
1512 | error = ECONNABORTED; | |
1513 | splx(s); | |
1514 | return error; | |
1515 | } | |
1516 | if( copcb == (struct cons_pcb *) isop ) { | |
1517 | copcb = (struct cons_pcb *)0; | |
1518 | /* avoid operating on a pcb twice */ | |
1519 | } else { | |
1520 | /* if isop is null (close/refuse): | |
1521 | * this would remove from the TP list, which is NOT what we want | |
1522 | * so only remove if there is an isop (gag) | |
1523 | */ | |
1524 | if( isop ) { | |
1525 | remque((struct cons_pcb *)copcb); /* take it off pending list */ | |
1526 | } else { | |
1527 | ASSERT( (cmd == CONN_CLOSE) || (cmd == CONN_REFUSE) ); | |
1528 | } | |
1529 | } | |
1530 | } | |
1531 | /* now we have one of these cases: | |
1532 | * 1) isop is non-null and copcb is null | |
1533 | * 2) isop is non-null and copcb is non-null and they are different | |
1534 | * 3) isop is null and copcb is non-null | |
1535 | */ | |
1536 | ASSERT( (isop != (struct isopcb *)0) || (copcb != (struct cons_pcb *)0)); | |
1537 | ||
1538 | switch(cmd) { | |
1539 | ||
1540 | case CONN_CONFIRM: | |
1541 | if( isdgm ) { | |
1542 | /* we want two separate pcbs */ | |
1543 | /* if we don't have a copcb, get one */ | |
1544 | ||
1545 | if( copcb == (struct cons_pcb *)0 ) { | |
1546 | if(( error = cons_pcballoc(&dummysocket, &cons_isopcb, | |
1547 | ((struct cons_pcb *)isop)->co_flags, | |
1548 | TP_proto, &copcb)) != EOK ) | |
1549 | return error; | |
1550 | /* copy missing info from isop */ | |
1551 | copcb->co_laddr = isop->isop_laddr; | |
1552 | copcb->co_faddr = isop->isop_faddr; | |
1553 | /* don't care about tsuffices */ | |
1554 | ((struct cons_pcb *)isop)->co_channel = 0; | |
1555 | /* no longer used */ | |
1556 | ||
1557 | copcb->co_ifp = ((struct cons_pcb *)isop)->co_ifp ; | |
1558 | ASSERT( copcb->co_pending.ifq_len == 0 ); | |
1559 | ||
1560 | } else { | |
1561 | insque((struct isopcb *)copcb, | |
1562 | (struct isopcb *)&cons_isopcb); | |
1563 | } | |
1564 | copcb->co_state = OPEN; | |
1565 | copcb->co_flags |= CONSF_DGM; | |
1566 | copcb->co_channel = channel; | |
1567 | ASSERT(copcb->co_channel != 0); | |
1568 | ||
1569 | IFDEBUG(D_CCONN) | |
1570 | printf("cons_netcmd: put 0x%x on regular list \n", copcb); | |
1571 | ENDDEBUG | |
1572 | } else { | |
1573 | /* must be TP 0, since this is never called from XTS code */ | |
1574 | /* we want ONE pcb, namely isop. | |
1575 | * If this TPE were the active side, | |
1576 | * there ought not to be a copcb, since TP should | |
1577 | * know that you can't send a CR with dgm and negot down | |
1578 | * to non-dgm. | |
1579 | * If this TPE were the passive side, we want to copy from | |
1580 | * the copcb that was on the pending list, and delete the | |
1581 | * pending copcb. | |
1582 | */ | |
1583 | if( copcb ) { | |
1584 | IFDEBUG(D_CCONN) | |
1585 | printf("cons_netcmd: copied info from 0x%x to 0x%x\n", | |
1586 | copcb, isop); | |
1587 | ENDDEBUG | |
1588 | isop->isop_laddr = copcb->co_laddr; | |
1589 | isop->isop_faddr = copcb->co_faddr; | |
1590 | /* tsuffices, socket should be there already */ | |
1591 | ((struct cons_pcb *)isop)->co_flags = | |
1592 | copcb->co_flags & ~CONSF_DGM; | |
1593 | ((struct cons_pcb *)isop)->co_init_ttl = copcb->co_init_ttl; | |
1594 | touch(((struct cons_pcb *)isop)); | |
1595 | ((struct cons_pcb *)isop)->co_channel = channel; | |
1596 | ((struct cons_pcb *)isop)->co_ifp = copcb->co_ifp; | |
1597 | ((struct cons_pcb *)isop)->co_proto = copcb->co_proto; | |
1598 | ((struct cons_pcb *)isop)->co_myself = | |
1599 | (struct cons_pcb *)isop; | |
1600 | SET_CHANMASK( isop, ((struct cons_pcb *)isop)->co_channel ); | |
1601 | ASSERT( copcb->co_pending.ifq_len == 0 ); | |
1602 | ||
1603 | /* get rid of the copcb that was on the pending list */ | |
1604 | (void) m_free(dtom(copcb)); | |
1605 | } | |
1606 | ((struct cons_pcb *)isop)->co_state = OPEN; | |
1607 | } | |
1608 | break; | |
1609 | ||
1610 | case CONN_CLOSE: | |
1611 | case CONN_REFUSE: | |
1612 | /* if dgm then ignore; the connections will | |
1613 | * be re-used or will time out | |
1614 | */ | |
1615 | if( isdgm ) | |
1616 | break; | |
1617 | ||
1618 | /* we should never come in here with both isop and copcb | |
1619 | * unless is dgm, hence the following assertion: | |
1620 | */ | |
1621 | ASSERT( (copcb == (struct cons_pcb *)0) || | |
1622 | (isop == (struct isopcb *)0) ); | |
1623 | ||
1624 | /* close whichever pcb we have */ | |
1625 | if( copcb ) | |
1626 | error = cons_clear(copcb, (cmd == CONN_CLOSE)? | |
1627 | E_CO_HLI_DISCN:E_CO_HLI_REJT); | |
1628 | if( isop ) | |
1629 | error = cons_clear((struct cons_pcb *)isop, (cmd == CONN_CLOSE)? | |
1630 | E_CO_HLI_DISCN:E_CO_HLI_REJT); | |
1631 | ||
1632 | if(copcb && (copcb->co_socket == (struct socket *)0) ) { | |
1633 | ASSERT( copcb->co_flags & (CONSF_DGM | CONSF_ICRE) ); | |
1634 | (void) m_free(dtom(copcb)); /* detached */ | |
1635 | } | |
1636 | /* isop will always be detached by the higher layer */ | |
1637 | break; | |
1638 | default: | |
1639 | error = EOPNOTSUPP; | |
1640 | break; | |
1641 | } | |
1642 | splx(s); | |
1643 | ||
1644 | IFDEBUG(D_CCONN) | |
1645 | printf("cons_netcmd returns 0x%x: isop 0x%x\n", isop, error ); | |
1646 | ENDDEBUG | |
1647 | return error; | |
1648 | } | |
1649 | ||
1650 | ||
1651 | /* | |
1652 | * NAME: addr_proto_consistency_check() | |
1653 | * CALLED FROM: cons_incoming() | |
1654 | * FUNCTION and ARGUMENTS: | |
1655 | * Enforces a set of rules regarding what addresses will serve | |
1656 | * what protocol stack. This is a kludge forced upon us by the | |
1657 | * fact that there's no way to tell which NET layer you want to | |
1658 | * run when opening a socket. Besides, no doubt, OSI directory | |
1659 | * services won't advertise any kind of a protocol stack with the | |
1660 | * NSAPs. sigh. | |
1661 | * RETURNS | |
1662 | * EAFNOSUPPORT or EOK. | |
1663 | */ | |
1664 | Static int | |
1665 | addr_proto_consistency_check(proto, addr) | |
1666 | int proto; | |
1667 | struct sockaddr_iso *addr; | |
1668 | { | |
1669 | switch( proto ) { | |
1670 | case ISOPROTO_CLNP: | |
1671 | break; | |
1672 | ||
1673 | case ISOPROTO_INACT_NL: | |
1674 | case ISOPROTO_CLTP: | |
1675 | return E_CO_HLI_PROTOID; | |
1676 | ||
1677 | case ISOPROTO_TP: | |
1678 | case ISOPROTO_X25: | |
1679 | /* hl is TP or X.25 */ | |
1680 | if (addr->siso_addr.isoa_afi != AFI_37) | |
1681 | return E_CO_AIWP; | |
1682 | /* kludge - necessary because this is the only type of | |
1683 | * NSAP we build for an incoming NC | |
1684 | */ | |
1685 | break; | |
1686 | default: /* unsupported */ | |
1687 | return E_CO_HLI_PROTOID; | |
1688 | } | |
1689 | return EOK; | |
1690 | } | |
1691 | /* | |
1692 | * NAME: cons_incoming() | |
1693 | * CALLED FROM: | |
1694 | * consintr() for incoming OPEN | |
1695 | * FUNCTION and ARGUMENTS: | |
1696 | * Determines which higher layer gets this call, and | |
1697 | * thus whether to immediately accept, reject, or to let the | |
1698 | * higher layer determine this question. | |
1699 | */ | |
1700 | Static | |
1701 | cons_incoming(ifp, ecnrq) | |
1702 | struct ifnet *ifp; | |
1703 | register struct eicon_request *ecnrq; | |
1704 | { | |
1705 | struct sockaddr_iso me; | |
1706 | struct sockaddr_iso peer; | |
1707 | struct cons_pcb *copcb; | |
1708 | int loop = 0; | |
1709 | int proto =0; | |
1710 | int error = 0; | |
1711 | struct dte_addr peer_dte; | |
1712 | ||
1713 | IFDEBUG(D_INCOMING) | |
1714 | printf("consincoming enter: ifp 0x%x ecnrq 0x%x\n", ifp, ecnrq); | |
1715 | ENDDEBUG | |
1716 | bzero( &me, sizeof(me)); | |
1717 | error = parse_facil( mtod(e_data(ecnrq), caddr_t), | |
1718 | (e_data(ecnrq))->m_len, &me, &peer, &proto, | |
1719 | &peer_dte); | |
1720 | loop = is_me( &peer ); /* <-- THIS may be a problem : | |
1721 | * peer may be nonsense. | |
1722 | * We can only expect that WE will do it right | |
1723 | * and never will we get an error return from | |
1724 | * parse_facil on a facil that WE generated, | |
1725 | * so if garbage comes in, peer will be garbage, | |
1726 | * and loop will be false. | |
1727 | */ | |
1728 | if( error != EOK ) { | |
1729 | (void) issue_clear_req(ecnrq->e_vc, error, ifp, loop); | |
1730 | IncStat(co_parse_facil_err); | |
1731 | IncStat(co_Rdrops); | |
1732 | return; | |
1733 | } | |
1734 | ||
1735 | if( (error = addr_proto_consistency_check(proto, &me)) != EOK ) { | |
1736 | /* problem with consistency */ | |
1737 | (void) issue_clear_req(ecnrq->e_vc, error, ifp, loop); | |
1738 | IncStat(co_addr_proto_consist_err); | |
1739 | IncStat(co_Rdrops); | |
1740 | return; | |
1741 | } else { | |
1742 | switch( proto ) { | |
1743 | case ISOPROTO_X25: | |
1744 | copcb = (struct cons_pcb *) | |
1745 | ((struct cons_pcb *)(&cons_isopcb))->co_next; | |
1746 | ||
1747 | while (copcb != (struct cons_pcb *)&cons_isopcb) { | |
1748 | if( copcb->co_lport == me.siso_tsuffix ) { | |
1749 | /* for cons "transport service", | |
1750 | * multiplexing is not allowed | |
1751 | */ | |
1752 | if( !copcb->co_socket ) { | |
1753 | printf( | |
1754 | "PANIC cons_incoming NOT TP but no sock\n"); | |
1755 | copcb = (struct cons_pcb *)0; | |
1756 | break; | |
1757 | } | |
1758 | if( copcb->co_socket->so_options & SO_ACCEPTCONN ) { | |
1759 | struct cons_pcb *newx; | |
1760 | ||
1761 | newx = (struct cons_pcb *) | |
1762 | sonewconn(copcb->co_socket)->so_pcb; | |
1763 | newx->co_laddr = copcb->co_laddr; | |
1764 | newx->co_peer_dte = peer_dte; | |
1765 | newx->co_proto = copcb->co_proto; | |
1766 | newx->co_myself = newx; | |
1767 | touch(copcb); | |
1768 | copcb = newx; | |
1769 | soisconnected(copcb->co_socket); | |
1770 | break; | |
1771 | } /* else keep looking */ | |
1772 | } | |
1773 | copcb = (struct cons_pcb *)copcb->co_next; | |
1774 | } | |
1775 | if (copcb == (struct cons_pcb *)&cons_isopcb) | |
1776 | copcb = (struct cons_pcb *) 0; | |
1777 | break; | |
1778 | ||
1779 | case ISOPROTO_TP: | |
1780 | ASSERT( me.siso_tsuffix == 0 ); | |
1781 | /* | |
1782 | * We treat this rather like we do for CLNP. | |
1783 | * TP can't tell which socket | |
1784 | * wants this until the TP header comes in, so there's no way | |
1785 | * to associate this channel with a tpcb/isopcb. | |
1786 | * We assume data will arrive (a CR TPDU) and be given to TP along with | |
1787 | * the channel number. We can then expect TP to call us with | |
1788 | * the channel number and pcb ptr, telling us to keep this connection | |
1789 | * or clear it. | |
1790 | * Now, tp will have created an isopcb in the tp_isopcb list. | |
1791 | * We will have to keep another copcb though, because there is no | |
1792 | * 1-1 correspondence between socket and copcb when multiplexing | |
1793 | * is allowed. | |
1794 | * But we want to save the peer address, ifp, and state, proto. | |
1795 | * If the channel should clear before TP responds, we need | |
1796 | * to know that also, so we create a tp-pending list... | |
1797 | */ | |
1798 | if( cons_pcballoc(&dummysocket, &tp_incoming_pending, | |
1799 | CONSF_ICRE, TP_proto, &copcb) != EOK ) { | |
1800 | copcb = (struct cons_pcb *)0; | |
1801 | } else { | |
1802 | copcb->co_peer_dte = peer_dte; | |
1803 | } | |
1804 | break; | |
1805 | ||
1806 | ||
1807 | case ISOPROTO_CLNP: | |
1808 | if( cons_pcballoc(&dummysocket, &cons_isopcb, | |
1809 | CONSF_ICRE | CONSF_DGM, CLNP_proto, &copcb ) != EOK ) { | |
1810 | /* choke */ | |
1811 | copcb = (struct cons_pcb *)0; | |
1812 | } else { | |
1813 | copcb->co_peer_dte = peer_dte; | |
1814 | } | |
1815 | break; | |
1816 | ||
1817 | default: | |
1818 | panic("cons_incoming"); | |
1819 | } /* end switch */ | |
1820 | ||
1821 | if(copcb) { | |
1822 | touch(copcb); | |
1823 | copcb->co_channel = (int)ecnrq->e_vc; | |
1824 | ASSERT( copcb->co_channel != 0); | |
1825 | copcb->co_state = OPEN; | |
1826 | copcb->co_ifp = ifp; | |
1827 | copcb->co_laddr = me; | |
1828 | copcb->co_faddr = peer; | |
1829 | if(loop) | |
1830 | copcb->co_flags |= CONSF_LOOPBACK; | |
1831 | IFDEBUG(D_CADDR) | |
1832 | printf("cons_incoming found XPCB 0x%x, loop 0x%x\n", | |
1833 | copcb, loop); | |
1834 | printf("\nco_laddr: "); | |
1835 | dump_buf(&copcb->co_laddr, sizeof(copcb->co_laddr)); | |
1836 | printf("\nco_faddr: "); | |
1837 | dump_buf(&copcb->co_faddr, sizeof(copcb->co_faddr)); | |
1838 | printf("\n"); | |
1839 | ENDDEBUG | |
1840 | } else { | |
1841 | ifp->if_ierrors ++; | |
1842 | (void) issue_clear_req(ecnrq->e_vc, E_CO_OSI_UNSAP, ifp, loop); | |
1843 | IncStat(co_no_copcb); | |
1844 | IncStat(co_Rdrops); | |
1845 | } | |
1846 | } | |
1847 | /* caller frees the mbuf so we don't have to do any such thing */ | |
1848 | } | |
1849 | ||
1850 | /* | |
1851 | **************************** DEVICE cons *************************** | |
1852 | */ | |
1853 | ||
1854 | /* | |
1855 | * NAME: cosns_output() | |
1856 | * CALLED FROM: | |
1857 | * clnp - this routine is given as the device-output routine | |
1858 | * for the adcom driver. | |
1859 | * FUNCTION and ARGUMENTS: | |
1860 | * (ifp) is the cons/adcom, found by routing function. | |
1861 | * (m0) is the clnp datagram. | |
1862 | * (dst) is the destination address | |
1863 | * This routine finds an x.25 connection for datagram use and | |
1864 | * sends the packet. | |
1865 | */ | |
1866 | int | |
1867 | cosns_output(ifp, m0, dst) | |
1868 | { | |
1869 | return cosns_output1(ifp, m0, dst, CLNP_proto, NULL); | |
1870 | } | |
1871 | ||
1872 | /* DEBUGGING ONLY? */ | |
1873 | int total_cosns_len = 0; | |
1874 | int total_cosns_cnt = 0; | |
1875 | int total_pkts_to_clnp = 0; | |
1876 | ||
1877 | /* | |
1878 | * The isop is passed here so that if we have set x25crud in the | |
1879 | * pcb, it can be passed down to cons_connect. It could be null | |
1880 | * however, in the case of tp4/x25/clnp | |
1881 | */ | |
1882 | Static int | |
1883 | cosns_output1(ifp, m0, dst, proto, isop) | |
1884 | struct ifnet *ifp; | |
1885 | register struct mbuf *m0; | |
1886 | struct sockaddr_iso *dst; | |
1887 | struct protosw *proto; | |
1888 | struct isopcb *isop; /* NULL if coming from clnp */ | |
1889 | { | |
1890 | register struct cons_pcb *copcb; | |
1891 | int s = splnet(); | |
1892 | int error = 0; | |
1893 | ||
1894 | { register struct mbuf *n=m0; | |
1895 | register int len = 0; | |
1896 | ||
1897 | for(;;) { | |
1898 | len += n->m_len; | |
1899 | if (n->m_next == MNULL ) { | |
1900 | break; | |
1901 | } | |
1902 | n = n->m_next; | |
1903 | } | |
1904 | total_cosns_len += len; | |
1905 | total_cosns_cnt ++; | |
1906 | ||
1907 | } | |
1908 | ||
1909 | IFDEBUG(D_CCONS) | |
1910 | printf("cosns_output1( ifp 0x%x, m 0x%x, dst 0x%x )\n", ifp, m0, dst ); | |
1911 | ENDDEBUG | |
1912 | if ( ! (copcb = cons_find( CONSF_DGM, dst, proto, 0, 0) )) { | |
1913 | struct cons_pcb *newcopcb; /* so we can pass addr of this to pcballoc */ | |
1914 | ||
1915 | if( (error = cons_pcballoc(&dummysocket, &cons_isopcb, | |
1916 | CONSF_DGM | CONSF_OCRE, proto, &newcopcb) ) != EOK ) { | |
1917 | IFDEBUG(D_CCONS) | |
1918 | printf("cosns_output: no copcb; returns \n"); | |
1919 | ENDDEBUG | |
1920 | (void) m_freem(m0); | |
1921 | goto done; | |
1922 | } | |
1923 | copcb = newcopcb; | |
1924 | ||
1925 | /* abbreviated form of iso_pcbconnect(): */ | |
1926 | bcopy((caddr_t)dst, (caddr_t)&copcb->co_faddr, | |
1927 | sizeof(struct sockaddr_iso)); | |
1928 | ||
1929 | /* copy x25crud into copcb if necessary */ | |
1930 | if ((isop != NULL) && (isop->isop_x25crud_len > 0)) { | |
1931 | bcopy(isop->isop_x25crud, copcb->co_x25crud, | |
1932 | isop->isop_x25crud_len); | |
1933 | copcb->co_x25crud_len = isop->isop_x25crud_len; | |
1934 | } | |
1935 | ||
1936 | copcb->co_ifp = ifp; /* NULL IF COMING FROM TP4! */ | |
1937 | ||
1938 | if ( error = cons_connect( copcb ) ) { /* if it doesn't work */ | |
1939 | /* oh, dear, throw packet away */ | |
1940 | remque((struct isopcb *)copcb); | |
1941 | (void) m_free(dtom(copcb)); | |
1942 | (void) m_freem(m0); | |
1943 | goto done; | |
1944 | } | |
1945 | } | |
1946 | IFDEBUG(D_CDATA) | |
1947 | printf("cosns_output1 @ senddata: state 0x%x flags 0x%x channel 0x%x\n", | |
1948 | copcb->co_state, copcb->co_flags, copcb->co_channel); | |
1949 | ENDDEBUG | |
1950 | ASSERT(copcb->co_channel != X_NOCHANNEL); | |
1951 | error = cons_senddata(copcb, m0); | |
1952 | done: | |
1953 | splx(s); | |
1954 | return error; | |
1955 | } | |
1956 | ||
1957 | ||
1958 | /* | |
1959 | **************************** TRANSPORT cons *************************** | |
1960 | */ | |
1961 | ||
1962 | ||
1963 | /* | |
1964 | * NAME: cons_detach() | |
1965 | * CALLED FROM: | |
1966 | * cons_usrreq() on PRU_DETACH | |
1967 | * cons_netcmd() when TP releases a net connection | |
1968 | * cons_slowtimo() when timeout releases a net connection | |
1969 | * FUNCTION and ARGUMENT: | |
1970 | * removes the copcb from the list of copcbs in use, and frees the mbufs. | |
1971 | * detaches the pcb from the socket, where a socket exists. | |
1972 | * RETURN VALUE: | |
1973 | * ENOTCONN if it couldn't find the copcb in the list of connections. | |
1974 | */ | |
1975 | ||
1976 | Static int | |
1977 | cons_detach( copcb ) | |
1978 | register struct cons_pcb *copcb; | |
1979 | { | |
1980 | struct socket *so = copcb->co_socket; | |
1981 | ||
1982 | IFDEBUG(D_CCONN) | |
1983 | printf("cons_detach( copcb 0x%x )\n", copcb); | |
1984 | ENDDEBUG | |
1985 | if(so) { | |
1986 | if (so->so_head) { | |
1987 | if (!soqremque(so, 0) && !soqremque(so, 1)) | |
1988 | panic("sofree dq"); | |
1989 | so->so_head = 0; | |
1990 | } | |
1991 | ((struct isopcb *)copcb)->isop_options = 0; /* kludge */ | |
1992 | iso_pcbdetach(copcb); /* detaches from so */ | |
1993 | } else { | |
1994 | remque((struct isopcb *)copcb); | |
1995 | (void) m_free(dtom(copcb)); | |
1996 | } | |
1997 | } | |
1998 | ||
1999 | Static int | |
2000 | cons_clear_and_detach(copcb, clearreason, ctlcmd) | |
2001 | register struct cons_pcb *copcb; | |
2002 | int clearreason; | |
2003 | int ctlcmd; | |
2004 | { | |
2005 | IFDEBUG(D_CCONN) | |
2006 | printf("Clear and Detach (0x%x, 0x%x, 0x%x)\n", | |
2007 | copcb, clearreason, ctlcmd); | |
2008 | ENDDEBUG | |
2009 | if( clearreason != DONTCLEAR ) { | |
2010 | (void) cons_clear( copcb , clearreason ); | |
2011 | } | |
2012 | if( copcb->co_proto && copcb->co_proto->pr_ctlinput ) | |
2013 | (*copcb->co_proto->pr_ctlinput)(ctlcmd, | |
2014 | (struct sockaddr_iso *)&copcb->co_faddr, (caddr_t)copcb); | |
2015 | ||
2016 | if( copcb->co_socket == (struct socket *)0 ) { | |
2017 | /* tp4, clnp users only */ | |
2018 | (void) cons_detach( copcb ); | |
2019 | } /* else detach will be called by the socket's closing */ | |
2020 | else { | |
2021 | ASSERT( copcb->co_socket != &dummysocket ); | |
2022 | ASSERT( (copcb->co_flags & CONSF_DGM) == 0 ); | |
2023 | } | |
2024 | IFDEBUG(D_CCONN) | |
2025 | printf("END OF Clear and Detach (0x%x, 0x%x, 0x%x)\n", | |
2026 | copcb, clearreason, ctlcmd); | |
2027 | ENDDEBUG | |
2028 | } | |
2029 | ||
2030 | Static int | |
2031 | cons_pcbbind( copcb, nam ) | |
2032 | register struct cons_pcb *copcb; | |
2033 | struct mbuf *nam; | |
2034 | { | |
2035 | int error; | |
2036 | ||
2037 | if( error = iso_pcbbind( copcb, nam) ) | |
2038 | return error; | |
2039 | ||
2040 | /* iso_pcbbind already ensured that if port < 1024 it's superuser */ | |
2041 | /* Now we check: must be in range 0 .. 23 or in range 1024 .. 99 */ | |
2042 | ||
2043 | if( (copcb->co_lport < X25_PORT_RESERVED) || | |
2044 | ((copcb->co_lport >= ISO_PORT_RESERVED) && | |
2045 | (copcb->co_lport <= X25_PORT_USERMAX))) { | |
2046 | munge( copcb->co_lport, (&copcb->co_laddr)->siso_addr.t37_idi + | |
2047 | ADDR37_IDI_LEN, 1 /* nibble */); | |
2048 | munge( copcb->co_fport, (&copcb->co_faddr)->siso_addr.t37_idi + | |
2049 | ADDR37_IDI_LEN, 1 /* nibble */); | |
2050 | return 0; | |
2051 | } else | |
2052 | return EADDRNOTAVAIL; | |
2053 | } | |
2054 | /* | |
2055 | * NAME: cons_usrreq() | |
2056 | * CALLED FROM: | |
2057 | * user level via proto switch | |
2058 | * FUNCTION and ARGUMENTS: | |
2059 | * so : socket | |
2060 | * req: which PRU* request | |
2061 | * m : data or mbuf ptr into which to stash data | |
2062 | * nam: mbuf ptr which is really a sockaddr_iso | |
2063 | * ifq: in PRU_CONTROL case, an ifnet structure | |
2064 | * RETURN VALUE: | |
2065 | * ENOTCONN if trying to do something which requires a connection | |
2066 | * and it's not yet connected | |
2067 | * EISCONN if trying to do something which cannot be done to a connection | |
2068 | * but it's connected | |
2069 | * ENOBUFS if ran out of mbufs | |
2070 | * EWOULDBLOCK if in nonblocking mode & can't send right away | |
2071 | * EOPNOSUPP if req isn't supported | |
2072 | * E* other passed up from lower layers or from other routines | |
2073 | */ | |
2074 | ||
2075 | cons_usrreq(so, req, m, nam, ifp) | |
2076 | struct socket *so; | |
2077 | u_int req; | |
2078 | struct mbuf *m, *nam; | |
2079 | int *ifp; | |
2080 | { | |
2081 | struct cons_pcb *copcb = (struct cons_pcb *)so->so_pcb; | |
2082 | int s = splnet(); | |
2083 | int error = 0; | |
2084 | ||
2085 | IFDEBUG(D_CCONS) | |
2086 | printf("cons_usrreq 0x%x so 0x%x copcb 0x%x\n", req, so, copcb); | |
2087 | ENDDEBUG | |
2088 | if (req == PRU_CONTROL) { | |
2089 | error = iso_control(so, (int)m, (caddr_t)nam, (struct ifnet *)ifp); | |
2090 | splx(s); | |
2091 | return error; | |
2092 | } | |
2093 | if (copcb == (struct cons_pcb *)0 && req != PRU_ATTACH) { | |
2094 | splx(s); | |
2095 | return ENOTCONN; | |
2096 | } | |
2097 | ||
2098 | switch (req) { | |
2099 | ||
2100 | case PRU_ATTACH: | |
2101 | if (copcb) { | |
2102 | error = EISCONN; | |
2103 | break; | |
2104 | } | |
2105 | soreserve(so, X25_SBSIZE, X25_SBSIZE); /* CONS size */ | |
2106 | error = cons_pcballoc(so, &cons_isopcb, CONSF_XTS, X25_proto, &copcb ); | |
2107 | break; | |
2108 | ||
2109 | case PRU_ABORT: /* called from close() */ | |
2110 | /* called for each incoming connect queued on the parent (accepting) | |
2111 | * socket (SO_ACCEPTCONN); | |
2112 | */ | |
2113 | error = cons_detach ( copcb ); | |
2114 | break; | |
2115 | ||
2116 | case PRU_DETACH: /* called from close() */ | |
2117 | /* called after disconnect was called iff was connected at the time | |
2118 | * of the close, or directly if socket never got connected */ | |
2119 | error = cons_detach ( copcb ); | |
2120 | break; | |
2121 | ||
2122 | case PRU_SHUTDOWN: | |
2123 | /* recv end may have been released; local credit might be zero */ | |
2124 | case PRU_DISCONNECT: | |
2125 | soisdisconnected(so); | |
2126 | error = cons_clear(copcb, E_CO_HLI_DISCN); | |
2127 | break; | |
2128 | ||
2129 | case PRU_BIND: | |
2130 | error = cons_pcbbind( copcb, nam); | |
2131 | break; | |
2132 | ||
2133 | case PRU_LISTEN: | |
2134 | if (copcb->co_lport == 0) | |
2135 | error = cons_pcbbind( copcb, 0 ); | |
2136 | break; | |
2137 | ||
2138 | ||
2139 | case PRU_SOCKADDR: { | |
2140 | struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *); | |
2141 | ||
2142 | nam->m_len = sizeof (struct sockaddr_iso); | |
2143 | if(copcb->co_ifp) | |
2144 | bcopy( (caddr_t)&copcb->co_laddr, | |
2145 | (caddr_t)siso, sizeof(struct sockaddr_iso) ); | |
2146 | ||
2147 | ((struct sockaddr_iso *)siso)->siso_tsuffix = copcb->co_lport; | |
2148 | } | |
2149 | break; | |
2150 | ||
2151 | case PRU_PEERADDR: | |
2152 | if( (so->so_state & SS_ISCONNECTED) && | |
2153 | (so->so_state & SS_ISDISCONNECTING) == 0) { | |
2154 | struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *); | |
2155 | ||
2156 | nam->m_len = sizeof (struct sockaddr_iso); | |
2157 | bcopy( (caddr_t)&copcb->co_faddr, (caddr_t)siso, | |
2158 | sizeof(struct sockaddr_iso) ); | |
2159 | } else | |
2160 | error = ENOTCONN; | |
2161 | break; | |
2162 | ||
2163 | case PRU_CONNECT: | |
2164 | /* TODO: We need to bind to the RIGHT interface. | |
2165 | * The only way to have the right interface is to have | |
2166 | * the right route. | |
2167 | */ | |
2168 | IFDEBUG(D_CCONN) | |
2169 | printf("PRU_CONNECT 1: local tsuffix 0x%x so->so_head 0x%x nam:\n", | |
2170 | copcb->co_lport, so->so_head); | |
2171 | dump_isoaddr( mtod(nam, struct sockaddr_iso *) ); | |
2172 | ENDDEBUG | |
2173 | if (copcb->co_lport == 0) { | |
2174 | if( error = cons_pcbbind( copcb, 0 )) | |
2175 | break; | |
2176 | } | |
2177 | IFDEBUG(D_CCONN) | |
2178 | printf("PRU_CONNECT 2: local tsuffix 0x%x so->so_head 0x%x nam:\n", | |
2179 | copcb->co_lport, so->so_head); | |
2180 | dump_isoaddr( mtod(nam, struct sockaddr_iso *) ); | |
2181 | ENDDEBUG | |
2182 | ||
2183 | { /* change the destination address so the last 2 digits | |
2184 | * are the port/suffix/selector (whatever you want to call it) | |
2185 | */ | |
2186 | register struct sockaddr_iso *siso = | |
2187 | mtod(nam, struct sockaddr_iso *); | |
2188 | if( (siso->siso_tsuffix < X25_PORT_RESERVED) || | |
2189 | ((siso->siso_tsuffix >= ISO_PORT_RESERVED) && | |
2190 | (siso->siso_tsuffix <= X25_PORT_USERMAX))) | |
2191 | munge( siso->siso_tsuffix, | |
2192 | siso->siso_addr.t37_idi + ADDR37_IDI_LEN, | |
2193 | 1 /* nibble */); | |
2194 | } | |
2195 | ||
2196 | soisconnecting(so); | |
2197 | if (error = iso_pcbconnect(copcb, nam)) | |
2198 | break; | |
2199 | error = cons_connect( copcb ); | |
2200 | if ( error ) { | |
2201 | /* | |
2202 | remque((struct isopcb *)copcb); | |
2203 | (void) m_free(dtom(copcb)); | |
2204 | */ | |
2205 | break; | |
2206 | } | |
2207 | while( (copcb->co_state != OPEN)&&(copcb->co_socket->so_error == 0) ) { | |
2208 | IFDEBUG(D_CCONN) | |
2209 | printf("PRU_CONNECT: error 0x%x sleeping on 0x%x\n", | |
2210 | copcb->co_socket->so_error, | |
2211 | (caddr_t)&copcb->co_state ); | |
2212 | ENDDEBUG | |
c3e97825 | 2213 | sleep((caddr_t)&copcb->co_state, PZERO+3, SLP_ISO_CONS, 0 ); |
3b1d357b KS |
2214 | } |
2215 | ||
2216 | ASSERT( copcb->co_channel != 0); | |
2217 | ||
2218 | SET_CHANMASK ( (struct isopcb *)copcb, copcb->co_channel); | |
2219 | break; | |
2220 | ||
2221 | case PRU_ACCEPT: | |
2222 | /* so here is the NEW socket */ | |
2223 | so->so_error = 0; | |
2224 | if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTED)== 0) { | |
2225 | error = EWOULDBLOCK; | |
2226 | break; | |
2227 | } | |
2228 | { | |
2229 | struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *); | |
2230 | ||
2231 | /* copy the peer's address into the return argument */ | |
2232 | nam->m_len = sizeof (struct sockaddr_iso); | |
2233 | bcopy( (caddr_t)&copcb->co_faddr, (caddr_t)siso, | |
2234 | sizeof(struct sockaddr_iso)); | |
2235 | } | |
2236 | break; | |
2237 | ||
2238 | case PRU_SEND: | |
2239 | case PRU_SENDEOT: | |
2240 | /* | |
2241 | * sosend calls this until sbspace goes negative. | |
2242 | * Sbspace may be made negative by appending this mbuf chain, | |
2243 | * possibly by a whole cluster. | |
2244 | */ | |
2245 | { | |
2246 | /* no need to actually queue this stuff and dequeue it, | |
2247 | * just bump the pointers in so_snd so that higher | |
2248 | * layer of socket code will cause it to sleep when | |
2249 | * we've run out of socket space | |
2250 | * TODO: | |
2251 | * Unfortunately that makes sbflush vomit so we have | |
2252 | * to allocate a single real mbuf (say size 240) | |
2253 | * and sballoc it and sbfree it upon CONS_SEND_DONE. | |
2254 | * Oh, my, is this sickening or what? | |
2255 | */ | |
2256 | { | |
2257 | struct mbuf *mx; | |
2258 | ||
2259 | MGET(mx, M_DONTWAIT, MT_DATA); | |
2260 | mx->m_len = MLEN; | |
2261 | sbappend((caddr_t)&copcb->co_socket->so_snd, mx); | |
2262 | } | |
2263 | if( m ) { | |
2264 | IFDEBUG(D_CDATA) | |
2265 | printf("X.25 Usrreq calling cons_senddata(0x%x, 0x%x)\n", | |
2266 | copcb, m); | |
2267 | ENDDEBUG | |
2268 | error = cons_senddata(copcb, m); | |
2269 | } | |
2270 | IFDEBUG(D_CCONS) | |
2271 | printf("PRU_SEND sent tsuffix 0x%x, m 0x%x error 0x%x\n", | |
2272 | copcb->co_lport, m, error); | |
2273 | ENDDEBUG | |
2274 | ||
2275 | if( req == PRU_SENDEOT ) { | |
2276 | while(copcb->co_socket->so_snd.sb_cc > 0) | |
2277 | sbwait(&copcb->co_socket->so_snd); | |
2278 | } | |
2279 | } | |
2280 | break; | |
2281 | ||
2282 | case PRU_CONTROL: | |
2283 | error = cons_ioctl(so, m, (caddr_t)nam); | |
2284 | break; | |
2285 | ||
2286 | ||
2287 | case PRU_RCVD: | |
2288 | case PRU_RCVOOB: | |
2289 | case PRU_SENDOOB: | |
2290 | /* COULD support INTERRUPT packets as oob */ | |
2291 | case PRU_PROTOSEND: | |
2292 | case PRU_PROTORCV: | |
2293 | case PRU_SENSE: | |
2294 | case PRU_SLOWTIMO: | |
2295 | case PRU_CONNECT2: | |
2296 | case PRU_FASTTIMO: | |
2297 | default: | |
2298 | error = EOPNOTSUPP; | |
2299 | } | |
2300 | ||
2301 | IFDEBUG(D_CCONS) | |
2302 | printf("cons_usrreq cmd 0x%x copcb 0x%x returned error 0x%x\n", | |
2303 | req, copcb, error); | |
2304 | ENDDEBUG | |
2305 | splx(s); | |
2306 | return error; | |
2307 | } | |
2308 | ||
2309 | /* | |
2310 | * NAME: cons_input() | |
2311 | * CALLED FROM: | |
2312 | * consintr() through the isosw protosw for "transport" version of X25 | |
2313 | * FUNCTION & ARGUMENTS: | |
2314 | * process incoming data | |
2315 | */ | |
2316 | cons_input(m, faddr, laddr, so) | |
2317 | register struct mbuf *m; | |
2318 | struct sockaddr_iso *faddr, *laddr; /* not used */ | |
2319 | register struct socket *so; | |
2320 | { | |
2321 | IFDEBUG(D_CCONS) | |
2322 | printf("cons_input( m 0x%x, so 0x%x)\n", m,so); | |
2323 | ENDDEBUG | |
2324 | sbappend(&so->so_rcv, m); | |
2325 | sbwakeup(&so->so_rcv); | |
2326 | } | |
2327 | ||
2328 | #ifdef notdef | |
2329 | /* | |
2330 | * NAME: cons_ctloutput() | |
2331 | * CALLED FROM: | |
2332 | * set/get sockopts() | |
2333 | * Presently the protosw has 0 in the ctloutput spot | |
2334 | * because we haven't inplemented anything yet. | |
2335 | * If there's reason to put some options in here, | |
2336 | * be sure to stick this routine name in the protosw in iso_proto.c | |
2337 | */ | |
2338 | cons_ctloutput(cmd, so, level, optname, mp) | |
2339 | int cmd, level, optname; | |
2340 | struct socket *so; | |
2341 | struct mbuf **mp; | |
2342 | { | |
2343 | int s = splnet(); | |
2344 | ||
2345 | splx(s); | |
2346 | return EOPNOTSUPP; | |
2347 | } | |
2348 | #endif notdef | |
2349 | ||
2350 | ||
2351 | /* | |
2352 | * NAME: cons_ctlinput() | |
2353 | * CALLED FROM: | |
2354 | * lower layer when ECN_CLEAR occurs : this routine is here | |
2355 | * for consistency - cons subnet service calls its higher layer | |
2356 | * through the protosw entry. | |
2357 | * FUNCTION & ARGUMENTS: | |
e663c139 | 2358 | * cmd is a PRC_* command, list found in ../sys/protosw.h |
3b1d357b KS |
2359 | * copcb is the obvious. |
2360 | * This serves the higher-layer cons service. | |
2361 | * NOTE: this takes 3rd arg. because cons uses it to inform itself | |
2362 | * of things (timeouts, etc) but has a pcb instead of an address. | |
2363 | */ | |
2364 | cons_ctlinput(cmd, sa, copcb) | |
2365 | int cmd; | |
2366 | struct sockaddr *sa; | |
2367 | register struct cons_pcb *copcb; | |
2368 | { | |
2369 | int error = 0; | |
2370 | int s = splnet(); | |
2371 | extern u_char inetctlerrmap[]; | |
2372 | extern int iso_rtchange(); | |
2373 | ||
2374 | IFDEBUG(D_CCONS) | |
2375 | printf("cons_ctlinput( cmd 0x%x, copcb 0x%x)\n", cmd, copcb); | |
2376 | ENDDEBUG | |
2377 | /* co_socket had better exist */ | |
2378 | switch (cmd) { | |
2379 | case PRC_CONS_SEND_DONE: | |
2380 | ASSERT( copcb->co_socket ); | |
2381 | ASSERT( copcb->co_flags & CONSF_XTS ); | |
2382 | sbdrop((caddr_t)&copcb->co_socket->so_snd, MLEN); | |
2383 | sbwakeup((caddr_t)&copcb->co_socket->so_snd); | |
2384 | break; | |
2385 | ||
2386 | case PRC_ROUTEDEAD: | |
2387 | error = ENETUNREACH; | |
2388 | break; | |
2389 | ||
2390 | case PRC_TIMXCEED_REASS: | |
2391 | error = ETIMEDOUT; | |
2392 | break; | |
2393 | ||
2394 | /* | |
2395 | case PRC_QUENCH: | |
2396 | iso_pcbnotify(&cons_pcb, sa, | |
2397 | (int)inetctlerrmap[cmd], iso_rtchange); | |
2398 | iso_pcbnotify(&tp_incoming_pending, sa, | |
2399 | (int)inetctlerrmap[cmd], tpiso_quench); | |
2400 | iso_pcbnotify(&tp_isopcb, sa, | |
2401 | (int)inetctlerrmap[cmd], tpiso_quench); | |
2402 | */ | |
2403 | ||
2404 | case PRC_IFDOWN: | |
2405 | iso_pcbnotify(&cons_isopcb, sa, | |
2406 | (int)inetctlerrmap[cmd], iso_rtchange); | |
2407 | iso_pcbnotify(&tp_incoming_pending, sa, | |
2408 | (int)inetctlerrmap[cmd], iso_rtchange); | |
2409 | iso_pcbnotify(&tp_isopcb, sa, | |
2410 | (int)inetctlerrmap[cmd], iso_rtchange); | |
2411 | break; | |
2412 | ||
2413 | ||
2414 | default: | |
2415 | printf("cons_ctlinput: unknown cmd 0x%x\n", cmd); | |
2416 | } | |
2417 | if(error) { | |
2418 | soisdisconnected(copcb->co_socket); | |
2419 | sohasoutofband(copcb->co_socket); | |
2420 | } | |
2421 | splx(s); | |
2422 | } | |
2423 | ||
2424 | /* | |
2425 | *********************** SERVES ALL cons embodiments ******************* | |
2426 | */ | |
2427 | ||
2428 | /* | |
2429 | * NAME: cons_chan_to_pcb() | |
2430 | * CALLED FROM: | |
2431 | * cons_chan_to_tpcb() in tp_cons.c | |
2432 | * and in this file: incoming requests that give only a channel number, i.e., | |
2433 | * ECN_ACCEPT, ECN_RECEIVE, ECN_CLEAR | |
2434 | * FUNCTION: | |
2435 | * identify the pcb assoc with that channel | |
2436 | * RETURN: | |
2437 | * ptr to the pcb | |
2438 | */ | |
2439 | struct cons_pcb * | |
2440 | #ifdef ARGO_DEBUG | |
2441 | cons_chan_to_pcb( channel, linenumber ) | |
2442 | int linenumber; | |
2443 | #else ARGO_DEBUG | |
2444 | cons_chan_to_pcb( channel) | |
2445 | #endif ARGO_DEBUG | |
2446 | register int channel; | |
2447 | { | |
2448 | register struct cons_pcb **copcblist = (struct cons_pcb **)Xpcblist; | |
2449 | register struct cons_pcb *copcb; | |
2450 | ||
2451 | /* just to be sure */ | |
2452 | channel = channel & 0xff; | |
2453 | ||
2454 | for( copcb = *copcblist; copcb; copcb = *(++copcblist) ) { | |
2455 | copcb = (struct cons_pcb *)copcb->co_next; | |
2456 | while (copcb != *copcblist) { | |
2457 | if ( copcb->co_channel == channel ) | |
2458 | goto found; /* want to break out of both loops */ | |
2459 | ||
2460 | copcb = (struct cons_pcb *)copcb->co_next; | |
2461 | } | |
2462 | } | |
2463 | found: /* or maybe not... */ | |
2464 | IFDEBUG(D_CCONS) | |
2465 | printf("cons_chan_to_pcb( 0x%x, %d ) %s 0x%x\n", channel, linenumber, | |
2466 | copcb?"FOUND":"FAILED", copcb); | |
2467 | ENDDEBUG | |
2468 | ||
2469 | return copcb; | |
2470 | } | |
2471 | ||
2472 | ||
2473 | /* | |
2474 | * NAME: is_me() | |
2475 | * CALLED FROM: | |
2476 | * cons_incoming(). Perhaps could just expand in line. | |
2477 | * FUNCTION and ARGUMENTS: | |
2478 | * for the given remote address (remadr) if it exactly matches | |
2479 | * one of the addresses of ME, and I am up as loopback, | |
2480 | * return TRUE, else return FALSE. | |
2481 | * RETURNS: | |
2482 | * Boolean | |
2483 | */ | |
2484 | Static int | |
2485 | is_me(remaddr) | |
2486 | struct sockaddr_iso *remaddr; | |
2487 | { | |
2488 | struct ifnet *ifp = consif; | |
2489 | /* PHASE2: this is ok */ | |
2490 | struct ifaddr *ifa = ifa_ifwithaddr(remaddr); | |
2491 | ||
2492 | IFDEBUG(D_CADDR) | |
2493 | printf("is_me: withaddr returns %s\n", | |
2494 | ifa?ifa->ifa_ifp->if_name:"NONE"); | |
2495 | ENDDEBUG | |
2496 | if( ifa ) { | |
2497 | /* remaddr matches one of my interfaces exactly */ | |
2498 | if( ifa->ifa_ifp->if_flags & IFF_LOOPBACK ) { | |
2499 | ASSERT( ifp == ifa->ifa_ifp ); | |
2500 | return 1; | |
2501 | } | |
2502 | } | |
2503 | return 0; | |
2504 | } | |
2505 | ||
2506 | find_error_reason( ecnrq ) | |
2507 | register struct eicon_request *ecnrq; | |
2508 | { | |
2509 | extern u_char x25_error_stats[]; | |
2510 | int error; | |
2511 | struct mbuf *cdm; | |
2512 | struct e_clear_data *ecd; | |
2513 | ||
2514 | cdm = e_data(ecnrq); | |
2515 | if( cdm && cdm->m_len > 0 ) { | |
2516 | ecd = mtod(cdm, struct e_clear_data *); | |
2517 | switch( ecd->ecd_cause ) { | |
2518 | case 0x00: | |
2519 | case 0x80: | |
2520 | /* DTE originated; look at the diagnostic */ | |
2521 | error = (CONL_ERROR_MASK | ecd->ecd_diagnostic); | |
2522 | goto done; | |
2523 | ||
2524 | case 0x01: /* number busy */ | |
2525 | case 0x81: | |
2526 | case 0x09: /* Out of order */ | |
2527 | case 0x89: | |
2528 | case 0x11: /* Remot Procedure Error */ | |
2529 | case 0x91: | |
2530 | case 0x19: /* reverse charging accept not subscribed */ | |
2531 | case 0x99: | |
2532 | case 0x21: /* Incampat destination */ | |
2533 | case 0xa1: | |
2534 | case 0x29: /* fast select accept not subscribed */ | |
2535 | case 0xa9: | |
2536 | case 0x39: /* ship absent */ | |
2537 | case 0xb9: | |
2538 | case 0x03: /* invalid facil request */ | |
2539 | case 0x83: | |
2540 | case 0x0b: /* access barred */ | |
2541 | case 0x8b: | |
2542 | case 0x13: /* local procedure error */ | |
2543 | case 0x93: | |
2544 | case 0x05: /* network congestion */ | |
2545 | case 0x85: | |
2546 | case 0x8d: /* not obtainable */ | |
2547 | case 0x0d: | |
2548 | case 0x95: /* RPOA out of order */ | |
2549 | case 0x15: | |
2550 | /* take out bit 8 | |
2551 | * so we don't have to have so many perror entries | |
2552 | */ | |
2553 | error = (CONL_ERROR_MASK | 0x100 | (ecd->ecd_cause & ~0x80)); | |
2554 | goto done; | |
2555 | ||
2556 | case 0xc1: /* gateway-detected proc error */ | |
2557 | case 0xc3: /* gateway congestion */ | |
2558 | ||
2559 | error = (CONL_ERROR_MASK | 0x100 | ecd->ecd_cause); | |
2560 | goto done; | |
2561 | } | |
2562 | } | |
2563 | /* otherwise, a *hopefully* valid perror exists in the e_reason field */ | |
2564 | error = ecnrq->e_reason; | |
2565 | if (error = 0) { | |
2566 | printf("Incoming PKT TYPE 0x%x with reason 0x%x\n", | |
2567 | ecnrq->e_cmd, | |
2568 | ecnrq->e_reason); | |
2569 | error = E_CO_HLI_DISCA; | |
2570 | } | |
2571 | ||
2572 | done: | |
2573 | if(error & 0x1ff == 0) { | |
2574 | error = 0; | |
2575 | } else if( error & 0x1ff > sizeof(x25_error_stats)) { | |
2576 | ASSERT(0); | |
2577 | } else { | |
2578 | x25_error_stats[error& 0x1ff] ++; | |
2579 | } | |
2580 | return error; | |
2581 | } | |
2582 | ||
2583 | /* | |
2584 | * NAME: consintr() | |
2585 | * CALLED FROM: | |
2586 | * the eicon driver via software interrupt | |
2587 | * FUNCTION and ARGUMENTS: | |
2588 | * processes incoming indications, passing them | |
2589 | * along to clnp, tp, or x.25-transport as appropriate. | |
2590 | */ | |
2591 | consintr() | |
2592 | { | |
2593 | struct ifnet *ifp = consif; | |
2594 | register struct eicon_request *ecnrq; | |
2595 | register struct cons_pcb *copcb = (struct cons_pcb *)0; | |
2596 | register struct mbuf *m; | |
2597 | int s, s0 = splnet(); | |
2598 | ||
2599 | IncStat(co_intr); | |
2600 | ifp->if_ipackets ++; | |
2601 | ||
2602 | for(;;) { | |
2603 | /* | |
2604 | * Get next request off input queue | |
2605 | */ | |
2606 | s = splimp(); | |
2607 | IF_DEQUEUE(&consintrq, m); | |
2608 | splx(s); | |
2609 | IFDEBUG(D_INCOMING) | |
2610 | printf("cons intr() 0x%x m_off 0x%x m_len 0x%x dequeued\n", | |
2611 | m, m?m->m_off:0, m?m->m_len:0); | |
2612 | ENDDEBUG | |
2613 | ||
2614 | if (m == 0) { | |
2615 | splx(s0); | |
2616 | return; | |
2617 | } | |
2618 | ||
2619 | if((m->m_off != MMINOFF)||(m->m_len != sizeof (struct eicon_request))){ | |
2620 | ifp->if_ierrors ++; | |
2621 | IncStat(co_Rdrops); | |
2622 | printf("Cons R DROP! BAD MBUF FROM LL 0x%x sizeof(...) 0x%x\n", | |
2623 | m, sizeof(struct eicon_request)); | |
2624 | continue; | |
2625 | } | |
2626 | ||
2627 | ecnrq = mtod(m, struct eicon_request *); | |
2628 | ||
2629 | ||
2630 | IFDEBUG(D_INCOMING) | |
2631 | printf("INTR: e_cmd 0x%x, e_data 0x%x\n", ecnrq->e_cmd, | |
2632 | e_data(ecnrq)); | |
2633 | if( e_data(ecnrq) != 0 ) { | |
2634 | /* let's just look at the first few bytes */ | |
2635 | /* | |
2636 | dump_buf( e_data(ecnrq), (e_data(ecnrq))->m_len + 12); | |
2637 | */ | |
2638 | dump_buf( e_data(ecnrq), 20 + 12); | |
2639 | } | |
2640 | ENDDEBUG | |
2641 | IFTRACE(D_CDATA) | |
2642 | tptrace( TPPTmisc, "INTR: req_type m lun\n", | |
2643 | ecnrq->e_cmd, m, ecnrq->e_vc, 0); | |
2644 | ENDTRACE | |
2645 | ||
2646 | switch( ecnrq->e_cmd ) { | |
2647 | ||
2648 | case ECN_ACK: /* data put on the board */ | |
2649 | IncStat(co_ack); | |
2650 | ASSERT( ecnrq->e_vc != 0); | |
2651 | /* from ACKWAIT to OPEN */ | |
2652 | if ( (copcb = | |
2653 | #ifdef ARGO_DEBUG | |
2654 | cons_chan_to_pcb( (int)ecnrq->e_vc, __LINE__ ) | |
2655 | #else ARGO_DEBUG | |
2656 | cons_chan_to_pcb( (int)ecnrq->e_vc ) | |
2657 | #endif ARGO_DEBUG | |
2658 | ) == (struct cons_pcb *)0 ) | |
2659 | break; | |
2660 | copcb->co_state = OPEN; | |
2661 | /* | |
2662 | * Anything on the pending queue for this connection? | |
2663 | */ | |
2664 | if( copcb->co_pending.ifq_len == 0 ) { | |
2665 | if( copcb->co_proto->pr_ctlinput ) | |
2666 | /* for the sake of higher layer protocol (tp) */ | |
2667 | (*copcb->co_proto->pr_ctlinput) | |
2668 | (PRC_CONS_SEND_DONE, | |
2669 | (struct sockaddr_iso *)&copcb->co_faddr, | |
2670 | (caddr_t)copcb); | |
2671 | } else { | |
2672 | register struct mbuf *m0; | |
2673 | ||
2674 | s = splimp(); | |
2675 | IF_DEQUEUE( &copcb->co_pending, m0 ); | |
2676 | splx(s); | |
2677 | /* CAN ONLY DO 1 item here | |
2678 | * if you change this if to while, HA HA | |
2679 | * it'll go right back onto | |
2680 | * the pending queue (which means things will | |
2681 | * be reordered on the queue!) | |
2682 | */ | |
2683 | if( m0 ) { | |
2684 | IFDEBUG(D_CDATA) | |
2685 | printf("ACK sending pending queue 0x%x len 0x%x\n", | |
2686 | m0, m0->m_len); | |
2687 | ENDDEBUG | |
2688 | ASSERT( m0->m_len != 0); | |
2689 | (void) cons_senddata(copcb, m0); | |
2690 | } | |
2691 | } | |
2692 | ||
2693 | /* send more? */ | |
2694 | break; | |
2695 | ||
2696 | case ECN_ACCEPT: /* call accepted at other end */ | |
2697 | /* adr_src, adr_dst are as given in the ECN_CALL | |
2698 | * pcb field is copied from our ECN_CALL | |
2699 | * request, confirm gives me a channel number | |
2700 | */ | |
2701 | ASSERT( ecnrq->e_vc != 0); | |
2702 | ||
2703 | IncStat(co_accept); | |
2704 | if(copcb = | |
2705 | #ifdef ARGO_DEBUG | |
2706 | cons_chan_to_pcb((int)ecnrq->e_vc, __LINE__ ) | |
2707 | #else ARGO_DEBUG | |
2708 | cons_chan_to_pcb((int)ecnrq->e_vc) | |
2709 | #endif ARGO_DEBUG | |
2710 | ) { | |
2711 | /* error: already exists */ | |
2712 | printf("cons PANIC: dbl confirm for channel 0x%x\n", | |
2713 | ecnrq->e_vc); | |
2714 | break; | |
2715 | } | |
2716 | copcb = (struct cons_pcb *)ecnrq->e_pcb; | |
2717 | if( copcb->co_myself != copcb ) { | |
2718 | struct mbuf *mm; | |
2719 | /* TODO: REMOVE */ | |
2720 | ASSERT(0); | |
2721 | printf("BAD e_pcb from ecn (0x%x) cmd 0x%x\n", | |
2722 | ecnrq->e_pcb, ecnrq->e_cmd); | |
2723 | mm = dtom( copcb ); | |
2724 | if(mm->m_type == MT_FREE) | |
2725 | printf("FREED MBUF!\n"); | |
2726 | dump_buf (ecnrq, sizeof (*ecnrq)); | |
2727 | panic("BAD ecnrq"); | |
2728 | break; | |
2729 | } | |
2730 | touch(copcb); | |
2731 | copcb->co_state = OPEN; | |
2732 | copcb->co_channel = (int)ecnrq->e_vc; | |
2733 | if(copcb->co_socket) { | |
2734 | /* tp0 will take care of itself */ | |
2735 | if( copcb->co_flags & CONSF_XTS) | |
2736 | soisconnected(copcb->co_socket); /* wake 'em up */ | |
2737 | } | |
2738 | wakeup( (caddr_t)&copcb->co_state ); | |
2739 | ||
2740 | /* | |
2741 | * Anything on the pending queue for this connection? | |
2742 | */ | |
2743 | if( copcb->co_pending.ifq_len > 0 ) { | |
2744 | register struct mbuf *m0; | |
2745 | ||
2746 | s = splimp(); | |
2747 | IF_DEQUEUE( &copcb->co_pending, m0 ); | |
2748 | splx(s); | |
2749 | /* CAN ONLY DO 1 item here | |
2750 | * if you change this if to while, HA HA | |
2751 | * it'll go right back onto | |
2752 | * the pending queue (which means things will | |
2753 | * be reordered on the queue!) | |
2754 | */ | |
2755 | if( m0 ) { | |
2756 | IFDEBUG(D_CDATA) | |
2757 | printf("ACPT sending pending queue 0x%x len 0x%x\n", | |
2758 | m0, m0->m_len); | |
2759 | ENDDEBUG | |
2760 | ASSERT( m0->m_len != 0); | |
2761 | (void) cons_senddata(copcb, m0); | |
2762 | } | |
2763 | } | |
2764 | break; | |
2765 | ||
2766 | case ECN_REFUSE: | |
2767 | /* other end refused our connect request */ | |
2768 | /* src, dst are as given in the ECN_CALL */ | |
2769 | ||
2770 | IncStat(co_refuse); | |
2771 | copcb = (struct cons_pcb *)ecnrq->e_pcb; | |
2772 | if( copcb->co_myself != copcb ) { | |
2773 | struct mbuf *mm; | |
2774 | /* TODO: REMOVE */ | |
2775 | ASSERT(0); | |
2776 | printf("BAD e_pcb from ecn (0x%x) cmd 0x%x\n", | |
2777 | ecnrq->e_pcb, ecnrq->e_cmd); | |
2778 | mm = dtom( copcb ); | |
2779 | if(mm->m_type == MT_FREE) | |
2780 | printf("FREED MBUF!\n"); | |
2781 | dump_buf (ecnrq, sizeof (*ecnrq)); | |
2782 | dump_buf (copcb, sizeof (*copcb)); | |
2783 | panic("BAD ecnrq"); | |
2784 | break; | |
2785 | } | |
2786 | touch(copcb); | |
2787 | copcb->co_state = CLOSED; /* do we have to do a clear?? */ | |
2788 | copcb->co_channel = X_NOCHANNEL; | |
2789 | if(copcb->co_socket) { | |
2790 | copcb->co_socket->so_error = ECONNREFUSED; | |
2791 | /* TODO: if there's diagnostic info in the | |
2792 | * packet, and it's more useful than this E*, | |
2793 | * get it | |
2794 | */ | |
2795 | soisdisconnected(copcb->co_socket); /* wake 'em up */ | |
2796 | IFDEBUG(D_INCOMING) | |
2797 | printf("ECN_REFUSE: waking up 0x%x\n", | |
2798 | (caddr_t)&copcb->co_state ); | |
2799 | ENDDEBUG | |
2800 | wakeup( (caddr_t)&copcb->co_state ); | |
2801 | } | |
2802 | /* | |
2803 | * Anything on the pending queue for this connection? | |
2804 | */ | |
2805 | while( copcb->co_pending.ifq_len > 0 ) { | |
2806 | register struct mbuf *m0; | |
2807 | ||
2808 | s = splimp(); | |
2809 | IF_DEQUEUE( &copcb->co_pending, m0 ); | |
2810 | splx(s); | |
2811 | m_freem(m0); | |
2812 | } | |
2813 | if ( ecnrq->e_reason == E_CO_NORESOURCES ) { | |
2814 | IncStat(co_noresources); | |
2815 | cons_clear_and_detach( copcb, DONTCLEAR, PRC_QUENCH ); | |
2816 | } else if(copcb->co_socket ) { | |
2817 | copcb->co_socket->so_error = find_error_reason( ecnrq ); | |
2818 | } | |
2819 | break; | |
2820 | ||
2821 | case ECN_CONNECT: /* incoming call */ | |
2822 | /* | |
2823 | * ECN_CONNECT indication gives adc_src, adc_dst and channel | |
2824 | */ | |
2825 | ASSERT( ecnrq->e_vc != 0); | |
2826 | ||
2827 | IncStat(co_connect); | |
2828 | cons_incoming(ifp, ecnrq); | |
2829 | break; | |
2830 | ||
2831 | case ECN_RESET: | |
2832 | case ECN_CLEAR: | |
2833 | /* | |
2834 | * ECN_CLEAR(indication) (if we can construct such a beast) | |
2835 | * gives e_vc, | |
2836 | * Throw away anything queued pending on this connection | |
2837 | * give a reset indication to the upper layer if TP | |
2838 | * free the mbufs | |
2839 | */ | |
2840 | ASSERT( ecnrq->e_vc != 0); | |
2841 | if( ecnrq->e_cmd == ECN_CLEAR ) | |
2842 | IncStat(co_clear_in); | |
2843 | else | |
2844 | IncStat(co_reset_in); | |
2845 | #ifdef ARGO_DEBUG | |
2846 | if( ! (copcb=cons_chan_to_pcb((int)ecnrq->e_vc, __LINE__)) ) | |
2847 | #else ARGO_DEBUG | |
2848 | if( ! (copcb=cons_chan_to_pcb((int)ecnrq->e_vc)) ) | |
2849 | #endif ARGO_DEBUG | |
2850 | ||
2851 | break; | |
2852 | while( copcb->co_pending.ifq_len ) { | |
2853 | register struct mbuf *m0; | |
2854 | ||
2855 | s = splimp(); | |
2856 | IF_DEQUEUE( &copcb->co_pending, m0 ); | |
2857 | splx(s); | |
2858 | m_freem(m0); | |
2859 | } | |
2860 | copcb->co_state = CLOSED; /* do we have to do a clear? */ | |
2861 | copcb->co_channel = X_NOCHANNEL; | |
2862 | ||
2863 | cons_clear_and_detach( copcb, DONTCLEAR, PRC_ROUTEDEAD ); | |
2864 | if (copcb->co_socket ) { | |
2865 | copcb->co_socket->so_error = find_error_reason( ecnrq ); | |
2866 | } | |
2867 | break; | |
2868 | ||
2869 | case ECN_RECEIVE: | |
2870 | /* | |
2871 | * ECN_RECEIVE (read) | |
2872 | */ | |
2873 | ASSERT( ecnrq->e_vc != 0); | |
2874 | IncStat(co_receive); | |
2875 | { | |
2876 | /* TODO: REMOVE */ | |
2877 | struct mbuf *thedata = e_data(ecnrq); | |
2878 | u_int *firstint = mtod( thedata, u_int *); | |
2879 | ||
2880 | if( (*firstint & 0xff000000) != 0x81000000 ) { | |
2881 | /* not clnp */ | |
2882 | switch( ((*firstint) & 0x00ff0000) >> 20 ) { | |
2883 | case 0x1: | |
2884 | case 0x2: | |
2885 | case 0x3: | |
2886 | case 0x6: | |
2887 | case 0x7: | |
2888 | case 0x8: | |
2889 | case 0xc: | |
2890 | case 0xd: | |
2891 | case 0xe: | |
2892 | case 0xf: | |
2893 | break; | |
2894 | default: | |
2895 | printf(" ECN_RECEIVE! BAD DATA\n" ); | |
2896 | dump_buf( thedata, 20 + 12 ); | |
2897 | m_freem( m ); | |
2898 | splx(s0); | |
2899 | } | |
2900 | } | |
2901 | } | |
2902 | if ( (copcb = | |
2903 | #ifdef ARGO_DEBUG | |
2904 | cons_chan_to_pcb( (int)ecnrq->e_vc, __LINE__ ) | |
2905 | #else ARGO_DEBUG | |
2906 | cons_chan_to_pcb( (int)ecnrq->e_vc ) | |
2907 | #endif ARGO_DEBUG | |
2908 | ) == (struct cons_pcb *)0 ) { | |
2909 | ifp->if_ierrors ++; | |
2910 | IFTRACE(D_CDATA) | |
2911 | tptrace(TPPTmisc, "ECN_RECEIVE DROPPED chan \n", | |
2912 | ecnrq->e_vc, 0, 0, 0); | |
2913 | ENDTRACE | |
2914 | break; | |
2915 | } | |
2916 | ||
2917 | touch(copcb); | |
2918 | if( ecnrq->e_info & ECN_INFO_RCVD_INT ) { | |
2919 | /* interrupt packet */ | |
2920 | printf("consintr: interrupt pkttype : DROPPED\n"); | |
2921 | IncStat(co_intrpt_pkts_in); | |
2922 | IncStat(co_Rdrops); | |
2923 | break; | |
2924 | } | |
2925 | /* new way */ | |
2926 | if( copcb->co_proto == CLNP_proto ) | |
2927 | { | |
2928 | /* IP: put it on the queue and set soft interrupt */ | |
2929 | struct ifqueue *ifq; | |
2930 | extern struct ifqueue clnlintrq; | |
2931 | register struct mbuf *ifpp; /* for ptr to ifp */ | |
2932 | register struct mbuf *data = e_data(ecnrq); | |
2933 | ||
2934 | total_pkts_to_clnp ++; | |
2935 | ||
2936 | /* when acting as a subnet service, have to prepend a | |
2937 | * pointer to the ifnet before handing this to clnp | |
2938 | * GAG | |
2939 | */ | |
2940 | if( ( data->m_off > MMINOFF + sizeof(struct snpa_hdr)) && | |
2941 | ( data->m_off <= MMAXOFF )) { | |
2942 | data->m_off -= sizeof(struct snpa_hdr); | |
2943 | data->m_len += sizeof(struct snpa_hdr); | |
2944 | } else { | |
2945 | MGET(ifpp, M_DONTWAIT, MT_XHEADER); | |
2946 | if( !ifpp ) { | |
2947 | ifp->if_ierrors ++; | |
2948 | splx(s0); | |
2949 | m_freem(m); /* frees everything */ | |
2950 | return; | |
2951 | } | |
2952 | ifpp->m_len = sizeof(struct snpa_hdr); | |
2953 | ifpp->m_act = 0; | |
2954 | ifpp->m_next = data; | |
2955 | data = ifpp; | |
2956 | } | |
2957 | IFTRACE(D_CDATA) | |
2958 | tptrace(TPPTmisc, "-->CLNP copcb\n", copcb, 0, 0, 0); | |
2959 | ENDTRACE | |
2960 | { | |
2961 | /* | |
2962 | * TODO: if we ever use esis/cons we have to | |
2963 | * think of something reasonable to stick in the | |
2964 | * snh_shost,snh_dhost fields. I guess | |
2965 | * the x.121 address is what we want. | |
2966 | * | |
2967 | * That would also require length fields in the | |
2968 | * snpa_hdr structure. | |
2969 | */ | |
2970 | struct snpa_hdr *snh = | |
2971 | mtod(data, struct snpa_hdr *); | |
2972 | bzero((caddr_t)&snh, sizeof(struct snpa_hdr)); | |
2973 | bcopy((caddr_t)&ifp, (caddr_t)&snh->snh_ifp, | |
2974 | sizeof(struct ifnet *)); | |
2975 | } | |
2976 | *( mtod(data, struct ifnet **) ) = ifp; /* KLUDGE */ | |
2977 | ||
2978 | ifq = &clnlintrq; | |
2979 | splimp(); | |
2980 | if (IF_QFULL(ifq)) { | |
2981 | IF_DROP(ifq); | |
2982 | m_freem(m); | |
2983 | IFDEBUG(D_INCOMING) | |
2984 | printf("DROPPED! ecnrq 0x%x, data 0x%x\n", m,data); | |
2985 | ENDDEBUG | |
2986 | splx(s0); | |
2987 | ifp->if_ierrors ++; | |
2988 | return; | |
2989 | } | |
2990 | IF_ENQUEUE(ifq, data); | |
2991 | IFDEBUG(D_INCOMING) | |
2992 | printf( | |
2993 | "0x%x enqueued on ip Q: m_len 0x%x m_type 0x%x m_off 0x%x\n", | |
2994 | data, data->m_len, data->m_type, data->m_off); | |
2995 | dump_buf(mtod(data, caddr_t), data->m_len); | |
2996 | ENDDEBUG | |
2997 | e_data(ecnrq) = (struct mbuf *)0; | |
2998 | schednetisr(NETISR_CLNP); | |
2999 | } else { | |
3000 | /* HL is NOT clnp */ | |
3001 | IFTRACE(D_CDATA) | |
3002 | tptrace(TPPTmisc, | |
3003 | "-->HL pr_input so copcb channel\n", | |
3004 | copcb->co_proto->pr_input, | |
3005 | copcb->co_socket, copcb, | |
3006 | copcb->co_channel); | |
3007 | ENDTRACE | |
3008 | IFDEBUG(D_INCOMING) | |
3009 | printf( "0x%x --> HL proto 0x%x chan 0x%x\n", | |
3010 | e_data(ecnrq), copcb->co_proto, copcb->co_channel ); | |
3011 | ENDDEBUG | |
3012 | ||
3013 | (*copcb->co_proto->pr_input)(e_data(ecnrq), | |
3014 | &copcb->co_faddr, | |
3015 | &copcb->co_laddr, | |
3016 | copcb->co_socket, /* used by cons-transport interface */ | |
3017 | (copcb->co_flags & CONSF_DGM)?0: | |
3018 | copcb->co_channel);/* used by tp-cons interface */ | |
3019 | ||
3020 | /* | |
3021 | * the pr_input will free the data chain, so we must | |
3022 | * zero the ptr to is so that m_free doesn't panic | |
3023 | */ | |
3024 | e_data(ecnrq) = (struct mbuf *)0; | |
3025 | } | |
3026 | break; | |
3027 | ||
3028 | default: | |
3029 | /* error */ | |
3030 | ifp->if_ierrors ++; | |
3031 | printf("consintr: unknown request\n"); | |
3032 | } | |
3033 | IFDEBUG(D_INCOMING) | |
3034 | printf("consintr: m_freem( 0x%x )\n", m); | |
3035 | ENDDEBUG | |
3036 | m_freem( m ); | |
3037 | } | |
3038 | splx(s0); | |
3039 | } | |
3040 | ||
3041 | /* | |
3042 | * Process an ioctl request. | |
3043 | * also set-time-limit, extend-time-limit | |
3044 | * for ALL channels, the time-limit ioctls will be done by open-a-dummy-socket, | |
3045 | * do ioctl with the channel number, close the socket (dumb!). | |
3046 | */ | |
3047 | /* ARGSUSED */ | |
3048 | cons_ioctl(so, cmd, data) | |
3049 | struct socket *so; | |
3050 | int cmd; | |
3051 | caddr_t data; | |
3052 | { | |
3053 | int s = splnet(); | |
3054 | int error = 0; | |
3055 | ||
3056 | IFDEBUG(D_CCONS) | |
3057 | printf("cons_ioctl( cmd 0x%x )\n", cmd); | |
3058 | ENDDEBUG | |
3059 | ||
3060 | #ifdef notdef | |
3061 | switch (cmd) { | |
3062 | ||
3063 | default: | |
3064 | #endif notdef | |
3065 | error = EOPNOTSUPP; | |
3066 | #ifdef notdef | |
3067 | } | |
3068 | #endif notdef | |
3069 | ||
3070 | splx(s); | |
3071 | return (error); | |
3072 | } | |
3073 | ||
3074 | ||
3075 | /* | |
3076 | ************************************************************* | |
3077 | * * | |
3078 | * * | |
3079 | * Interface to CO Subnetwork service from CLNP * | |
3080 | * Must be a device interface. ***** | |
3081 | * *** | |
3082 | * * | |
3083 | * Poof! | |
3084 | */ | |
3085 | ||
3086 | /* | |
3087 | * NAME: consioctl() | |
3088 | * CALLED FROM: | |
3089 | * called through the ifnet structure. | |
3090 | * FUNCTION and ARGUMENTS: | |
3091 | * the usual ioctl stuff | |
3092 | * RETURNS: | |
3093 | * E* | |
3094 | * SIDE EFFECTS: | |
3095 | * NOTES: | |
3096 | */ | |
3097 | consioctl(ifp, cmd, data) | |
3098 | register struct ifnet *ifp; | |
3099 | register int cmd; | |
3100 | register caddr_t data; | |
3101 | { | |
3102 | register struct ifaddr *ifa = (struct ifaddr *)data; | |
3103 | register int s = splimp(); | |
3104 | register struct ifreq *ifr = (struct ifreq *)data; | |
3105 | register int error = 0; | |
3106 | void consshutdown(); | |
3107 | ||
3108 | switch (cmd) { | |
3109 | case SIOCSIFADDR: | |
3110 | switch (ifa->ifa_addr.sa_family) { | |
3111 | case AF_ISO: | |
3112 | if( (ifp->if_flags & IFF_UP ) == 0) | |
3113 | consinit(ifp->if_unit); | |
3114 | break; | |
3115 | default: | |
3116 | printf("CANNOT config cons with address family %d\n", | |
3117 | ifa->ifa_addr.sa_family); | |
3118 | break; | |
3119 | } | |
3120 | break; | |
3121 | case SIOCSIFFLAGS: | |
3122 | IFDEBUG(D_CCONS) | |
3123 | printf("consioctl: set flags to x%x\n", ifr->ifr_flags); | |
3124 | printf("consioctl: ifp flags are x%x\n", ifp->if_flags); | |
3125 | ENDDEBUG | |
3126 | if( ifr->ifr_flags & IFF_LOOPBACK ) | |
3127 | ifp->if_flags |= IFF_LOOPBACK; | |
3128 | else | |
3129 | ifp->if_flags &= ~IFF_LOOPBACK; | |
3130 | ||
3131 | /* if board is down but request takes it up, init the board */ | |
3132 | if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) | |
3133 | consinit(ifp->if_unit); | |
3134 | ||
3135 | /* if board is up but request takes it down, shut the board down */ | |
3136 | if (((ifr->ifr_flags & IFF_UP) == 0) && (ifp->if_flags & IFF_UP)) { | |
3137 | consshutdown(ifp->if_unit); | |
3138 | } | |
3139 | IFDEBUG(D_CCONS) | |
3140 | printf("consioctl: flags are x%x\n", ifp->if_flags); | |
3141 | ENDDEBUG | |
3142 | break; | |
3143 | case SIOCGSTATUS: | |
3144 | /* warning: must coerse ifp to (struct ifstatus *) in order to use */ | |
3145 | IFDEBUG(D_CCONS) | |
3146 | printf("consioctl: EICON status request\n"); | |
3147 | ENDDEBUG | |
3148 | #if NECN>0 | |
3149 | ecnioctl(ifp, cmd, data); | |
3150 | #else | |
3151 | error = ENODEV; | |
3152 | #endif NECN>0 | |
3153 | break; | |
3154 | default: | |
3155 | error = EINVAL; | |
3156 | } | |
3157 | splx(s); | |
3158 | return error; | |
3159 | } | |
3160 | ||
3161 | /* | |
3162 | * NAME: consattach() | |
3163 | * CALLED FROM: | |
3164 | * cons_init() (which comes from autoconf) | |
3165 | * FUNCTION and ARGUMENTS: | |
3166 | * creates an ifp and fills it in; calls ifattach() on it. | |
3167 | * RETURNS: | |
3168 | * no return value | |
3169 | * SIDE EFFECTS: | |
3170 | * NOTES: | |
3171 | */ | |
3172 | consattach() | |
3173 | { | |
3174 | register struct ifnet *ifp; | |
3175 | register struct mbuf *m; | |
3176 | ||
3177 | if(sizeof(struct ifnet) > MLEN) { | |
3178 | printf("Can't attach cons! sizeof(struct ifnet) > MLEN\n"); | |
3179 | return; | |
3180 | } | |
3181 | MGET(m, M_DONTWAIT, MT_IFADDR); | |
3182 | if( !m ) { | |
3183 | printf("Can't attach cons! NO MBUFS!\n"); | |
3184 | return; | |
3185 | } | |
3186 | m->m_len = sizeof(struct ifnet); | |
3187 | ifp = consif = mtod(m, struct ifnet *); | |
3188 | ifp->if_unit = 0; | |
3189 | ifp->if_name = "cons"; | |
3190 | ifp->if_mtu = ECN_MTU; | |
3191 | ifp->if_init = consinit; | |
3192 | ifp->if_ioctl = consioctl; | |
3193 | ifp->if_output = cosns_output; /* called by clnp */ | |
3194 | ifp->if_flags = IFF_LOOPBACK; /* default */ | |
3195 | if_attach(ifp); | |
3196 | printf("cons%d: pseudo device attached \n", ifp->if_unit); | |
3197 | } | |
3198 | ||
3199 | /* | |
3200 | * NAME: consinit() | |
3201 | * CALLED FROM: | |
3202 | * consioctl() | |
3203 | * FUNCTION and ARGUMENTS: | |
3204 | * Initializes apropos data structures, etc. | |
3205 | * Marks the device as up. | |
3206 | * Zaps the address list. | |
3207 | * Calls device layer restart on the device if necessary. | |
3208 | */ | |
3209 | Static | |
3210 | consinit(_unit) | |
3211 | register int _unit; /* unit to initialize */ | |
3212 | { | |
3213 | struct ifnet *ecnifp(); | |
3214 | struct ifnet *ifp; | |
3215 | int s; | |
3216 | ||
3217 | if ((ifp = ecnifp(_unit)) != (struct ifnet *)0 ) { | |
3218 | ecnrestart(ifp); | |
3219 | IncStat(co_restart); | |
3220 | } | |
3221 | if (consif->if_addrlist == (struct ifaddr *)0) | |
3222 | return; | |
3223 | if ((consif->if_flags & IFF_UP) == 0) { | |
3224 | s = splimp(); | |
3225 | consif->if_flags |= IFF_UP; | |
3226 | splx(s); | |
3227 | } | |
3228 | ||
3229 | } | |
3230 | ||
3231 | /* | |
3232 | * NAME: consshutdown() | |
3233 | * CALLED FROM: | |
3234 | * cons_ioctl() when user takes down an interface w/ SIOCSIFFLAGS | |
3235 | * FUNCTION and ARGUMENTS: | |
3236 | * calls lower layer shutdown routine on the device. | |
3237 | * and marks the if as down if the if is the sw loopback pseudodevice. | |
3238 | * RETURNS: | |
3239 | * no return value | |
3240 | */ | |
3241 | void | |
3242 | consshutdown(_unit) | |
3243 | register int _unit; /* unit to shutdown */ | |
3244 | { | |
3245 | extern struct ifnet *ecnifp(); | |
3246 | struct ifnet *ifp; | |
3247 | int s; | |
3248 | ||
3249 | if ((ifp = ecnifp(_unit)) != (struct ifnet *)0 ) { | |
3250 | ecnshutdown(ifp); | |
3251 | } | |
3252 | if ((consif->if_flags & IFF_UP) ) { | |
3253 | s = splimp(); | |
3254 | consif->if_flags &= ~IFF_UP; | |
3255 | splx(s); | |
3256 | } | |
3257 | } | |
3258 | #endif KERNEL | |
3259 | ||
3260 | /* | |
3261 | * NAME: munge() | |
3262 | * CALLED FROM: | |
3263 | * cons_pcbbind(), cons_usrreq() | |
3264 | * FUNCTION and ARGUMENTS: | |
3265 | * Takes the argument (value) and stashes it into the last two | |
3266 | * nibbles of an X.121 address. Does this in the two nibbles beginning | |
3267 | * at the location defined by the character pointer (dst_octet) and the | |
3268 | * integer (dst_nibble). Nibble 0 is the lower nibble (high | |
3269 | * order 4 bits); nibble 1 is the low order 4 bits of *(dst_octet). | |
3270 | * | |
3271 | * RETURNS: | |
3272 | * no return value | |
3273 | */ | |
3274 | Static | |
3275 | munge( value, dst_octet, dst_nibble) | |
3276 | int value; | |
3277 | caddr_t dst_octet; | |
3278 | int dst_nibble; | |
3279 | { | |
3280 | IFDEBUG(D_CCONN) | |
3281 | printf("MUNGE: value 0x%x dst_octet 0x%x, nibble 0x%x)\n", | |
3282 | value, dst_octet, dst_nibble); | |
3283 | ENDDEBUG | |
3284 | if (value >= ISO_PORT_RESERVED) | |
3285 | value -= 1000; | |
3286 | ||
3287 | { | |
3288 | /* convert so it looks like a decimal number */ | |
3289 | register int tens, ones; | |
3290 | ||
3291 | tens = value/10; | |
3292 | ASSERT( tens <= 9 ); | |
3293 | ones = value - (tens * 10); | |
3294 | ||
3295 | value = tens * 16 + ones; | |
3296 | } | |
3297 | ||
3298 | dst_octet --; | |
3299 | /* leave nibble same 'cause it's one after the last set nibble */ | |
3300 | ||
3301 | *dst_octet &= ~(0xff<<(dst_nibble << 2)); /* zero it */ | |
3302 | *dst_octet |= ((value>>4) << (dst_nibble<<2)); | |
3303 | dst_nibble = 1-dst_nibble; | |
3304 | dst_octet += dst_nibble; | |
3305 | ||
3306 | *dst_octet &= ~(0xff<<(dst_nibble << 2)); /* zero it */ | |
3307 | *dst_octet |= ((value&0xff) << (dst_nibble<<2)); | |
3308 | } | |
3309 | ||
3310 | /* | |
3311 | * NAME: unmunge() | |
3312 | * CALLED FROM: | |
3313 | * DTEtoNSAP(), FACILtoNSAP() | |
3314 | * FUNCTION and ARGUMENTS: | |
3315 | * return the port/tsuffix represented by the two digits found in a | |
3316 | * bcd string beginning at the (dst_nibble)th nibble of the | |
3317 | * octet BEFORE (dst_octet). | |
3318 | * | |
3319 | * dst_octet,dst_nibble is the nibble after the one we'll look at | |
3320 | * RETURNS: | |
3321 | * an integer, the port/tsuffix | |
3322 | * Note- converts to a port > 1000 if necessary. | |
3323 | */ | |
3324 | Static int | |
3325 | unmunge( dst_octet, dst_nibble ) | |
3326 | caddr_t dst_octet; | |
3327 | int dst_nibble; | |
3328 | { | |
3329 | register u_short last = 0; | |
3330 | ||
3331 | dst_octet --; | |
3332 | /* leave nibble same 'cause it's one after the last set nibble */ | |
3333 | IFDEBUG(D_CADDR) | |
3334 | printf("unmunge: *octet 0x%x, nibble 0x%x\n", *dst_octet, | |
3335 | dst_nibble); | |
3336 | ENDDEBUG | |
3337 | ||
3338 | last = ((*dst_octet) & (0xff<<(dst_nibble<<2))); | |
3339 | dst_nibble = 1-dst_nibble; | |
3340 | dst_octet += dst_nibble; | |
3341 | ||
3342 | last |= ((*dst_octet) & (0xff<<(dst_nibble << 2))); | |
3343 | { | |
3344 | /* convert to a decimal number */ | |
3345 | register int tens, ones; | |
3346 | ||
3347 | tens = (last&0xf0)>>4; | |
3348 | ones = last&0xf; | |
3349 | ||
3350 | last = tens * 10 + ones; | |
3351 | } | |
3352 | ||
3353 | IFDEBUG(D_CADDR) | |
3354 | printf("unmunge computes 0x%x\n", last); | |
3355 | ENDDEBUG | |
3356 | if((int)last+1000 >= ISO_PORT_RESERVED) | |
3357 | last += 1000; | |
3358 | IFDEBUG(D_CADDR) | |
3359 | printf("unmunge returns 0x%x\n", last); | |
3360 | ENDDEBUG | |
3361 | return last; | |
3362 | } | |
3363 | ||
3364 | /* | |
3365 | * NAME: make_partial_x25_packet() | |
3366 | * | |
3367 | * FUNCTION and ARGUMENTS: | |
3368 | * Makes part of an X.25 call packet, for use by the eicon board. | |
3369 | * (src) and (dst) are the NSAP-addresses of source and destination. | |
3370 | * (proto) is the higher-layer protocol number (in iso.h) | |
3371 | * (buf) is a ptr to a buffer into which to write this partial header. | |
3372 | * | |
3373 | * The partial header looks like (choke): | |
3374 | * octet meaning | |
3375 | * 1 calling DTE len | called DTE len (lengths in nibbles) | |
3376 | * 2..n-1 called DTE addr | (<-- boundary may be middle of an octet) | |
3377 | * calling DTE addr | zero nibble to round to octet boundary. | |
3378 | * n Facility length (in octets) | |
3379 | * n+1 Facility field, which is a set of: | |
3380 | * m facil code | |
3381 | * m+1 facil param len (for >2-byte facilities) in octets | |
3382 | * m+2..p facil param field | |
3383 | * q user data (protocol identification octet) | |
3384 | * | |
3385 | * | |
3386 | * RETURNS: | |
3387 | * 0 if OK | |
3388 | * E* if failed. | |
3389 | */ | |
3390 | ||
3391 | #ifdef X25_1984 | |
3392 | int cons_use_facils = 1; | |
3393 | #else X25_1984 | |
3394 | int cons_use_facils = 0; | |
3395 | #endif X25_1984 | |
3396 | ||
3397 | int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */ | |
3398 | ||
3399 | Static int | |
3400 | make_partial_x25_packet(copcb, m) | |
3401 | struct cons_pcb *copcb; | |
3402 | struct mbuf *m; | |
3403 | { | |
3404 | struct sockaddr_iso *src, *dst; | |
3405 | u_int proto; | |
3406 | int flag; | |
3407 | caddr_t buf = mtod(m, caddr_t); | |
3408 | register caddr_t ptr = buf + 1; /* make room for 2 length nibbles */ | |
3409 | register int len = 0; | |
3410 | int buflen =0; | |
3411 | caddr_t facil_len; | |
3412 | int oddness = 0; | |
3413 | ||
3414 | src = &copcb->co_laddr; | |
3415 | dst = &copcb->co_faddr; | |
3416 | proto = copcb->co_proto->pr_protocol, | |
3417 | flag = copcb->co_flags & CONSF_XTS; | |
3418 | ||
3419 | ||
3420 | IFDEBUG(D_CCONN) | |
3421 | printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", | |
3422 | src, dst, proto, m, flag); | |
3423 | ENDDEBUG | |
3424 | ||
3425 | /* | |
3426 | * Note - order of addrs in x25 pkt hdr is wierd: | |
3427 | * calling len/called len/called addr/calling addr (p.40 ISO 8202) | |
3428 | */ | |
3429 | if( (len = copcb->co_peer_dte.dtea_niblen) > 0 ) { | |
3430 | nibble_copy( (char *)(copcb->co_peer_dte.dtea_addr), HIGH_NIBBLE, | |
3431 | ptr, HIGH_NIBBLE, len); | |
3432 | } else { | |
3433 | if ((len = NSAPtoDTE( ptr, HIGH_NIBBLE, dst)) <=0 ) { | |
3434 | return E_CO_OSI_UNSAP; | |
3435 | } | |
3436 | } | |
3437 | *buf = len; /* fill in called dte addr length */ | |
3438 | ptr += len>>1; /* len is in nibbles */ | |
3439 | oddness += len&0x1; | |
3440 | ||
3441 | if ((len = NSAPtoDTE( ptr, 1-(len&0x1), src)) <=0 ) { | |
3442 | return E_CO_OSI_UNSAP; | |
3443 | } | |
3444 | ptr += len>>1; /* len is in nibbles */ | |
3445 | *buf |= len << 4; /* fill in calling dte addr length */ | |
3446 | oddness += len&0x1; | |
3447 | ||
3448 | IFDEBUG(D_CADDR) | |
3449 | printf("make_partial 2: ptr 0x%x, len 0x%x oddness 0x%x\n", | |
3450 | ptr, len, oddness ); | |
3451 | ENDDEBUG | |
3452 | /* if either of the addresses were an odd length, the count is off by 1 */ | |
3453 | if( oddness ) { | |
3454 | ptr ++; | |
3455 | } | |
3456 | ||
3457 | /* ptr now points to facil length (len of whole facil field in OCTETS */ | |
3458 | facil_len = ptr ++; | |
3459 | ||
3460 | IFDEBUG(D_CADDR) | |
3461 | printf("make_partial calling: ptr 0x%x, len 0x%x\n", ptr, | |
3462 | src->siso_addr.isoa_len); | |
3463 | ENDDEBUG | |
3464 | if( cons_use_facils ) { | |
3465 | *ptr = 0xcb; /* calling facility code */ | |
3466 | ptr ++; | |
3467 | ptr ++; /* leave room for facil param len (in OCTETS + 1) */ | |
3468 | ptr ++; /* leave room for the facil param len (in nibbles), | |
3469 | * high two bits of which indicate full/partial NSAP | |
3470 | */ | |
3471 | len = src->siso_addr.isoa_len; | |
3472 | bcopy( &src->siso_addr.isoa_afi, ptr, len); | |
3473 | *(ptr-2) = len+2; /* facil param len in octets */ | |
3474 | *(ptr-1) = len<<1; /* facil param len in nibbles */ | |
3475 | ptr += len; | |
3476 | ||
3477 | IFDEBUG(D_CADDR) | |
3478 | printf("make_partial called: ptr 0x%x, len 0x%x\n", ptr, | |
3479 | dst->siso_addr.isoa_len); | |
3480 | ENDDEBUG | |
3481 | *ptr = 0xc9; /* called facility code */ | |
3482 | ptr ++; | |
3483 | ptr ++; /* leave room for facil param len (in OCTETS + 1) */ | |
3484 | ptr ++; /* leave room for the facil param len (in nibbles), | |
3485 | * high two bits of which indicate full/partial NSAP | |
3486 | */ | |
3487 | len = dst->siso_addr.isoa_len; | |
3488 | bcopy( &dst->siso_addr.isoa_afi, ptr, len); | |
3489 | *(ptr-2) = len+2; /* facil param len = addr len + 1 for each of these | |
3490 | * two length fields, in octets */ | |
3491 | *(ptr-1) = len<<1; /* facil param len in nibbles */ | |
3492 | ptr += len; | |
3493 | ||
3494 | } | |
3495 | *facil_len = ptr - facil_len - 1; | |
3496 | if(*facil_len > X25_FACIL_LEN_MAX ) | |
3497 | return E_CO_PNA_LONG; | |
3498 | ||
3499 | if( cons_use_udata ) { | |
3500 | if (copcb->co_x25crud_len > 0) { | |
3501 | /* | |
3502 | * The user specified something. Stick it in | |
3503 | */ | |
3504 | bcopy(copcb->co_x25crud, ptr, copcb->co_x25crud_len); | |
3505 | ptr += copcb->co_x25crud_len; | |
3506 | } else { | |
3507 | /* protocol identifier */ | |
3508 | switch (proto) { | |
3509 | /* unfortunately all are considered 1 protocol */ | |
3510 | case ISOPROTO_TP0: | |
3511 | case ISOPROTO_TP1: | |
3512 | case ISOPROTO_TP2: | |
3513 | case ISOPROTO_TP3: | |
3514 | case ISOPROTO_TP4: | |
3515 | case ISOPROTO_CLTP: | |
3516 | /* no user data for TP */ | |
3517 | break; | |
3518 | ||
3519 | case ISOPROTO_CLNP: | |
3520 | *ptr = 0x81; | |
3521 | ptr++; /* count the proto id byte! */ | |
3522 | break; | |
3523 | case ISOPROTO_INACT_NL: | |
3524 | *ptr = 0x0; | |
3525 | ptr++; /* count the proto id byte! */ | |
3526 | break; | |
3527 | case ISOPROTO_X25: | |
3528 | *ptr = 0xff; /* reserved for future extensions */ | |
3529 | /* we're stealing this value for local use */ | |
3530 | ptr++; /* count the proto id byte! */ | |
3531 | break; | |
3532 | default: | |
3533 | return EPROTONOSUPPORT; | |
3534 | } | |
3535 | } | |
3536 | } | |
3537 | ||
3538 | buflen = (int)(ptr - buf); | |
3539 | ||
3540 | IFDEBUG(D_CDUMP_REQ) | |
3541 | register int i; | |
3542 | ||
3543 | printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n", | |
3544 | buf, buflen, buflen); | |
3545 | for( i=0; i < buflen; ) { | |
3546 | printf("+%d: %x %x %x %x %x %x %x %x\n", | |
3547 | i, | |
3548 | *(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3), | |
3549 | *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7)); | |
3550 | i+=8; | |
3551 | } | |
3552 | ENDDEBUG | |
3553 | IFDEBUG(D_CADDR) | |
3554 | printf("make_partial returns buf 0x%x size 0x%x bytes\n", | |
3555 | mtod(m, caddr_t), buflen); | |
3556 | ENDDEBUG | |
3557 | ||
3558 | ASSERT( X25_PARTIAL_PKT_LEN_MAX < MLEN ); | |
3559 | ||
3560 | if(buflen > X25_PARTIAL_PKT_LEN_MAX) | |
3561 | return E_CO_PNA_LONG; | |
3562 | ||
3563 | m->m_len = buflen; | |
3564 | return 0; | |
3565 | } | |
3566 | ||
3567 | /* | |
3568 | * NAME: NSAPtoDTE() | |
3569 | * CALLED FROM: | |
3570 | * make_partial_x25_packet() | |
3571 | * FUNCTION and ARGUMENTS: | |
3572 | * get a DTE address from an NSAP-address (struct sockaddr_iso) | |
3573 | * (dst_octet) is the octet into which to begin stashing the DTE addr | |
3574 | * (dst_nibble) takes 0 or 1. 1 means begin filling in the DTE addr | |
3575 | * in the high-order nibble of dst_octet. 0 means low-order nibble. | |
3576 | * (addr) is the NSAP-address | |
3577 | * (flag) is true if the transport suffix is to become the | |
3578 | * last two digits of the DTE address | |
3579 | * A DTE address is a series of BCD digits | |
3580 | * | |
3581 | * A DTE address may have leading zeros. The are significant. | |
3582 | * 1 digit per nibble, may be an odd number of nibbles. | |
3583 | * | |
3584 | * An NSAP-address has the DTE address in the IDI. Leading zeros are | |
3585 | * significant. Trailing hex f indicates the end of the DTE address. | |
3586 | * Also is a series of BCD digits, one per nibble. | |
3587 | * | |
3588 | * RETURNS | |
3589 | * # significant digits in the DTE address, -1 if error. | |
3590 | */ | |
3591 | ||
3592 | Static int | |
3593 | NSAPtoDTE( dst_octet, dst_nibble, addr) | |
3594 | caddr_t dst_octet; | |
3595 | int dst_nibble; | |
3596 | register struct sockaddr_iso *addr; | |
3597 | { | |
3598 | int error; | |
3599 | u_char x121string[7]; /* maximum is 14 digits */ | |
3600 | int x121strlen; | |
3601 | struct dte_addr *dtea; | |
3602 | ||
3603 | IFDEBUG(D_CADDR) | |
3604 | printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&addr->siso_addr)); | |
3605 | ENDDEBUG | |
3606 | ||
3607 | error = iso_8208snparesolve(addr, x121string, &x121strlen); | |
3608 | ASSERT(error == 0); | |
3609 | if( error != 0 ) { | |
3610 | /* no snpa - cannot send */ | |
3611 | IFDEBUG(D_CADDR) | |
3612 | printf("NSAPtoDTE: 8208resolve: %d\n", error ); | |
3613 | ENDDEBUG | |
3614 | return 0; | |
3615 | } | |
3616 | ASSERT(x121strlen == sizeof(struct dte_addr)); | |
3617 | dtea = (struct dte_addr *)x121string; | |
3618 | x121strlen = dtea->dtea_niblen; | |
3619 | ||
3620 | nibble_copy((char *)x121string, HIGH_NIBBLE, | |
3621 | dst_octet, dst_nibble, x121strlen); | |
3622 | return x121strlen; | |
3623 | } | |
3624 | ||
3625 | /* | |
3626 | * NAME: FACILtoNSAP() | |
3627 | * CALLED FROM: | |
3628 | * parse_facil() | |
3629 | * FUNCTION and ARGUMENTS: | |
3630 | * Creates and NSAP in the sockaddr_iso (addr) from the | |
3631 | * x.25 facility found at (buf), of length (buf_len). | |
3632 | * RETURNS: | |
3633 | * 0 if ok, non-zero if error; | |
3634 | */ | |
3635 | ||
3636 | Static int | |
3637 | FACILtoNSAP( buf, buf_len, addr) | |
3638 | caddr_t buf; | |
3639 | u_char buf_len; /* in bytes */ | |
3640 | register struct sockaddr_iso *addr; | |
3641 | { | |
3642 | int len_in_nibbles; | |
3643 | ||
3644 | IFDEBUG(D_CADDR) | |
3645 | printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n", | |
3646 | buf, buf_len, addr ); | |
3647 | ENDDEBUG | |
3648 | ||
3649 | len_in_nibbles = *buf; | |
3650 | /* despite the fact that X.25 makes us put a length in nibbles | |
3651 | * here, the NSAP-addrs are always in full octets | |
3652 | */ | |
3653 | buf ++; | |
3654 | ||
3655 | bzero( addr, sizeof (struct sockaddr_iso) ); | |
3656 | ||
3657 | ASSERT(buf_len <= 1+sizeof (struct iso_addr)); | |
3658 | if(buf_len > 1+sizeof (struct iso_addr)) { | |
3659 | return -1; /* error */ | |
3660 | } | |
3661 | ASSERT(len_in_nibbles == (buf_len - 1)<<1); | |
3662 | if(len_in_nibbles != (buf_len - 1)<<1) { | |
3663 | return -2; /* error */ | |
3664 | } | |
3665 | bcopy(buf, &addr->siso_addr.isoa_afi, buf_len-1); | |
3666 | addr->siso_addr.isoa_len = buf_len-1; | |
3667 | IFDEBUG(D_CADDR) | |
3668 | printf("FACILtoNSAP: isoa_len 0x%x\n", | |
3669 | addr->siso_addr.isoa_len); | |
3670 | ENDDEBUG | |
3671 | addr->siso_family = AF_ISO; | |
3672 | ||
3673 | addr->siso_tsuffix = | |
3674 | unmunge( ((caddr_t)&addr->siso_addr.t37_idi) + ADDR37_IDI_LEN , 1 ); | |
3675 | return 0; | |
3676 | } | |
3677 | ||
3678 | /* | |
3679 | * NAME: DTEtoNSAP() | |
3680 | * CALLED FROM: | |
3681 | * parse_facil() | |
3682 | * FUNCTION and ARGUMENTS: | |
3683 | * Creates a type 37 NSAP in the sockaddr_iso (addr) | |
3684 | * from a DTE address found at the (src_nibble)th nibble of | |
3685 | * the octet (src_octet), of length (src_nib_len). | |
3686 | * | |
3687 | * RETURNS: | |
3688 | * 0 if ok; E* otherwise. | |
3689 | */ | |
3690 | ||
3691 | Static int | |
3692 | DTEtoNSAP(addr, src_octet, src_nibble, src_nib_len) | |
3693 | struct sockaddr_iso *addr; | |
3694 | caddr_t src_octet; | |
3695 | int src_nibble, src_nib_len; | |
3696 | { | |
3697 | caddr_t dst_octet; | |
3698 | int pad_len; | |
3699 | int dst_nibble; | |
3700 | char first_nib; | |
3701 | static char *z_pad = "\0\0\0\0\0\0\0"; | |
3702 | static char *f_pad = "\021\021\021\021\021\021\021"; | |
3703 | ||
3704 | IFDEBUG(D_CADDR) | |
3705 | printf("DTEtoNSAP( 0x%x, 0x%x, 0x%x, 0x%x )\n", | |
3706 | src_octet, src_nibble, src_nib_len, addr ); | |
3707 | ENDDEBUG | |
3708 | ||
3709 | bzero( addr, sizeof(*addr)); | |
3710 | addr->siso_family = AF_ISO; | |
3711 | /* | |
3712 | * Coming from a DTE addr it's always type 37. | |
3713 | * src_octet <-- starting place in the NSAP-address of | |
3714 | * the embedded SNPA-address (x.121 addr or DTE addr). | |
3715 | */ | |
3716 | addr->siso_addr.isoa_afi = 0x37; | |
3717 | ||
3718 | /* first, figure out what pad to use and pad */ | |
3719 | ||
3720 | first_nib = (*src_octet) >> (SHIFT*(1-src_nibble)); | |
3721 | pad_len = (ADDR37_IDI_LEN<<1 - src_nib_len); | |
3722 | nibble_copy(first_nib? z_pad : f_pad, HIGH_NIBBLE, | |
3723 | (caddr_t) addr->siso_addr.t37_idi, HIGH_NIBBLE, pad_len); | |
3724 | ||
3725 | dst_octet += (pad_len>>1); | |
3726 | dst_nibble = 1-(pad_len & 0x1); | |
3727 | IFDEBUG(D_CADDR) | |
3728 | printf("DTEtoNSAP 2( 0x%x, 0x%x, 0x%x, 0x%x )\n", | |
3729 | dst_octet, dst_nibble, pad_len, src_nib_len ); | |
3730 | ENDDEBUG | |
3731 | ||
3732 | /* now copy the dte address */ | |
3733 | nibble_copy( src_octet, src_nibble, dst_octet, dst_nibble, src_nib_len); | |
3734 | ||
3735 | addr->siso_addr.isoa_len = ADDR37_IDI_LEN + ADDR37_DSP_LEN +1 /* for afi */; | |
3736 | /* kludge */ | |
3737 | ||
3738 | addr->siso_tsuffix = unmunge( | |
3739 | (caddr_t) &(addr->siso_addr.t37_idi[ADDR37_IDI_LEN]), HIGH_NIBBLE); | |
3740 | ||
3741 | IFDEBUG(D_CADDR) | |
3742 | printf("DTEtoNSAP 3 returning 0 tsuffix 0x%x\n", addr->siso_tsuffix); | |
3743 | ENDDEBUG | |
3744 | ||
3745 | return 0; /* ok */ | |
3746 | } | |
3747 | ||
3748 | /* | |
3749 | * FUNCTION and ARGUMENTS: | |
3750 | * parses (buf_len) bytes beginning at (buf) and finds | |
3751 | * a called nsap, a calling nsap, and protocol identifier. | |
3752 | * RETURNS: | |
3753 | * 0 if ok, E* otherwise. | |
3754 | */ | |
3755 | ||
3756 | Static int | |
3757 | parse_facil( buf, buf_len, called, calling, proto, peer_dte) | |
3758 | caddr_t buf; | |
3759 | u_char buf_len; /* in bytes */ | |
3760 | register struct sockaddr_iso *called, *calling; | |
3761 | int *proto; | |
3762 | struct dte_addr *peer_dte; | |
3763 | { | |
3764 | register int i; | |
3765 | caddr_t ptr; | |
3766 | caddr_t facil_len; | |
3767 | int facil_param_len; | |
3768 | struct sockaddr_iso *addr; | |
3769 | int addrs_not_parsed = (int)0xcb + (int)0xc9; | |
3770 | ||
3771 | IFDEBUG(D_CADDR) | |
3772 | printf("parse_facil( 0x%x, 0x%x, 0x%x, 0x%x, 0x%x )\n", | |
3773 | buf, buf_len, called, calling, *proto); | |
3774 | dump_buf(buf, buf_len); | |
3775 | ENDDEBUG | |
3776 | ||
3777 | /* find the beginnings of the facility fields in buf | |
3778 | * by skipping over the called & calling DTE addresses | |
3779 | * i <- # nibbles in called + # nibbles in calling | |
3780 | * i += 1 so that an odd nibble gets rounded up to even | |
3781 | * before dividing by 2, then divide by two to get # octets | |
3782 | */ | |
3783 | i = (int)(*buf >> 4) + (int)(*buf&0xf); | |
3784 | i++; | |
3785 | ptr = (caddr_t) (buf + (i>>1)); | |
3786 | /* now i is number of octets */ | |
3787 | ||
3788 | ptr ++; /* plus one for the DTE lengths byte */ | |
3789 | ||
3790 | /* ptr now is at facil_length field */ | |
3791 | facil_len = ptr++; | |
3792 | IFDEBUG(D_CADDR) | |
3793 | printf("parse_facils: facil length is 0x%x\n", (int) *facil_len); | |
3794 | ENDDEBUG | |
3795 | ||
3796 | while( ptr <= (caddr_t)(facil_len + (int)*facil_len) ) { | |
3797 | /* get NSAP addresses from facilities */ | |
3798 | switch (*ptr) { | |
3799 | case 0xcb: | |
3800 | facil_param_len = 0; | |
3801 | addr = calling; | |
3802 | addrs_not_parsed -= 0xcb; | |
3803 | break; | |
3804 | case 0xc9: | |
3805 | facil_param_len = 0; | |
3806 | addr = called; | |
3807 | addrs_not_parsed -= 0xc9; | |
3808 | break; | |
3809 | ||
3810 | /* from here to default are legit cases that I ignore */ | |
3811 | ||
3812 | /* variable length */ | |
3813 | case 0xca: /* end-to-end transit delay negot */ | |
3814 | case 0xc6: /* network user id */ | |
3815 | case 0xc5: /* charging info : indicating monetary unit */ | |
3816 | case 0xc2: /* charging info : indicating segment count */ | |
3817 | case 0xc1: /* charging info : indicating call duration */ | |
3818 | case 0xc4: /* RPOA extended format */ | |
3819 | case 0xc3: /* call redirection notification */ | |
3820 | facil_param_len = 0; | |
3821 | addr = (struct sockaddr_iso *)0; | |
3822 | break; | |
3823 | ||
3824 | /* 1 octet */ | |
3825 | case 0x0a: /* min. throughput class negot */ | |
3826 | case 0x02: /* throughput class */ | |
3827 | case 0x03: case 0x47: /* CUG shit */ | |
3828 | case 0x0b: /* expedited data negot */ | |
3829 | case 0x01: /* Fast select or reverse charging | |
3830 | (example of intelligent protocol design) */ | |
3831 | case 0x04: /* charging info : requesting service */ | |
3832 | case 0x08: /* called line addr modified notification */ | |
3833 | facil_param_len = 1; | |
3834 | addr = (struct sockaddr_iso *)0; | |
3835 | break; | |
3836 | ||
3837 | /* any 2 octets */ | |
3838 | case 0x42: /* pkt size */ | |
3839 | case 0x43: /* win size */ | |
3840 | case 0x44: /* RPOA basic format */ | |
3841 | case 0x41: /* bilateral CUG shit */ | |
3842 | case 0x49: /* transit delay selection and indication */ | |
3843 | facil_param_len = 2; | |
3844 | addr = (struct sockaddr_iso *)0; | |
3845 | break; | |
3846 | ||
3847 | /* don't have any 3 octets */ | |
3848 | /* | |
3849 | facil_param_len = 3; | |
3850 | */ | |
3851 | default: | |
3852 | ASSERT(0); | |
3853 | printf( | |
3854 | "BOGUS FACILITY CODE facil_len 0x%x *facil_len 0x%x, ptr 0x%x *ptr 0x%x\n", | |
3855 | facil_len, *facil_len, | |
3856 | ptr, *ptr); | |
3857 | addr = (struct sockaddr_iso *)0; | |
3858 | /* facil that we don't handle */ | |
3859 | return E_CO_HLI_REJI; | |
3860 | } | |
3861 | ptr++; /* one for facil code */ | |
3862 | if(facil_param_len == 0) /* variable length */ | |
3863 | facil_param_len = (int)*ptr; /* 1 + the real facil param */ | |
3864 | if( addr && FACILtoNSAP(ptr+1, facil_param_len-1, addr) ) { | |
3865 | return E_CO_OSI_UNSAP; | |
3866 | } | |
3867 | ptr += facil_param_len; | |
3868 | } | |
3869 | if( addrs_not_parsed ) { | |
3870 | /* no facilities, get NSAP addresses from DTE addresses */ | |
3871 | register int ed, ing; | |
3872 | ||
3873 | ed = (int)(*buf&0xf); | |
3874 | if( ed == 0 ) { | |
3875 | panic("Called DTE address absent"); | |
3876 | } | |
3877 | DTEtoNSAP(called, (buf + 1)/*octet*/, | |
3878 | 1/*nibble*/, ed); | |
3879 | ||
3880 | ing = (int)(*buf >> 4); | |
3881 | if( ing == 0 ) { | |
3882 | printf("cons: panic: Calling DTE address absent"); | |
3883 | return E_CO_HLI_REJI; | |
3884 | } | |
3885 | nibble_copy((buf + (ed>>1)+1)/*octet*/, 1-(ed&0x1)/*nibble*/, | |
3886 | peer_dte->dtea_addr, HIGH_NIBBLE, ing); | |
3887 | DTEtoNSAP(calling, (buf + (ed>>1)+1)/*octet*/, | |
3888 | 1-(ed&0x1)/*nibble*/, ing); | |
3889 | ||
3890 | } | |
3891 | ||
3892 | ASSERT( ptr == (caddr_t)(facil_len + 1 + (int)*facil_len) ); | |
3893 | ||
3894 | /* | |
3895 | * now look for user data to find protocol identifier | |
3896 | */ | |
3897 | if( ptr == buf + buf_len ) { | |
3898 | /* no user data */ | |
3899 | *proto = ISOPROTO_TP; /* to proto id --> use TP */ | |
3900 | IFDEBUG(D_CADDR) | |
3901 | printf("NO USER DATA: use TP\n"); | |
3902 | ENDDEBUG | |
3903 | } else { | |
3904 | ASSERT ( ptr < buf + buf_len ); | |
3905 | if ( ptr >= buf + buf_len ) { | |
3906 | printf("ptr 0x%x buf 0x%x buf_len 0x%x buf+buf_len 0x%x\n", | |
3907 | ptr, buf, buf_len, buf+buf_len); | |
3908 | } | |
3909 | IFDEBUG(D_CADDR) | |
3910 | printf("proto byte 0x%x, value 0x%x\n", ptr, *ptr); | |
3911 | ENDDEBUG | |
3912 | switch(*ptr) { | |
3913 | case 0x81: | |
3914 | *proto = ISOPROTO_CLNP; | |
3915 | break; | |
3916 | case 0x0: | |
3917 | *proto = ISOPROTO_INACT_NL; | |
3918 | break; | |
3919 | case 'e': /* for EAN */ | |
3920 | *proto = ISOPROTO_TP; | |
3921 | /* can check for "an2" or can ignore the rest of the u data */ | |
3922 | break; | |
3923 | case 0xff: /* reserved for future extensions */ | |
3924 | *proto = ISOPROTO_X25; | |
3925 | break; | |
3926 | case 0x82: /* 9542 not implemented */ | |
3927 | case 0x84: /* 8878/A SNDCP not implemented */ | |
3928 | default: | |
3929 | *proto = -1; | |
3930 | return E_CO_HLI_PROTOID; | |
3931 | } | |
3932 | } | |
3933 | return 0; | |
3934 | } | |
3935 | ||
3936 | #endif NARGOXTWENTYFIVE > 0 |