Commit | Line | Data |
---|---|---|
b5c41248 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_lpb.c,v 4.2 88/06/29 14:59:38 hagens Exp $ | |
29 | * $Source: /usr/argo/sys/netiso/RCS/if_lpb.c,v $ | |
30 | * | |
31 | * LOOPBACK driver that mimics the | |
32 | * Eicon x.25 board for use by CONS | |
33 | */ | |
34 | ||
35 | #ifndef lint | |
36 | static char *rcsid = "$Header: if_lpb.c,v 4.2 88/06/29 14:59:38 hagens Exp $"; | |
37 | #endif lint | |
38 | ||
39 | ||
40 | #include "param.h" | |
41 | #include "systm.h" | |
42 | #include "types.h" | |
43 | #include "mbuf.h" | |
44 | #include "buf.h" | |
45 | #include "protosw.h" | |
46 | #include "socket.h" | |
47 | #include "ioctl.h" | |
48 | #include "errno.h" | |
49 | ||
50 | #include "../net/if.h" | |
51 | #include "../net/netisr.h" | |
52 | #include "../net/route.h" | |
d301d150 | 53 | #include "machine/io.h" |
b5c41248 KS |
54 | #include "../machineio/ioccvar.h" |
55 | ||
56 | #include "ecn.h" | |
a50e2bc0 KS |
57 | #include "iso.h" |
58 | #include "argo_debug.h" | |
b5c41248 KS |
59 | #include "../caif/eicon.h" |
60 | #include "iso_errno.h" | |
61 | ||
62 | #define LPB_DEBUG | |
63 | #ifdef LPB_DEBUG | |
64 | #define MT_LPB_OPEN 0x55 | |
65 | #define MT_LPB_ACK 0x56 | |
66 | #else LPB_DEBUG | |
67 | #define MT_LPB_DATA MT_DATA | |
68 | #define MT_LPB_ACK MT_DATA | |
69 | #endif LPB_DEBUG | |
70 | ||
71 | extern struct ifqueue consintrq; | |
72 | int lpboutput(); | |
73 | ||
74 | /* These next 2 declarations are for Logical Unit Numbers - i.e. VC # - | |
75 | * the 2I assigns and frees them; we have to fake it | |
76 | */ | |
77 | ||
78 | static u_char free_luns[32]; | |
79 | static u_char *next_lun = free_luns; | |
80 | ||
81 | /* | |
82 | * Initialize all LUNs as available for use. | |
83 | */ | |
84 | init_lpb() | |
85 | { | |
86 | register int i; | |
87 | ||
88 | for (i = 0; i < 32; i++) { | |
89 | free_luns[i] = i+1; | |
90 | } | |
91 | next_lun = free_luns; | |
92 | } | |
93 | ||
94 | /* | |
95 | * Allocate new logical unit number. | |
96 | * Allocating number n means that both n and -n are allocated & used. | |
97 | * NOTE: next_lun always points to an UNALLOCATED lun, hence | |
98 | * take a lun then increment, or decrement then stash the lun. | |
99 | */ | |
100 | ||
101 | u_char | |
102 | getlun() | |
103 | { | |
104 | if( ((next_lun) - free_luns) > 32 ) { | |
105 | printf("PANIC: if_lpb: too many channels! \n"); | |
106 | return 0; | |
107 | } | |
108 | IFDEBUG(D_CCONN) | |
109 | printf("getlun: returns 0x%x\n", *next_lun); | |
110 | ENDDEBUG | |
111 | ASSERT( *next_lun != 0 ); | |
112 | if( *next_lun == 0 ) { | |
113 | register int i; | |
114 | ||
115 | printf( | |
116 | "PANIC IN lpb: free_luns 0x%x next_len 0x%x *next_lun 0x%x\n", | |
117 | free_luns, next_lun, *next_lun); | |
118 | ||
119 | for(i=0; i<32; i++) { | |
120 | printf("free_luns[ 0x%x ] = 0x%x\n", i, free_luns[i] ); | |
121 | } | |
122 | } | |
123 | return *(next_lun++); | |
124 | ||
125 | } | |
126 | ||
127 | /* | |
128 | * When you free one you free its neg | |
129 | */ | |
130 | ||
131 | freelun(lun) | |
132 | u_char lun; | |
133 | { | |
134 | IFDEBUG(D_CCONN) | |
135 | printf("freelun(0x%x)\n", lun); | |
136 | ENDDEBUG | |
137 | if( lun > 32 ) | |
138 | return; | |
139 | ||
140 | ASSERT( (lun & 0xc0) == 0 ); | |
141 | ASSERT( lun <= 32 ); | |
142 | ||
143 | /* check for lun already in the list */ | |
144 | { | |
145 | register u_char *r = next_lun; | |
146 | ||
147 | while( (int)(r - free_luns) <= 32 ) { | |
148 | if( *r == lun ) { | |
149 | return; | |
150 | } | |
151 | r++; | |
152 | } | |
153 | } | |
154 | ||
155 | next_lun --; | |
156 | *next_lun = lun; | |
157 | } | |
158 | ||
159 | ||
160 | /* | |
161 | * FUNCTION: lpboutput | |
162 | * | |
163 | * PURPOSE: Process an eicon x.25 request from a higher layer | |
164 | * protocol. | |
165 | * ARGUMENTS: (ifp) is points to the ifnet structure for this unit/device | |
166 | * (m) is an mbuf *, *m is an eicon request structure | |
167 | * | |
168 | * RETURNS: unix error code | |
169 | * | |
170 | * NOTES: Mimics the eicon driver. | |
171 | * | |
172 | */ | |
173 | lpboutput(ifp,m) | |
174 | register struct ifnet *ifp; | |
175 | register struct mbuf *m; /* request */ | |
176 | { | |
177 | int s; | |
178 | struct eicon_request *req; | |
179 | int error = 0; | |
180 | ||
181 | /* Do this even if (ifp->if_flags & IFF_LOOPBACK) == 0 | |
182 | * because whether or not a vc is on loopback is determined | |
183 | * at the time of connection establishement. | |
184 | */ | |
185 | s = splnet(); | |
186 | req = mtod(m, struct eicon_request *); | |
187 | IFDEBUG(D_CDUMP_REQ) | |
188 | dump_buf(req, sizeof(struct eicon_request)); | |
189 | ENDDEBUG | |
190 | switch (req->e_cmd) { | |
191 | case ECN_CALL: { | |
192 | /* | |
193 | * ECN_CALL -> ECN_ACCEPT (for orig CONNECT) | |
194 | * -> ECN_CONNECT (other side's connect indication) | |
195 | */ | |
196 | struct mbuf *mdata; | |
197 | struct mbuf *mopen; | |
198 | struct eicon_request *open; | |
199 | ||
200 | MGET(mopen, M_DONTWAIT, MT_LPB_OPEN); | |
201 | if (mopen == NULL) { | |
202 | printf("No mbufs for copy\n"); | |
203 | error = ENOBUFS; | |
204 | break; | |
205 | } | |
206 | mopen->m_len = sizeof(struct eicon_request); | |
207 | ||
208 | open = mtod(mopen, struct eicon_request *); | |
209 | bcopy( req, open, sizeof(struct eicon_request) ); | |
210 | ||
211 | /* get mbuf for the connect data */ | |
212 | MGET(mdata, M_DONTWAIT, MT_LPB_OPEN); | |
213 | if (mdata == NULL) { | |
214 | printf("No mbufs for copy\n"); | |
215 | error = ENOBUFS; | |
216 | break; | |
217 | } | |
218 | mdata->m_len = (e_data(req))->m_len; | |
219 | e_data(open) = mdata; /* e_data is really mtod(open)->m_next */ | |
220 | /* make a copy of the connect data */ | |
221 | IFDEBUG(D_CCONN) | |
222 | printf("bcopy( 0x%x, 0x%x, 0x%x)\n", mtod(e_data(req), caddr_t), | |
223 | mtod(mdata, caddr_t), | |
224 | (e_data(req))->m_len); | |
225 | ENDDEBUG | |
226 | bcopy( mtod(e_data(req), caddr_t), mtod(mdata, caddr_t), | |
227 | (e_data(req))->m_len); | |
228 | /* setup call */ | |
229 | open->e_cmd = ECN_CONNECT; | |
230 | open->e_vc = getlun(); | |
231 | ||
232 | /* setup call confirm */ | |
233 | req->e_cmd = ECN_ACCEPT; | |
234 | req->e_vc = -(open->e_vc); | |
235 | ||
236 | IFDEBUG(D_CDUMP_REQ) | |
237 | printf("lpboutput CALL middle \n"); | |
238 | ENDDEBUG | |
239 | ||
240 | if (IF_QFULL(&consintrq)) { | |
241 | IF_DROP(&consintrq); | |
242 | m_freem(mopen); | |
243 | printf("lpboutput: response dropped\n"); | |
244 | error = ENOBUFS; | |
245 | break; | |
246 | } else { | |
247 | /* connect */ | |
248 | IFDEBUG(D_CCONS); | |
249 | printf("CONNECT 0x%x --> X25INTRQ\n", mopen); | |
250 | ENDDEBUG | |
251 | IF_ENQUEUE(&consintrq, mopen); | |
252 | IFDEBUG(D_CDUMP_REQ); | |
253 | dump_buf(open, sizeof(struct eicon_request)); | |
254 | ENDDEBUG | |
255 | ||
256 | /* confirm */ | |
257 | IFDEBUG(D_CCONS); | |
258 | printf("CONFIRM 0x%x (data 0x%x =?= 0x%x) --> X25INTRQ\n", | |
259 | m, m->m_next, e_data(req)); | |
260 | ENDDEBUG | |
261 | IF_ENQUEUE(&consintrq, m); | |
262 | IFDEBUG(D_CDUMP_REQ); | |
263 | dump_buf(req, sizeof(struct eicon_request)); | |
264 | ENDDEBUG | |
265 | } | |
266 | } break; | |
267 | ||
268 | case ECN_RESET: | |
269 | case ECN_CLEAR: { | |
270 | /* | |
271 | * ECN_RESET -> ECN_RESET (other side's reset indication) | |
272 | * ECN_CLEAR -> ECN_CLEAR (other side's close indication) | |
273 | * TODO: MAY HAVE DATA PACKET! | |
274 | * TODO: Have to be able to handle a 2nd CLEAR on on vc! | |
275 | */ | |
276 | freelun(req->e_vc); | |
277 | freelun((-req->e_vc)&0xff); | |
278 | req->e_vc = -req->e_vc; /* other side */ | |
279 | req->e_reason = E_CO_PDNCLRESET; | |
280 | if (IF_QFULL(&consintrq)) { | |
281 | IF_DROP(&consintrq); | |
282 | printf("lpboutput: respose dropped\n"); | |
283 | error = ENOBUFS; | |
284 | } else { | |
285 | IFDEBUG(D_CCONS); | |
286 | printf("CLOSE 0x%x --> X25INTRQ\n", m); | |
287 | ENDDEBUG | |
288 | IF_ENQUEUE(&consintrq, m); | |
289 | IFDEBUG(D_CDUMP_REQ); | |
290 | dump_buf(req, sizeof(struct eicon_request)); | |
291 | ENDDEBUG | |
292 | } | |
293 | } break; | |
294 | ||
295 | case ECN_SEND: { | |
296 | /* | |
297 | * ECN_SEND -> ECN_RECEIVE (data send becomes data recvd) | |
298 | */ | |
299 | struct mbuf *m0; | |
300 | struct eicon_request *ack; | |
301 | ||
302 | MGET(m0, M_DONTWAIT, MT_LPB_ACK); /* sets type, next, off */ | |
303 | if (m0 == NULL) { | |
304 | printf("PANIC No mbufs for copy\n"); | |
305 | error = ENOBUFS; | |
306 | break; | |
307 | } | |
308 | m0->m_len = sizeof(struct eicon_request); | |
309 | ||
310 | ack = mtod(m0, struct eicon_request *); | |
311 | /* setup ack */ | |
312 | ack->e_cmd = ECN_ACK; | |
313 | ack->e_vc = req->e_vc; | |
314 | req->e_vc = -req->e_vc; | |
315 | req->e_cmd = ECN_RECEIVE; | |
316 | ||
317 | if (IF_QFULL(&consintrq)) { | |
318 | IF_DROP(&consintrq); | |
319 | printf("lpboutput: ADR_ACK DROPPED\n"); | |
320 | m_freem(m0); | |
321 | error = ECONNABORTED; | |
322 | } else { | |
323 | IF_ENQUEUE(&consintrq, m); | |
324 | IFDEBUG(D_CCONS); | |
325 | printf("DATA 0x%x --> X25INTRQ\n", m); | |
326 | ENDDEBUG | |
327 | IFDEBUG(D_CDUMP_REQ); | |
328 | dump_buf(req, sizeof(struct eicon_request)); | |
329 | ENDDEBUG | |
330 | IFDEBUG(D_CCONS); | |
331 | printf("ACK 0x%x --> X25INTRQ\n", m0); | |
332 | ENDDEBUG | |
333 | IF_ENQUEUE(&consintrq, m0); | |
334 | IFDEBUG(D_CDUMP_REQ); | |
335 | dump_buf(ack, sizeof(struct eicon_request)); | |
336 | ENDDEBUG | |
337 | } | |
338 | } break; | |
339 | ||
340 | default: | |
341 | printf("Bad loopback request 0x%x\n", req->e_cmd); | |
342 | error = EINVAL; | |
343 | } | |
344 | ||
345 | if( error ) { | |
346 | m_freem(m); | |
347 | } else | |
348 | schednetisr(NETISR_X25); | |
349 | ||
350 | splx(s); | |
351 | return error; | |
352 | } | |
353 | ||
354 | #if NECN>0 | |
355 | /* nothing */ | |
356 | #else | |
357 | ||
358 | /* KLUDGE: when no ecn board config-ed in, we need a routing | |
359 | * ecnifp to return null. We want to be able to configure with | |
360 | * sw loopback only. | |
361 | */ | |
362 | struct ifnet * | |
363 | ecnifp(unit) | |
364 | int unit; | |
365 | { | |
366 | return (struct ifnet *)NULL; | |
367 | } | |
368 | ||
369 | int | |
370 | ecnoutput(ifp, m) | |
371 | struct ifnet *ifp; | |
372 | struct mbuf *m; | |
373 | { | |
374 | printf("ecnoutput: ecn not configured\n"); | |
375 | (void) m_freem(m); | |
376 | return ENETDOWN; | |
377 | ||
378 | } | |
379 | ||
380 | ecnshutdown(ifp) | |
381 | { | |
382 | printf("ecnshutdown: ecn not configured\n"); | |
383 | } | |
384 | ||
385 | ecnrestart(ifp) | |
386 | { | |
387 | printf("ecnrestart: ecn not configured\n"); | |
388 | } | |
389 | #endif NECN>0 |