1/* 2 * $Id: at_sun.c,v 1.2 2001-08-06 13:39:30 rufustfirefly Exp $ 3 */ 4 5#include <sys/param.h> 6#include <sys/types.h> 7#include <sys/socket.h> 8#include <sys/mbuf.h> 9#include <sys/protosw.h> 10#include <sys/domain.h> 11#include <sys/errno.h> 12 13#include <net/if_arp.h> 14#include <net/if.h> 15#include <net/route.h> 16#include <net/af.h> 17#include <net/netisr.h> 18 19#include <sun/vddrv.h> 20 21#include <netinet/in.h> 22#undef s_net 23#include <netinet/if_ether.h> 24 25#include <netatalk/at.h> 26#include <netatalk/at_var.h> 27#include <netatalk/ddp_var.h> 28#include <netatalk/phase2.h> 29 30struct vdlat { 31 int vda_magic; 32 char *vda_name; 33} atvdl = { 34 VDMAGIC_USER, "netatalk" 35}; 36 37struct ifqueue *atef_input(); 38int atef_output(); 39extern int atintr(); 40 41extern u_char aarp_org_code[ 3 ]; 42extern u_char at_org_code[ 3 ]; 43 44/* 45 * Entries in this table are inserted into the ether_families linked 46 * list at the beginnning. As such, they will be searched by the input 47 * and output routines opposite to the order here. 48 * 49 * In order to do both phase 1 and phase 2 during output, we have a 50 * special entry (the AF_APPLETALK entry) whose ethertype field is 51 * changed by the output function, to reflect the actual link layer 52 * to be used. This ether_family entry is never seen during Ethernet 53 * input, since the earlier entry captures all packets (it is seen 54 * during loopback input, in that the input function is called directly 55 * on loopback output). 56 */ 57struct ether_family ether_atalk[] = { 58 { 59 AF_APPLETALK, 0, /* Changed by atef_output() */ 60 atef_input, atef_output, atintr, 61 }, 62 { 63 0, ETHERTYPE_AARP, 64 atef_input, 0, 0, 65 }, 66 { 67 0, ETHERTYPE_AT, 68 atef_input, 0, atintr, 69 }, 70 { 71 0, EF_8023_TYPE, 72 atef_input, 0, atintr, 73 }, 74}; 75int ether_atalkN = sizeof( ether_atalk ) / sizeof( ether_atalk[ 0 ] ); 76 77extern struct ether_family *ether_families; 78 79extern int atalk_hash(), atalk_netmatch(); 80extern int null_hash(), null_netmatch(); 81 82xxxinit( cmd, vdd, vdi, vds ) 83 unsigned int cmd; 84 struct vddrv *vdd; 85 addr_t vdi; 86 struct vdstat *vds; 87{ 88 struct ether_family *ef; 89 struct domain *dom; 90 struct protosw *pr; 91 int i; 92 93 switch( cmd ) { 94 case VDLOAD : 95 vdd->vdd_vdtab = (struct vdlinkage *)&atvdl; 96 97 /* 98 * Register with the network-interface layer (ethernet). 99 */ 100 for ( i = 0; i < ether_atalkN; i++ ) { 101 ether_register( ðer_atalk[ i ] ); 102 } 103 104 /* 105 * Register with the socket layer. 106 */ 107 atalkdomain.dom_next = domains; 108 domains = &atalkdomain; 109 if ( atalkdomain.dom_init ) { 110 (*atalkdomain.dom_init)(); 111 } 112 for ( pr = atalkdomain.dom_protosw; 113 pr < atalkdomain.dom_protoswNPROTOSW; pr++ ) { 114 if ( pr->pr_init ) { 115 (*pr->pr_init)(); 116 } 117 } 118 119 /* 120 * Cobble ourselves into the routing table. 121 */ 122 afswitch[ AF_APPLETALK ].af_hash = atalk_hash; 123 afswitch[ AF_APPLETALK ].af_netmatch = atalk_netmatch; 124 return( 0 ); 125 126 case VDUNLOAD : 127 /* 128 * Make sure that there are no open appletalk sockets. 129 */ 130 if ( ddpcb != NULL ) { 131 return( EMFILE ); 132 } 133 134 /* 135 * There is no ether_unregister(), so we'll have to do it 136 * our selves... 137 */ 138 for ( i = 0; i < ether_atalkN; i++ ) { 139 if ( ether_families == ðer_atalk[ i ] ) { 140 ether_families = ether_families->ef_next; 141 continue; 142 } else { 143 for ( ef = ether_families; ef->ef_next; ef = ef->ef_next ) { 144 if ( ef->ef_next == ðer_atalk[ i ] ) { 145 ef->ef_next = ef->ef_next->ef_next; 146 break; 147 } 148 } 149 } 150 } 151 152 /* 153 * Remove aarp timers and held packets. 154 */ 155 aarp_clean(); 156 157 /* 158 * Remove AppleTalk interface addresses. 159 */ 160 aa_clean(); 161 162 /* 163 * Remove our routines from the routing table. 164 */ 165 afswitch[ AF_APPLETALK ].af_hash = null_hash; 166 afswitch[ AF_APPLETALK ].af_netmatch = null_netmatch; 167 168 /* 169 * Remove atalkdomain from the domains list. 170 * Unlikely, but someone may have registered after us. 171 */ 172 if ( domains == &atalkdomain ) { 173 domains = domains->dom_next; 174 } else { 175 for ( dom = domains; dom->dom_next; dom = dom->dom_next ) { 176 if ( dom->dom_next == &atalkdomain ) { 177 dom->dom_next = dom->dom_next->dom_next; 178 break; 179 } 180 } 181 } 182 return( 0 ); 183 184 case VDSTAT : 185 return( 0 ); 186 default : 187 return( EIO ); 188 } 189} 190 191/* 192 * Input routine for netatalk on suns. There are five possible 193 * packets. First, packets received on the loopback interface 194 * are immediately sent to the phase 1 interrupt queue (this will 195 * have to change if we ever do a phase 2 only version). Second, 196 * IEEE802 packet are sent to either the aarpinput() routine or 197 * the phase 2 interrupt queue. Finally, DIX packets are sent 198 * to either aarpinput() or the phase 1 interrupt queue. 199 */ 200 struct ifqueue * 201atef_input( ifp, m, header ) 202 struct ifnet *ifp; 203 struct mbuf *m; 204 struct ether_header *header; 205{ 206 struct llc llc; 207 struct mbuf *n = 0; 208 209 /* 210 * Check first for LOOPBACK flag, since loopback code passes NULL for 211 * the header. 212 */ 213 if ( ifp->if_flags & IFF_LOOPBACK ) { 214 return( &atintrq2 ); 215 } 216 217 /* 218 * Before SunOS 4.1, the ether_type was passed as is from the 219 * packet. After SunOS 4.1, the ether_type is swapped in 220 * do_protocol(), before the ether_family routines are called. 221 */ 222#if defined( sun ) && defined( i386 ) 223 header->ether_type = ntohs( header->ether_type ); 224#endif /* sun i386 */ 225 226 if ( header->ether_type <= ETHERMTU ) { /* IEEE802 */ 227 /* 228 * We need to remove the interface pointer from the beginning of this 229 * packet. We can't always use IF_ADJ(), since it can (and will, 230 * very often) MFREE() the first mbuf in our chain. If IF_ADJ() 231 * would free the first mbuf, we just advance our pointer to the 232 * next mbuf. Since our calling routine passes m by value, we're 233 * not actually losing m. Later, we don't need to put the interface 234 * pointer back on, since the caller still has it in its copy of m. 235 */ 236 if ( m->m_len == sizeof( struct ifnet * )) { 237 n = m; 238 m = m->m_next; 239 } else { 240 IF_ADJ( m ); 241 } 242 243 /* 244 * We can't call m_pullup(), since we need to preserve 245 * the value of m. 246 */ 247 if ( m->m_len < sizeof( struct llc )) { 248printf( "atef_input size llc\n" ); 249 ( n ) ? m_freem( n ) : m_freem( m ); 250 return( 0 ); 251 } 252 bcopy( mtod( m, caddr_t ), &llc, sizeof( struct llc )); 253 if ( llc.llc_dsap != LLC_SNAP_LSAP || llc.llc_ssap != LLC_SNAP_LSAP || 254 llc.llc_control != LLC_UI ) { 255 ( n ) ? m_freem( n ) : m_freem( m ); 256 return( 0 ); 257 } 258 259 /* 260 * See IF_ADJ() above. Here we prepend ifp to the mbuf chain. If we 261 * didn't remove it earlier, we don't replace it here. 262 */ 263 if ( n ) { 264 m_adj( m, sizeof( struct llc )); 265 } else { 266 m_adj( m, sizeof( struct llc ) - sizeof( struct ifnet *)); 267 if ( m->m_len < sizeof( struct ifnet * )) { 268printf( "atef_input too small!\n" ); 269 m_freem( m ); 270 return( 0 ); 271 } 272 *mtod( m, struct ifnet ** ) = ifp; 273 } 274 275 if ( ntohs( llc.llc_ether_type ) == ETHERTYPE_AT && 276 bcmp( llc.llc_org_code, at_org_code, 277 sizeof( at_org_code )) == 0 ) { 278 return( &atintrq2 ); 279 } 280 281 /* do we really want to pass m, here? what happened to n? XXX */ 282 if ( ntohs( llc.llc_ether_type ) == ETHERTYPE_AARP && 283 bcmp( llc.llc_org_code, aarp_org_code, 284 sizeof( aarp_org_code )) == 0 ) { 285 aarpinput( ifp, n ? n : m ); 286 return( 0 ); 287 } 288 289 } else { /* DIX */ 290 switch ( header->ether_type ) { 291 case ETHERTYPE_AT : 292 return( &atintrq1 ); 293 294 case ETHERTYPE_AARP : 295 aarpinput( ifp, m ); 296 return( 0 ); 297 } 298 } 299 300 ( n ) ? m_freem( n ) : m_freem( m ); 301 return( 0 ); 302} 303 304/* 305 * If the destination is on a 802.3 wire, do phase 2 encapsulation, 306 * adding the 802.2 and SNAP headers. Always fill in the edst with the 307 * ethernet address of the destination. 308 */ 309atef_output( dst, m, ifp, edst ) 310 struct sockaddr_at *dst; 311 struct mbuf *m; 312 struct ifnet *ifp; 313 struct ether_addr *edst; 314{ 315 struct at_ifaddr *aa; 316 struct mbuf *m0; 317 struct llc llc; 318 int s; 319 320 s = splimp(); 321 if ( !aarpresolve( ifp, m, dst, edst )) { 322 (void) splx( s ); 323 return( 1 ); 324 } 325 (void) splx( s ); 326 327 /* 328 * ifaddr is the first thing in at_ifaddr 329 */ 330 if (( aa = (struct at_ifaddr *)at_ifawithnet( dst, ifp->if_addrlist )) 331 == 0 ) { 332 m_freem( m ); 333 return( 1 ); 334 } 335 336 /* 337 * In the phase 2 case, we need to prepend an mbuf for the llc header. 338 * Since we must preserve the value of m, which is passed to us by 339 * value, we m_copy() the first mbuf, and use it for our llc header. 340 * 341 * We could worry about leaving space for the ether header, but 342 * since we'll have to go through all sorts of hoops, including a 343 * possibly large copy, there's really no sense. 344 */ 345 if ( aa->aa_flags & AFA_PHASE2 ) { 346 if ( M_HASCL( m ) || m->m_off - MMINOFF < sizeof( struct llc )) { 347 if (( m0 = m_copy( m, 0, m->m_len )) == 0 ) { 348 m_freem( m ); 349 return( 1 ); 350 } 351 if ( M_HASCL( m )) { /* m is a cluster */ 352 int s = splimp(); 353 354 mclput( m ); 355 splx( s ); 356 } 357 358 m0->m_next = m->m_next; 359 m->m_next = m0; 360 m->m_off = MMAXOFF - sizeof( struct llc ); 361 m->m_len = sizeof( struct llc ); 362 } else { 363 m->m_off -= sizeof( struct llc ); 364 m->m_len += sizeof( struct llc ); 365 } 366 367 llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; 368 llc.llc_control = LLC_UI; 369 bcopy( at_org_code, llc.llc_org_code, sizeof( at_org_code )); 370 llc.llc_ether_type = htons( ETHERTYPE_AT ); 371 bcopy( &llc, mtod( m, caddr_t ), sizeof( struct llc )); 372 ether_atalk[ 0 ].ef_ethertype = EF_8023_TYPE; 373 return( 0 ); 374 } else { 375 ether_atalk[ 0 ].ef_ethertype = ETHERTYPE_AT; 376 return( 0 ); 377 } 378} 379