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" 53 #include "machine/io.h" 54 #include "../machineio/ioccvar.h" 55 56 #include "ecn.h" 57 #include "iso.h" 58 #include "argo_debug.h" 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 390