static void ddp_input(struct mbuf *m, struct ifnet *ifp, struct elaphdr *elh, int phase) { struct sockaddr_at from, to; struct ddpshdr *dsh, ddps; struct at_ifaddr *aa; struct ddpehdr *deh = NULL, ddpe; struct ddpcb *ddp; int dlen, mlen; u_short cksum = 0; bzero( (caddr_t)&from, sizeof( struct sockaddr_at )); bzero( (caddr_t)&to, sizeof( struct sockaddr_at )); if ( elh ) { /* * Extract the information in the short header. * netowrk information is defaulted to ATADDR_ANYNET * and node information comes from the elh info. * We must be phase 1. */ ddpstat.ddps_short++; if ( m->m_len < sizeof( struct ddpshdr ) && (( m = m_pullup( m, sizeof( struct ddpshdr ))) == 0 )) { ddpstat.ddps_tooshort++; return; } dsh = mtod( m, struct ddpshdr *); bcopy( (caddr_t)dsh, (caddr_t)&ddps, sizeof( struct ddpshdr )); ddps.dsh_bytes = ntohl( ddps.dsh_bytes ); dlen = ddps.dsh_len; to.sat_addr.s_net = ATADDR_ANYNET; to.sat_addr.s_node = elh->el_dnode; to.sat_port = ddps.dsh_dport; from.sat_addr.s_net = ATADDR_ANYNET; from.sat_addr.s_node = elh->el_snode; from.sat_port = ddps.dsh_sport; /* * Make sure that we point to the phase1 ifaddr info * and that it's valid for this packet. */ for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { if ( (aa->aa_ifp == ifp) && ( (aa->aa_flags & AFA_PHASE2) == 0) && ( (to.sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node) || (to.sat_addr.s_node == ATADDR_BCAST))) { break; } } /* * maybe we got a broadcast not meant for us.. ditch it. */ if ( aa == NULL ) { m_freem( m ); return; } } else {
/* * For the moment, this just find the pcb with the correct local address. * In the future, this will actually do some real searching, so we can use * the sender's address to do de-multiplexing on a single port to many * sockets (pcbs). */ struct ddpcb * ddp_search( struct sockaddr_at *from, struct sockaddr_at *to, struct at_ifaddr *aa) { struct ddpcb *ddp; /* * Check for bad ports. */ if ( to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST ) { return( NULL ); } /* * Make sure the local address matches the sent address. What about * the interface? */ for ( ddp = ddp_ports[ to->sat_port - 1 ]; ddp; ddp = ddp->ddp_pnext ) { /* XXX should we handle 0.YY? */ /* XXXX.YY to socket on destination interface */ if ( to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net && to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node ) { break; } /* 0.255 to socket on receiving interface */ if ( to->sat_addr.s_node == ATADDR_BCAST && ( to->sat_addr.s_net == 0 || to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net ) && ddp->ddp_lsat.sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) { break; } /* XXXX.0 to socket on destination interface */ if ( to->sat_addr.s_net == aa->aa_firstnet && to->sat_addr.s_node == 0 && ntohs( ddp->ddp_lsat.sat_addr.s_net ) >= ntohs( aa->aa_firstnet ) && ntohs( ddp->ddp_lsat.sat_addr.s_net ) <= ntohs( aa->aa_lastnet )) { break; } } return( ddp ); }
static void aarpwhohas( struct arpcom *ac, struct sockaddr_at *sat ) { struct mbuf *m; struct ether_header *eh; struct ether_aarp *ea; struct at_ifaddr *aa; struct llc *llc; struct sockaddr sa; if (( m = m_gethdr( M_DONTWAIT, MT_DATA )) == NULL ) { return; } #ifdef MAC mac_create_mbuf_linklayer(&ac->ac_if, m); #endif m->m_len = sizeof( *ea ); m->m_pkthdr.len = sizeof( *ea ); MH_ALIGN( m, sizeof( *ea )); ea = mtod( m, struct ether_aarp *); bzero((caddr_t)ea, sizeof( *ea )); ea->aarp_hrd = htons( AARPHRD_ETHER ); ea->aarp_pro = htons( ETHERTYPE_AT ); ea->aarp_hln = sizeof( ea->aarp_sha ); ea->aarp_pln = sizeof( ea->aarp_spu ); ea->aarp_op = htons( AARPOP_REQUEST ); bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->aarp_sha, sizeof( ea->aarp_sha )); /* * We need to check whether the output ethernet type should * be phase 1 or 2. We have the interface that we'll be sending * the aarp out. We need to find an AppleTalk network on that * interface with the same address as we're looking for. If the * net is phase 2, generate an 802.2 and SNAP header. */ if ((aa = at_ifawithnet( sat )) == NULL) { m_freem( m ); return; } eh = (struct ether_header *)sa.sa_data; if ( aa->aa_flags & AFA_PHASE2 ) { bcopy((caddr_t)atmulticastaddr, (caddr_t)eh->ether_dhost, sizeof( eh->ether_dhost )); eh->ether_type = htons(sizeof(struct llc) + sizeof(struct ether_aarp)); M_PREPEND( m, sizeof( struct llc ), M_TRYWAIT ); llc = mtod( m, struct llc *); llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; llc->llc_control = LLC_UI; bcopy( aarp_org_code, llc->llc_org_code, sizeof( aarp_org_code )); llc->llc_ether_type = htons( ETHERTYPE_AARP ); bcopy( &AA_SAT( aa )->sat_addr.s_net, ea->aarp_spnet, sizeof( ea->aarp_spnet )); bcopy( &sat->sat_addr.s_net, ea->aarp_tpnet, sizeof( ea->aarp_tpnet )); ea->aarp_spnode = AA_SAT( aa )->sat_addr.s_node; ea->aarp_tpnode = sat->sat_addr.s_node; } else {
static int at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, struct proc *p) { struct sockaddr_at lsat, *sat; struct at_ifaddr *aa; struct ddpcb *ddpp; if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT ) { /* shouldn't be bound */ return( EINVAL ); } if (addr != 0) { /* validate passed address */ sat = (struct sockaddr_at *)addr; if (sat->sat_family != AF_APPLETALK) { return(EAFNOSUPPORT); } if ( sat->sat_addr.s_node != ATADDR_ANYNODE || sat->sat_addr.s_net != ATADDR_ANYNET ) { for ( aa = at_ifaddr; aa; aa = aa->aa_next ) { if (( sat->sat_addr.s_net == AA_SAT( aa )->sat_addr.s_net ) && ( sat->sat_addr.s_node == AA_SAT( aa )->sat_addr.s_node )) { break; } } if ( !aa ) { return( EADDRNOTAVAIL ); } } if ( sat->sat_port != ATADDR_ANYPORT ) { if ( sat->sat_port < ATPORT_FIRST || sat->sat_port >= ATPORT_LAST ) { return( EINVAL ); } if ( sat->sat_port < ATPORT_RESERVED && suser(p) ) { return( EACCES ); } } } else { bzero( (caddr_t)&lsat, sizeof( struct sockaddr_at )); lsat.sat_len = sizeof(struct sockaddr_at); lsat.sat_addr.s_node = ATADDR_ANYNODE; lsat.sat_addr.s_net = ATADDR_ANYNET; lsat.sat_family = AF_APPLETALK; sat = &lsat; } if ( sat->sat_addr.s_node == ATADDR_ANYNODE && sat->sat_addr.s_net == ATADDR_ANYNET ) { if ( at_ifaddr == NULL ) { return( EADDRNOTAVAIL ); } sat->sat_addr = AA_SAT( at_ifaddr )->sat_addr; } ddp->ddp_lsat = *sat; /* * Choose port. */ if ( sat->sat_port == ATADDR_ANYPORT ) { for ( sat->sat_port = ATPORT_RESERVED; sat->sat_port < ATPORT_LAST; sat->sat_port++ ) { if ( ddp_ports[ sat->sat_port - 1 ] == 0 ) { break; } } if ( sat->sat_port == ATPORT_LAST ) { return( EADDRNOTAVAIL ); } ddp->ddp_lsat.sat_port = sat->sat_port; ddp_ports[ sat->sat_port - 1 ] = ddp; } else { for ( ddpp = ddp_ports[ sat->sat_port - 1 ]; ddpp; ddpp = ddpp->ddp_pnext ) { if ( ddpp->ddp_lsat.sat_addr.s_net == sat->sat_addr.s_net && ddpp->ddp_lsat.sat_addr.s_node == sat->sat_addr.s_node ) { break; } } if ( ddpp != NULL ) { return( EADDRINUSE ); } ddp->ddp_pnext = ddp_ports[ sat->sat_port - 1 ]; ddp_ports[ sat->sat_port - 1 ] = ddp; if ( ddp->ddp_pnext ) { ddp->ddp_pnext->ddp_pprev = ddp; } } return( 0 ); }
/* * given an at_ifaddr,a sockaddr_at and an ifp, * bang them all together at high speed and see what happens */ static int at_ifinit(struct ifnet *ifp, struct at_ifaddr *aa, struct sockaddr_at *sat) { struct netrange nr, onr; struct sockaddr_at oldaddr; int error = 0, i, j; int netinc, nodeinc, nnets; u_short net; crit_enter(); /* * save the old addresses in the at_ifaddr just in case we need them. */ oldaddr = aa->aa_addr; onr.nr_firstnet = aa->aa_firstnet; onr.nr_lastnet = aa->aa_lastnet; /* * take the address supplied as an argument, and add it to the * at_ifnet (also given). Remember ing to update * those parts of the at_ifaddr that need special processing */ bzero( AA_SAT( aa ), sizeof( struct sockaddr_at )); bcopy( sat->sat_zero, &nr, sizeof( struct netrange )); bcopy( sat->sat_zero, AA_SAT( aa )->sat_zero, sizeof( struct netrange )); nnets = ntohs( nr.nr_lastnet ) - ntohs( nr.nr_firstnet ) + 1; aa->aa_firstnet = nr.nr_firstnet; aa->aa_lastnet = nr.nr_lastnet; /* XXX ALC */ #if 0 kprintf("at_ifinit: %s: %u.%u range %u-%u phase %d\n", ifp->if_name, ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node, ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), (aa->aa_flags & AFA_PHASE2) ? 2 : 1); #endif /* * We could eliminate the need for a second phase 1 probe (post * autoconf) if we check whether we're resetting the node. Note * that phase 1 probes use only nodes, not net.node pairs. Under * phase 2, both the net and node must be the same. */ if ( ifp->if_flags & IFF_LOOPBACK ) { AA_SAT( aa )->sat_len = sat->sat_len; AA_SAT( aa )->sat_family = AF_APPLETALK; AA_SAT( aa )->sat_addr.s_net = sat->sat_addr.s_net; AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node; #if 0 } else if ( fp->if_flags & IFF_POINTOPOINT) { /* unimplemented */ /* * we'd have to copy the dstaddr field over from the sat * but it's not clear that it would contain the right info.. */ #endif } else { /* * We are a normal (probably ethernet) interface. * apply the new address to the interface structures etc. * We will probe this address on the net first, before * applying it to ensure that it is free.. If it is not, then * we will try a number of other randomly generated addresses * in this net and then increment the net. etc.etc. until * we find an unused address. */ aa->aa_flags |= AFA_PROBING; /* if not loopback we Must probe? */ AA_SAT( aa )->sat_len = sizeof(struct sockaddr_at); AA_SAT( aa )->sat_family = AF_APPLETALK; if ( aa->aa_flags & AFA_PHASE2 ) { if ( sat->sat_addr.s_net == ATADDR_ANYNET ) { /* * If we are phase 2, and the net was not specified * then we select a random net within the supplied netrange. * XXX use /dev/random? */ if ( nnets != 1 ) { net = ntohs( nr.nr_firstnet ) + time_second % ( nnets - 1 ); } else { net = ntohs( nr.nr_firstnet ); } } else { /* * if a net was supplied, then check that it is within * the netrange. If it is not then replace the old values * and return an error */ if ( ntohs( sat->sat_addr.s_net ) < ntohs( nr.nr_firstnet ) || ntohs( sat->sat_addr.s_net ) > ntohs( nr.nr_lastnet )) { aa->aa_addr = oldaddr; aa->aa_firstnet = onr.nr_firstnet; aa->aa_lastnet = onr.nr_lastnet; crit_exit(); return( EINVAL ); } /* * otherwise just use the new net number.. */ net = ntohs( sat->sat_addr.s_net ); } } else { /* * we must be phase one, so just use whatever we were given. * I guess it really isn't going to be used... RIGHT? */ net = ntohs( sat->sat_addr.s_net ); } /* * set the node part of the address into the ifaddr. * If it's not specified, be random about it... * XXX use /dev/random? */ if ( sat->sat_addr.s_node == ATADDR_ANYNODE ) { AA_SAT( aa )->sat_addr.s_node = time_second; } else { AA_SAT( aa )->sat_addr.s_node = sat->sat_addr.s_node; } /* * Copy the phase. */ AA_SAT( aa )->sat_range.r_netrange.nr_phase = ((aa->aa_flags & AFA_PHASE2) ? 2:1); /* * step through the nets in the range * starting at the (possibly random) start point. */ for ( i = nnets, netinc = 1; i > 0; net = ntohs( nr.nr_firstnet ) + (( net - ntohs( nr.nr_firstnet ) + netinc ) % nnets ), i-- ) { AA_SAT( aa )->sat_addr.s_net = htons( net ); /* * using a rather strange stepping method, * stagger through the possible node addresses * Once again, starting at the (possibly random) * initial node address. */ for ( j = 0, nodeinc = time_second | 1; j < 256; j++, AA_SAT( aa )->sat_addr.s_node += nodeinc ) { if ( AA_SAT( aa )->sat_addr.s_node > 253 || AA_SAT( aa )->sat_addr.s_node < 1 ) { continue; } aa->aa_probcnt = 10; /* * start off the probes as an asynchronous activity. * though why wait 200mSec? */ callout_reset(&aa->aa_ch, hz / 5, aarpprobe, ifp); if ( tsleep( aa, PCATCH, "at_ifinit", 0 )) { /* * theoretically we shouldn't time out here * so if we returned with an error.. */ kprintf( "at_ifinit: why did this happen?!\n" ); aa->aa_addr = oldaddr; aa->aa_firstnet = onr.nr_firstnet; aa->aa_lastnet = onr.nr_lastnet; crit_exit(); return( EINTR ); } /* * The async activity should have woken us up. * We need to see if it was successful in finding * a free spot, or if we need to iterate to the next * address to try. */ if (( aa->aa_flags & AFA_PROBING ) == 0 ) { break; } } /* * of course we need to break out through two loops... */ if (( aa->aa_flags & AFA_PROBING ) == 0 ) { break; } /* reset node for next network */ AA_SAT( aa )->sat_addr.s_node = time_second; } /* * if we are still trying to probe, then we have finished all * the possible addresses, so we need to give up */ if ( aa->aa_flags & AFA_PROBING ) { aa->aa_addr = oldaddr; aa->aa_firstnet = onr.nr_firstnet; aa->aa_lastnet = onr.nr_lastnet; crit_exit(); return( EADDRINUSE ); } } /* * Now that we have selected an address, we need to tell the interface * about it, just in case it needs to adjust something. */ ifnet_serialize_all(ifp); if (ifp->if_ioctl && (error = ifp->if_ioctl(ifp, SIOCSIFADDR, (caddr_t)aa, NULL)) ) { /* * of course this could mean that it objects violently * so if it does, we back out again.. */ aa->aa_addr = oldaddr; aa->aa_firstnet = onr.nr_firstnet; aa->aa_lastnet = onr.nr_lastnet; ifnet_deserialize_all(ifp); crit_exit(); return( error ); } ifnet_deserialize_all(ifp); /* * set up the netmask part of the at_ifaddr * and point the appropriate pointer in the ifaddr to it. * probably pointless, but what the heck.. XXX */ bzero(&aa->aa_netmask, sizeof(aa->aa_netmask)); aa->aa_netmask.sat_len = sizeof(struct sockaddr_at); aa->aa_netmask.sat_family = AF_APPLETALK; aa->aa_netmask.sat_addr.s_net = 0xffff; aa->aa_netmask.sat_addr.s_node = 0; aa->aa_ifa.ifa_netmask =(struct sockaddr *) &(aa->aa_netmask); /* XXX */ /* * Initialize broadcast (or remote p2p) address */ bzero(&aa->aa_broadaddr, sizeof(aa->aa_broadaddr)); aa->aa_broadaddr.sat_len = sizeof(struct sockaddr_at); aa->aa_broadaddr.sat_family = AF_APPLETALK; aa->aa_ifa.ifa_metric = ifp->if_metric; if (ifp->if_flags & IFF_BROADCAST) { aa->aa_broadaddr.sat_addr.s_net = htons(0); aa->aa_broadaddr.sat_addr.s_node = 0xff; aa->aa_ifa.ifa_broadaddr = (struct sockaddr *) &aa->aa_broadaddr; /* add the range of routes needed */ error = aa_dorangeroute(&aa->aa_ifa, ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), RTM_ADD ); } else if (ifp->if_flags & IFF_POINTOPOINT) { struct at_addr rtaddr, rtmask; bzero(&rtaddr, sizeof(rtaddr)); bzero(&rtmask, sizeof(rtmask)); /* fill in the far end if we know it here XXX */ aa->aa_ifa.ifa_dstaddr = (struct sockaddr *) &aa->aa_dstaddr; error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask); } else if ( ifp->if_flags & IFF_LOOPBACK ) { struct at_addr rtaddr, rtmask; bzero(&rtaddr, sizeof(rtaddr)); bzero(&rtmask, sizeof(rtmask)); rtaddr.s_net = AA_SAT( aa )->sat_addr.s_net; rtaddr.s_node = AA_SAT( aa )->sat_addr.s_node; rtmask.s_net = 0xffff; rtmask.s_node = 0x0; /* XXX should not be so.. should be HOST route */ error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask); } /* * set the address of our "check if this addr is ours" routine. */ aa->aa_ifa.ifa_claim_addr = aa_claim_addr; /* * of course if we can't add these routes we back out, but it's getting * risky by now XXX */ if ( error ) { at_scrub( ifp, aa ); aa->aa_addr = oldaddr; aa->aa_firstnet = onr.nr_firstnet; aa->aa_lastnet = onr.nr_lastnet; crit_exit(); return( error ); } /* * note that the address has a route associated with it.... */ aa->aa_ifa.ifa_flags |= IFA_ROUTE; aa->aa_flags |= AFA_ROUTE; crit_exit(); return( 0 ); }