1139827Simp/*- 2194619Srwatson * Copyright (c) 2004-2009 Robert N. M. Watson 3133422Srwatson * All rights reserved. 4133422Srwatson * 5133422Srwatson * Redistribution and use in source and binary forms, with or without 6133422Srwatson * modification, are permitted provided that the following conditions 7133422Srwatson * are met: 8133422Srwatson * 1. Redistributions of source code must retain the above copyright 9133422Srwatson * notice, this list of conditions and the following disclaimer. 10133422Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11133422Srwatson * notice, this list of conditions and the following disclaimer in the 12133422Srwatson * documentation and/or other materials provided with the distribution. 13133422Srwatson * 14133422Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15133422Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16133422Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17133422Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18133422Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19133422Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20133422Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21133422Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22133422Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23133422Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24133422Srwatson * SUCH DAMAGE. 25165891Srwatson * 26165974Srwatson * Copyright (c) 1990, 1994 Regents of The University of Michigan. 2756555Sbrian * 28133422Srwatson * Permission to use, copy, modify, and distribute this software and 29133422Srwatson * its documentation for any purpose and without fee is hereby granted, 30133422Srwatson * provided that the above copyright notice appears in all copies and 31133422Srwatson * that both that copyright notice and this permission notice appear 32133422Srwatson * in supporting documentation, and that the name of The University 33133422Srwatson * of Michigan not be used in advertising or publicity pertaining to 34133422Srwatson * distribution of the software without specific, written prior 35133422Srwatson * permission. This software is supplied as is without expressed or 36133422Srwatson * implied warranties of any kind. 37133422Srwatson * 38133422Srwatson * This product includes software developed by the University of 39133422Srwatson * California, Berkeley and its contributors. 40133422Srwatson * 41133422Srwatson * Research Systems Unix Group 42133422Srwatson * The University of Michigan 43133422Srwatson * c/o Wesley Craig 44133422Srwatson * 535 W. William Street 45133422Srwatson * Ann Arbor, Michigan 46133422Srwatson * +1-313-764-2278 47133422Srwatson * netatalk@umich.edu 48133422Srwatson * 4956555Sbrian * $FreeBSD$ 5015885Sjulian */ 5115885Sjulian 5215885Sjulian#include <sys/param.h> 5315885Sjulian#include <sys/kernel.h> 5495759Stanimura#include <sys/lock.h> 5515885Sjulian#include <sys/mbuf.h> 5695759Stanimura#include <sys/signalvar.h> 5715885Sjulian#include <sys/socket.h> 5815885Sjulian#include <sys/socketvar.h> 5995759Stanimura#include <sys/sx.h> 6095759Stanimura#include <sys/systm.h> 6115885Sjulian#include <net/if.h> 6215885Sjulian#include <net/route.h> 6315885Sjulian 6418207Sbde#include <netatalk/at.h> 6518207Sbde#include <netatalk/at_var.h> 6618207Sbde#include <netatalk/ddp.h> 6718207Sbde#include <netatalk/ddp_var.h> 68132043Srwatson#include <netatalk/ddp_pcb.h> 6915885Sjulian#include <netatalk/at_extern.h> 7015885Sjulian 71163606Srwatson#include <security/mac/mac_framework.h> 72163606Srwatson 7329185Sbdestatic volatile int ddp_forward = 1; 7429185Sbdestatic volatile int ddp_firewall = 0; 7529184Sbdestatic struct ddpstat ddpstat; 76132043Srwatson 7729185Sbdestatic struct route forwro; 7829184Sbde 7929185Sbdestatic void ddp_input(struct mbuf *, struct ifnet *, struct elaphdr *, int); 8015885Sjulian 8115885Sjulian/* 8215885Sjulian * Could probably merge these two code segments a little better... 8315885Sjulian */ 84111888Sjlemonvoid 85111888Sjlemonat2intr(struct mbuf *m) 8615885Sjulian{ 8715885Sjulian 88111888Sjlemon /* 89165974Srwatson * Phase 2 packet handling . 90111888Sjlemon */ 91111888Sjlemon ddp_input(m, m->m_pkthdr.rcvif, NULL, 2); 92111888Sjlemon} 9315885Sjulian 94111888Sjlemonvoid 95111888Sjlemonat1intr(struct mbuf *m) 96111888Sjlemon{ 97111888Sjlemon struct elaphdr *elhp, elh; 9815885Sjulian 99111888Sjlemon /* 100111888Sjlemon * Phase 1 packet handling 101111888Sjlemon */ 102165974Srwatson if (m->m_len < SZ_ELAPHDR && ((m = m_pullup(m, SZ_ELAPHDR)) == 103165974Srwatson NULL)) { 104111888Sjlemon ddpstat.ddps_tooshort++; 105111888Sjlemon return; 10615885Sjulian } 10715885Sjulian 10830822Sjulian /* 109111888Sjlemon * This seems a little dubious, but I don't know phase 1 so leave it. 11030822Sjulian */ 111111888Sjlemon elhp = mtod(m, struct elaphdr *); 112111888Sjlemon m_adj(m, SZ_ELAPHDR); 11315885Sjulian 114165974Srwatson if (elhp->el_type != ELAP_DDPEXTEND) { 115111888Sjlemon bcopy((caddr_t)elhp, (caddr_t)&elh, SZ_ELAPHDR); 116111888Sjlemon ddp_input(m, m->m_pkthdr.rcvif, &elh, 1); 117165974Srwatson } else 118165974Srwatson ddp_input(m, m->m_pkthdr.rcvif, NULL, 1); 11915885Sjulian} 12015885Sjulian 12157178Speterstatic void 122165974Srwatsonddp_input(struct mbuf *m, struct ifnet *ifp, struct elaphdr *elh, int phase) 12315885Sjulian{ 124165974Srwatson struct sockaddr_at from, to; 125165974Srwatson struct ddpshdr *dsh, ddps; 126165974Srwatson struct at_ifaddr *aa; 127165974Srwatson struct ddpehdr *deh = NULL, ddpe; 128165974Srwatson struct ddpcb *ddp; 129165974Srwatson int dlen, mlen; 130165974Srwatson u_short cksum = 0; 13115885Sjulian 132165974Srwatson bzero((caddr_t)&from, sizeof(struct sockaddr_at)); 133165974Srwatson bzero((caddr_t)&to, sizeof(struct sockaddr_at)); 134165974Srwatson if (elh != NULL) { 135165974Srwatson /* 136165974Srwatson * Extract the information in the short header. Network 137165974Srwatson * information is defaulted to ATADDR_ANYNET and node 138165974Srwatson * information comes from the elh info. We must be phase 1. 139165974Srwatson */ 140165974Srwatson ddpstat.ddps_short++; 14115885Sjulian 142165974Srwatson if (m->m_len < sizeof(struct ddpshdr) && 143165974Srwatson ((m = m_pullup(m, sizeof(struct ddpshdr))) == NULL)) { 144165974Srwatson ddpstat.ddps_tooshort++; 145165974Srwatson return; 146165974Srwatson } 14715885Sjulian 148165974Srwatson dsh = mtod(m, struct ddpshdr *); 149165974Srwatson bcopy((caddr_t)dsh, (caddr_t)&ddps, sizeof(struct ddpshdr)); 150165974Srwatson ddps.dsh_bytes = ntohl(ddps.dsh_bytes); 151165974Srwatson dlen = ddps.dsh_len; 15215885Sjulian 153165974Srwatson to.sat_addr.s_net = ATADDR_ANYNET; 154165974Srwatson to.sat_addr.s_node = elh->el_dnode; 155165974Srwatson to.sat_port = ddps.dsh_dport; 156165974Srwatson from.sat_addr.s_net = ATADDR_ANYNET; 157165974Srwatson from.sat_addr.s_node = elh->el_snode; 158165974Srwatson from.sat_port = ddps.dsh_sport; 15915885Sjulian 160165974Srwatson /* 161165974Srwatson * Make sure that we point to the phase1 ifaddr info and that 162165974Srwatson * it's valid for this packet. 163165974Srwatson */ 164194619Srwatson AT_IFADDR_RLOCK(); 165194913Srwatson TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { 166165974Srwatson if ((aa->aa_ifp == ifp) 167165974Srwatson && ((aa->aa_flags & AFA_PHASE2) == 0) 168165974Srwatson && ((to.sat_addr.s_node == 169165974Srwatson AA_SAT(aa)->sat_addr.s_node) || 170165974Srwatson (to.sat_addr.s_node == ATADDR_BCAST))) 171165974Srwatson break; 172165974Srwatson } 173165974Srwatson /* 174165974Srwatson * maybe we got a broadcast not meant for us.. ditch it. 175165974Srwatson */ 176165974Srwatson if (aa == NULL) { 177194619Srwatson AT_IFADDR_RUNLOCK(); 178165974Srwatson m_freem(m); 179165974Srwatson return; 180165974Srwatson } 181165974Srwatson } else { 182165974Srwatson /* 183165974Srwatson * There was no 'elh' passed on. This could still be either 184165974Srwatson * phase1 or phase2. We have a long header, but we may be 185165974Srwatson * running on a phase 1 net. Extract out all the info 186165974Srwatson * regarding this packet's src & dst. 187165974Srwatson */ 188165974Srwatson ddpstat.ddps_long++; 18915885Sjulian 190165974Srwatson if (m->m_len < sizeof(struct ddpehdr) && 191165974Srwatson ((m = m_pullup(m, sizeof(struct ddpehdr))) == NULL)) { 192194619Srwatson AT_IFADDR_RUNLOCK(); 193165974Srwatson ddpstat.ddps_tooshort++; 194165974Srwatson return; 195165974Srwatson } 19615885Sjulian 197165974Srwatson deh = mtod(m, struct ddpehdr *); 198165974Srwatson bcopy((caddr_t)deh, (caddr_t)&ddpe, sizeof(struct ddpehdr)); 199165974Srwatson ddpe.deh_bytes = ntohl(ddpe.deh_bytes); 200165974Srwatson dlen = ddpe.deh_len; 20115885Sjulian 202165974Srwatson if ((cksum = ddpe.deh_sum) == 0) 203165974Srwatson ddpstat.ddps_nosum++; 204165974Srwatson 205165974Srwatson from.sat_addr.s_net = ddpe.deh_snet; 206165974Srwatson from.sat_addr.s_node = ddpe.deh_snode; 207165974Srwatson from.sat_port = ddpe.deh_sport; 208165974Srwatson to.sat_addr.s_net = ddpe.deh_dnet; 209165974Srwatson to.sat_addr.s_node = ddpe.deh_dnode; 210165974Srwatson to.sat_port = ddpe.deh_dport; 211165974Srwatson 212194619Srwatson AT_IFADDR_RLOCK(); 213165974Srwatson if (to.sat_addr.s_net == ATADDR_ANYNET) { 214165974Srwatson /* 215165974Srwatson * The TO address doesn't specify a net, so by 216165974Srwatson * definition it's for this net. Try find ifaddr 217165974Srwatson * info with the right phase, the right interface, 218165974Srwatson * and either to our node, a broadcast, or looped 219165974Srwatson * back (though that SHOULD be covered in the other 220165974Srwatson * cases). 221165974Srwatson * 222165974Srwatson * XXX If we have multiple interfaces, then the first 223165974Srwatson * with this node number will match (which may NOT be 224165974Srwatson * what we want, but it's probably safe in 99.999% of 225165974Srwatson * cases. 226165974Srwatson */ 227194913Srwatson TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { 228165974Srwatson if (phase == 1 && (aa->aa_flags & 229165974Srwatson AFA_PHASE2)) 230165974Srwatson continue; 231165974Srwatson if (phase == 2 && (aa->aa_flags & 232165974Srwatson AFA_PHASE2) == 0) 233165974Srwatson continue; 234165974Srwatson if ((aa->aa_ifp == ifp) && 235165974Srwatson ((to.sat_addr.s_node == 236165974Srwatson AA_SAT(aa)->sat_addr.s_node) || 237165974Srwatson (to.sat_addr.s_node == ATADDR_BCAST) || 238165974Srwatson (ifp->if_flags & IFF_LOOPBACK))) 239165974Srwatson break; 240165974Srwatson } 241165974Srwatson } else { 242165974Srwatson /* 243165974Srwatson * A destination network was given. We just try to 244165974Srwatson * find which ifaddr info matches it. 245165974Srwatson */ 246194913Srwatson TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { 247165974Srwatson /* 248165974Srwatson * This is a kludge. Accept packets that are 249165974Srwatson * for any router on a local netrange. 250165974Srwatson */ 251165974Srwatson if (to.sat_addr.s_net == aa->aa_firstnet && 252165974Srwatson to.sat_addr.s_node == 0) 253165974Srwatson break; 254165974Srwatson /* 255165974Srwatson * Don't use ifaddr info for which we are 256165974Srwatson * totally outside the netrange, and it's not 257165974Srwatson * a startup packet. Startup packets are 258165974Srwatson * always implicitly allowed on to the next 259165974Srwatson * test. 260165974Srwatson */ 261165974Srwatson if (((ntohs(to.sat_addr.s_net) < 262165974Srwatson ntohs(aa->aa_firstnet)) || 263165974Srwatson (ntohs(to.sat_addr.s_net) > 264165974Srwatson ntohs(aa->aa_lastnet))) && 265165974Srwatson ((ntohs(to.sat_addr.s_net) < 0xff00) || 266165974Srwatson (ntohs(to.sat_addr.s_net) > 0xfffe))) 267165974Srwatson continue; 268165974Srwatson 269165974Srwatson /* 270165974Srwatson * Don't record a match either if we just 271165974Srwatson * don't have a match in the node address. 272165974Srwatson * This can have if the interface is in 273165974Srwatson * promiscuous mode for example. 274165974Srwatson */ 275165974Srwatson if ((to.sat_addr.s_node != 276165974Srwatson AA_SAT(aa)->sat_addr.s_node) && 277165974Srwatson (to.sat_addr.s_node != ATADDR_BCAST)) 278165974Srwatson continue; 279165974Srwatson break; 280165974Srwatson } 281165974Srwatson } 28215885Sjulian } 283194619Srwatson if (aa != NULL) 284194619Srwatson ifa_ref(&aa->aa_ifa); 285194619Srwatson AT_IFADDR_RUNLOCK(); 28615885Sjulian 287165974Srwatson /* 288165974Srwatson * Adjust the length, removing any padding that may have been added 289165974Srwatson * at a link layer. We do this before we attempt to forward a 290165974Srwatson * packet, possibly on a different media. 291165974Srwatson */ 292165974Srwatson mlen = m->m_pkthdr.len; 293165974Srwatson if (mlen < dlen) { 294165974Srwatson ddpstat.ddps_toosmall++; 295194619Srwatson goto out; 296165974Srwatson } 297165974Srwatson if (mlen > dlen) 298165974Srwatson m_adj(m, dlen - mlen); 29915885Sjulian 300165974Srwatson /* 301165974Srwatson * If it isn't for a net on any of our interfaces, or it IS for a net 302165974Srwatson * on a different interface than it came in on, (and it is not looped 303165974Srwatson * back) then consider if we should forward it. As we are not really 304165974Srwatson * a router this is a bit cheeky, but it may be useful some day. 305165974Srwatson */ 306165974Srwatson if ((aa == NULL) || ((to.sat_addr.s_node == ATADDR_BCAST) && 307165974Srwatson (aa->aa_ifp != ifp) && ((ifp->if_flags & IFF_LOOPBACK) == 0))) { 308165974Srwatson /* 309165974Srwatson * If we've explicitly disabled it, don't route anything. 310165974Srwatson */ 311194619Srwatson if (ddp_forward == 0) 312194619Srwatson goto out; 313165974Srwatson 314165974Srwatson /* 315165974Srwatson * If the cached forwarding route is still valid, use it. 316165974Srwatson * 317165974Srwatson * XXXRW: Access to the cached route may not be properly 318165974Srwatson * synchronized for parallel input handling. 319165974Srwatson */ 320165974Srwatson if (forwro.ro_rt && 321165974Srwatson (satosat(&forwro.ro_dst)->sat_addr.s_net != 322165974Srwatson to.sat_addr.s_net || 323165974Srwatson satosat(&forwro.ro_dst)->sat_addr.s_node != 324165974Srwatson to.sat_addr.s_node)) { 325165974Srwatson RTFREE(forwro.ro_rt); 326165974Srwatson forwro.ro_rt = NULL; 32715885Sjulian } 328165974Srwatson 32930822Sjulian /* 330165974Srwatson * If we don't have a cached one (any more) or it's useless, 331165974Srwatson * then get a new route. 332165974Srwatson * 333165974Srwatson * XXX this could cause a 'route leak'. Check this! 33430822Sjulian */ 335165974Srwatson if (forwro.ro_rt == NULL || forwro.ro_rt->rt_ifp == NULL) { 336165974Srwatson forwro.ro_dst.sa_len = sizeof(struct sockaddr_at); 337165974Srwatson forwro.ro_dst.sa_family = AF_APPLETALK; 338165974Srwatson satosat(&forwro.ro_dst)->sat_addr.s_net = 339165974Srwatson to.sat_addr.s_net; 340165974Srwatson satosat(&forwro.ro_dst)->sat_addr.s_node = 341165974Srwatson to.sat_addr.s_node; 342165974Srwatson rtalloc(&forwro); 34315885Sjulian } 344165974Srwatson 345165974Srwatson /* 346165974Srwatson * If it's not going to get there on this hop, and it's 347165974Srwatson * already done too many hops, then throw it away. 34830822Sjulian */ 349165974Srwatson if ((to.sat_addr.s_net != 350165974Srwatson satosat(&forwro.ro_dst)->sat_addr.s_net) && 351194619Srwatson (ddpe.deh_hops == DDP_MAXHOPS)) 352194619Srwatson goto out; 35330822Sjulian 35430822Sjulian /* 355165974Srwatson * A ddp router might use the same interface to forward the 356165974Srwatson * packet, which this would not effect. Don't allow packets 357165974Srwatson * to cross from one interface to another however. 35830822Sjulian */ 359165974Srwatson if (ddp_firewall && ((forwro.ro_rt == NULL) || 360194619Srwatson (forwro.ro_rt->rt_ifp != ifp))) 361194619Srwatson goto out; 36215885Sjulian 363165974Srwatson /* 364165974Srwatson * Adjust the header. If it was a short header then it would 365165974Srwatson * have not gotten here, so we can assume there is room to 366165974Srwatson * drop the header in. 367165974Srwatson * 368165974Srwatson * XXX what about promiscuous mode, etc... 369165974Srwatson */ 370165974Srwatson ddpe.deh_hops++; 371165974Srwatson ddpe.deh_bytes = htonl(ddpe.deh_bytes); 372165974Srwatson /* XXX deh? */ 373165974Srwatson bcopy((caddr_t)&ddpe, (caddr_t)deh, sizeof(u_short)); 374165974Srwatson if (ddp_route(m, &forwro)) 375165974Srwatson ddpstat.ddps_cantforward++; 376165974Srwatson else 377165974Srwatson ddpstat.ddps_forward++; 378194619Srwatson if (aa != NULL) 379194619Srwatson ifa_free(&aa->aa_ifa); 380165974Srwatson return; 38115885Sjulian } 38230822Sjulian 38330822Sjulian /* 384165974Srwatson * It was for us, and we have an ifaddr to use with it. 38530822Sjulian */ 386165974Srwatson from.sat_len = sizeof(struct sockaddr_at); 387165974Srwatson from.sat_family = AF_APPLETALK; 38815885Sjulian 38930822Sjulian /* 390165974Srwatson * We are no longer interested in the link layer so cut it off. 39130822Sjulian */ 392165974Srwatson if (elh == NULL) { 393165974Srwatson if (ddp_cksum && cksum && cksum != 394165974Srwatson at_cksum(m, sizeof(int))) { 395165974Srwatson ddpstat.ddps_badsum++; 396194619Srwatson goto out; 397165974Srwatson } 398165974Srwatson m_adj(m, sizeof(struct ddpehdr)); 399165974Srwatson } else 400165974Srwatson m_adj(m, sizeof(struct ddpshdr)); 40115885Sjulian 402165974Srwatson /* 403165974Srwatson * Search for ddp protocol control blocks that match these addresses. 40430822Sjulian */ 405165974Srwatson DDP_LIST_SLOCK(); 406165974Srwatson if ((ddp = ddp_search(&from, &to, aa)) == NULL) 407194619Srwatson goto out_unlock; 40815885Sjulian 409165974Srwatson#ifdef MAC 410193332Srwatson if (mac_socket_check_deliver(ddp->ddp_socket, m) != 0) 411194619Srwatson goto out_unlock; 412101937Srwatson#endif 413101937Srwatson 41430822Sjulian /* 415165974Srwatson * If we found one, deliver the packet to the socket 41630822Sjulian */ 417165974Srwatson SOCKBUF_LOCK(&ddp->ddp_socket->so_rcv); 418165974Srwatson if (sbappendaddr_locked(&ddp->ddp_socket->so_rcv, 419165974Srwatson (struct sockaddr *)&from, m, NULL) == 0) { 420165974Srwatson SOCKBUF_UNLOCK(&ddp->ddp_socket->so_rcv); 421165974Srwatson /* 422165974Srwatson * If the socket is full (or similar error) dump the packet. 423165974Srwatson */ 424165974Srwatson ddpstat.ddps_nosockspace++; 425194619Srwatson goto out_unlock; 42615885Sjulian } 42715885Sjulian 428165974Srwatson /* 429165974Srwatson * And wake up whatever might be waiting for it 430165974Srwatson */ 431165974Srwatson sorwakeup_locked(ddp->ddp_socket); 432165974Srwatson m = NULL; 433194619Srwatsonout_unlock: 434194619Srwatson DDP_LIST_SUNLOCK(); 435165974Srwatsonout: 436194619Srwatson if (aa != NULL) 437194619Srwatson ifa_free(&aa->aa_ifa); 438165974Srwatson if (m != NULL) 439165974Srwatson m_freem(m); 44015885Sjulian} 441