1/* 2 * $Id: ddp_input.c,v 1.4 2002-01-04 04:45:48 sibaz Exp $ 3 * 4 * Copyright (c) 1990,1994 Regents of The University of Michigan. 5 * All Rights Reserved. See COPYRIGHT. 6 */ 7 8#ifdef HAVE_CONFIG_H 9#include "config.h" 10#endif /* HAVE_CONFIG_H */ 11 12#include <sys/types.h> 13#include <sys/param.h> 14#include <sys/mbuf.h> 15#include <sys/socket.h> 16#include <sys/socketvar.h> 17#include <atalk/logger.h> 18#include <net/if.h> 19#include <net/route.h> 20#ifdef _IBMR2 21#include <net/spl.h> 22#endif /* _IBMR2 */ 23 24#include "at.h" 25#include "at_var.h" 26#include "endian.h" 27#include "ddp.h" 28#include "ddp_var.h" 29 30int ddp_forward = 1; 31int ddp_firewall = 0; 32extern int ddp_cksum; 33extern u_short at_cksum(); 34 35/* 36 * Could probably merge these two code segments a little better... 37 */ 38atintr() 39{ 40 struct elaphdr *elhp, elh; 41 struct ifnet *ifp; 42 struct mbuf *m; 43 struct at_ifaddr *aa; 44 int s; 45 46 for (;;) { 47#ifndef _IBMR2 48 s = splimp(); 49#endif /* ! _IBMR2 */ 50 51#ifdef BSD4_4 52 IF_DEQUEUE( &atintrq2, m ); 53#else /* BSD4_4 */ 54 IF_DEQUEUEIF( &atintrq2, m, ifp ); 55#endif /* BSD4_4 */ 56 57#ifndef _IBMR2 58 splx( s ); 59#endif /* ! _IBMR2 */ 60 61 if ( m == 0 ) { /* no more queued packets */ 62 break; 63 } 64 65#ifdef BSD4_4 66 ifp = m->m_pkthdr.rcvif; 67#endif /* BSD4_4 */ 68 for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { 69 if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 )) { 70 break; 71 } 72 } 73 if ( aa == NULL ) { /* ifp not an appletalk interface */ 74 m_freem( m ); 75 continue; 76 } 77 78 ddp_input( m, ifp, (struct elaphdr *)NULL, 2 ); 79 } 80 81 for (;;) { 82#ifndef _IBMR2 83 s = splimp(); 84#endif /* ! _IBMR2 */ 85 86#ifdef BSD4_4 87 IF_DEQUEUE( &atintrq1, m ); 88#else /* BSD4_4 */ 89 IF_DEQUEUEIF( &atintrq1, m, ifp ); 90#endif /* BSD4_4 */ 91 92#ifndef _IBMR2 93 splx( s ); 94#endif /* ! _IBMR2 */ 95 96 if ( m == 0 ) { /* no more queued packets */ 97 break; 98 } 99 100#ifdef BSD4_4 101 ifp = m->m_pkthdr.rcvif; 102#endif /* BSD4_4 */ 103 for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { 104 if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { 105 break; 106 } 107 } 108 if ( aa == NULL ) { /* ifp not an appletalk interface */ 109 m_freem( m ); 110 continue; 111 } 112 113 if ( m->m_len < SZ_ELAPHDR && 114 (( m = m_pullup( m, SZ_ELAPHDR )) == 0 )) { 115 ddpstat.ddps_tooshort++; 116 continue; 117 } 118 119 elhp = mtod( m, struct elaphdr *); 120 m_adj( m, SZ_ELAPHDR ); 121 122 if ( elhp->el_type == ELAP_DDPEXTEND ) { 123 ddp_input( m, ifp, (struct elaphdr *)NULL, 1 ); 124 } else { 125 bcopy((caddr_t)elhp, (caddr_t)&elh, SZ_ELAPHDR ); 126 ddp_input( m, ifp, &elh, 1 ); 127 } 128 } 129 return; 130} 131 132struct route forwro; 133 134ddp_input( m, ifp, elh, phase ) 135 struct mbuf *m; 136 struct ifnet *ifp; 137 struct elaphdr *elh; 138 int phase; 139{ 140 struct sockaddr_at from, to; 141 struct ddpshdr *dsh, ddps; 142 struct at_ifaddr *aa; 143 struct ddpehdr *deh, ddpe; 144#ifndef BSD4_4 145 struct mbuf *mp; 146#endif /* BSD4_4 */ 147 struct ddpcb *ddp; 148 int dlen, mlen; 149 u_short cksum; 150 151 bzero( (caddr_t)&from, sizeof( struct sockaddr_at )); 152 if ( elh ) { 153 ddpstat.ddps_short++; 154 155 if ( m->m_len < sizeof( struct ddpshdr ) && 156 (( m = m_pullup( m, sizeof( struct ddpshdr ))) == 0 )) { 157 ddpstat.ddps_tooshort++; 158 return; 159 } 160 161 dsh = mtod( m, struct ddpshdr *); 162 bcopy( (caddr_t)dsh, (caddr_t)&ddps, sizeof( struct ddpshdr )); 163 ddps.dsh_bytes = ntohl( ddps.dsh_bytes ); 164 dlen = ddps.dsh_len; 165 166 to.sat_addr.s_net = 0; 167 to.sat_addr.s_node = elh->el_dnode; 168 to.sat_port = ddps.dsh_dport; 169 from.sat_addr.s_net = 0; 170 from.sat_addr.s_node = elh->el_snode; 171 from.sat_port = ddps.dsh_sport; 172 173 for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { 174 if ( aa->aa_ifp == ifp && ( aa->aa_flags & AFA_PHASE2 ) == 0 && 175 ( AA_SAT( aa )->sat_addr.s_node == to.sat_addr.s_node || 176 to.sat_addr.s_node == ATADDR_BCAST )) { 177 break; 178 } 179 } 180 if ( aa == NULL ) { 181 m_freem( m ); 182 return; 183 } 184 } else { 185 ddpstat.ddps_long++; 186 187 if ( m->m_len < sizeof( struct ddpehdr ) && 188 (( m = m_pullup( m, sizeof( struct ddpehdr ))) == 0 )) { 189 ddpstat.ddps_tooshort++; 190 return; 191 } 192 193 deh = mtod( m, struct ddpehdr *); 194 bcopy( (caddr_t)deh, (caddr_t)&ddpe, sizeof( struct ddpehdr )); 195 ddpe.deh_bytes = ntohl( ddpe.deh_bytes ); 196 dlen = ddpe.deh_len; 197 198 if (( cksum = ddpe.deh_sum ) == 0 ) { 199 ddpstat.ddps_nosum++; 200 } 201 202 from.sat_addr.s_net = ddpe.deh_snet; 203 from.sat_addr.s_node = ddpe.deh_snode; 204 from.sat_port = ddpe.deh_sport; 205 to.sat_addr.s_net = ddpe.deh_dnet; 206 to.sat_addr.s_node = ddpe.deh_dnode; 207 to.sat_port = ddpe.deh_dport; 208 209 if ( to.sat_addr.s_net == 0 ) { 210 for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { 211 if ( phase == 1 && ( aa->aa_flags & AFA_PHASE2 )) { 212 continue; 213 } 214 if ( phase == 2 && ( aa->aa_flags & AFA_PHASE2 ) == 0 ) { 215 continue; 216 } 217 if ( aa->aa_ifp == ifp && 218 ( AA_SAT( aa )->sat_addr.s_node == to.sat_addr.s_node || 219 to.sat_addr.s_node == ATADDR_BCAST || 220 ( ifp->if_flags & IFF_LOOPBACK ))) { 221 break; 222 } 223 } 224 } else { 225 for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { 226 if ( to.sat_addr.s_net == aa->aa_firstnet && 227 to.sat_addr.s_node == 0 ) { 228 break; 229 } 230 if (( ntohs( to.sat_addr.s_net ) < ntohs( aa->aa_firstnet ) || 231 ntohs( to.sat_addr.s_net ) > ntohs( aa->aa_lastnet )) && 232 ( ntohs( to.sat_addr.s_net ) < 0xff00 || 233 ntohs( to.sat_addr.s_net ) > 0xfffe)) { 234 continue; 235 } 236 if ( to.sat_addr.s_node != AA_SAT( aa )->sat_addr.s_node && 237 to.sat_addr.s_node != ATADDR_BCAST ) { 238 continue; 239 } 240 break; 241 } 242 } 243 } 244 245 /* 246 * Adjust the length, removing any padding that may have been added 247 * at a link layer. We do this before we attempt to forward a packet, 248 * possibly on a different media. 249 */ 250#ifdef BSD4_4 251 mlen = m->m_pkthdr.len; 252#else /* BSD4_4 */ 253 for ( mlen = 0, mp = m; mp; mp = mp->m_next ) { 254 mlen += mp->m_len; 255 } 256#endif /* BSD4_4 */ 257 if ( mlen < dlen ) { 258 ddpstat.ddps_toosmall++; 259 m_freem( m ); 260 return; 261 } 262 if ( mlen > dlen ) { 263 m_adj( m, dlen - mlen ); 264 } 265 266 /* 267 * XXX Should we deliver broadcasts locally, also, or rely on the 268 * link layer to give us a copy? For the moment, the latter. 269 */ 270 if ( aa == NULL || ( to.sat_addr.s_node == ATADDR_BCAST && 271 aa->aa_ifp != ifp && ( ifp->if_flags & IFF_LOOPBACK ) == 0 )) { 272 if ( ddp_forward == 0 ) { 273 m_freem( m ); 274 return; 275 } 276 if ( forwro.ro_rt && ( satosat( &forwro.ro_dst )->sat_addr.s_net != 277 to.sat_addr.s_net || 278 satosat( &forwro.ro_dst )->sat_addr.s_node != 279 to.sat_addr.s_node )) { 280#ifdef ultrix 281 rtfree( forwro.ro_rt ); 282#else /* ultrix */ 283 RTFREE( forwro.ro_rt ); 284#endif /* ultrix */ 285 forwro.ro_rt = (struct rtentry *)0; 286 } 287 if ( forwro.ro_rt == (struct rtentry *)0 || 288 forwro.ro_rt->rt_ifp == (struct ifnet *)0 ) { 289#ifdef BSD4_4 290 forwro.ro_dst.sa_len = sizeof( struct sockaddr_at ); 291#endif /* BSD4_4 */ 292 forwro.ro_dst.sa_family = AF_APPLETALK; 293 satosat( &forwro.ro_dst )->sat_addr.s_net = to.sat_addr.s_net; 294 satosat( &forwro.ro_dst )->sat_addr.s_node = to.sat_addr.s_node; 295 rtalloc( &forwro ); 296 } 297 298 if ( to.sat_addr.s_net != satosat( &forwro.ro_dst )->sat_addr.s_net && 299 ddpe.deh_hops == DDP_MAXHOPS ) { 300 m_freem( m ); 301 return; 302 } 303 304 if ( ddp_firewall && 305 ( forwro.ro_rt == NULL || ( forwro.ro_rt->rt_ifp != ifp && 306 forwro.ro_rt->rt_ifp != at_ifaddr->aa_ifp ))) { 307 m_freem( m ); 308 return; 309 } 310 311 ddpe.deh_hops++; 312 ddpe.deh_bytes = htonl( ddpe.deh_bytes ); 313 bcopy( (caddr_t)&ddpe, (caddr_t)deh, sizeof( u_short )); 314 if ( ddp_route( m, &forwro )) { 315 ddpstat.ddps_cantforward++; 316 } else { 317 ddpstat.ddps_forward++; 318 } 319 return; 320 } 321 322#ifdef BSD4_4 323 from.sat_len = sizeof( struct sockaddr_at ); 324#endif /* BSD4_4 */ 325 from.sat_family = AF_APPLETALK; 326 327 if ( elh ) { 328 m_adj( m, sizeof( struct ddpshdr )); 329 } else { 330 if ( ddp_cksum && cksum && cksum != at_cksum( m, sizeof( int ))) { 331 ddpstat.ddps_badsum++; 332 m_freem( m ); 333 return; 334 } 335 m_adj( m, sizeof( struct ddpehdr )); 336 } 337 338 if (( ddp = ddp_search( &from, &to, aa )) == NULL ) { 339 m_freem( m ); 340 return; 341 } 342 343 if ( sbappendaddr( &ddp->ddp_socket->so_rcv, (struct sockaddr *)&from, 344 m, (struct mbuf *)0 ) == 0 ) { 345 ddpstat.ddps_nosockspace++; 346 m_freem( m ); 347 return; 348 } 349 sorwakeup( ddp->ddp_socket ); 350} 351 352m_printm( m ) 353 struct mbuf *m; 354{ 355 for (; m; m = m->m_next ) { 356 bprint( mtod( m, char * ), m->m_len ); 357 } 358} 359 360#define BPXLEN 48 361#define BPALEN 16 362#include <ctype.h> 363char hexdig[] = "0123456789ABCDEF"; 364 365bprint( data, len ) 366 char *data; 367 int len; 368{ 369 char xout[ BPXLEN ], aout[ BPALEN ]; 370 int i = 0; 371 372 bzero( xout, BPXLEN ); 373 bzero( aout, BPALEN ); 374 375 for ( ;; ) { 376 if ( len < 1 ) { 377 if ( i != 0 ) { 378 printf( "%s\t%s\n", xout, aout ); 379 } 380 printf( "%s\n", "(end)" ); 381 break; 382 } 383 384 xout[ (i*3) ] = hexdig[ ( *data & 0xf0 ) >> 4 ]; 385 xout[ (i*3) + 1 ] = hexdig[ *data & 0x0f ]; 386 387 if ( (u_char)*data < 0x7f && (u_char)*data > 0x20 ) { 388 aout[ i ] = *data; 389 } else { 390 aout[ i ] = '.'; 391 } 392 393 xout[ (i*3) + 2 ] = ' '; 394 395 i++; 396 len--; 397 data++; 398 399 if ( i > BPALEN - 2 ) { 400 printf( "%s\t%s\n", xout, aout ); 401 bzero( xout, BPXLEN ); 402 bzero( aout, BPALEN ); 403 i = 0; 404 continue; 405 } 406 } 407} 408