ddp_input.c revision 139827
1/*- 2 * Copyright (c) 2004 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26/*- 27 * Copyright (c) 1990,1994 Regents of The University of Michigan. 28 * 29 * Permission to use, copy, modify, and distribute this software and 30 * its documentation for any purpose and without fee is hereby granted, 31 * provided that the above copyright notice appears in all copies and 32 * that both that copyright notice and this permission notice appear 33 * in supporting documentation, and that the name of The University 34 * of Michigan not be used in advertising or publicity pertaining to 35 * distribution of the software without specific, written prior 36 * permission. This software is supplied as is without expressed or 37 * implied warranties of any kind. 38 * 39 * This product includes software developed by the University of 40 * California, Berkeley and its contributors. 41 * 42 * Research Systems Unix Group 43 * The University of Michigan 44 * c/o Wesley Craig 45 * 535 W. William Street 46 * Ann Arbor, Michigan 47 * +1-313-764-2278 48 * netatalk@umich.edu 49 * 50 * $FreeBSD: head/sys/netatalk/ddp_input.c 139827 2005-01-07 02:35:34Z imp $ 51 */ 52 53#include "opt_mac.h" 54 55#include <sys/param.h> 56#include <sys/kernel.h> 57#include <sys/lock.h> 58#include <sys/mac.h> 59#include <sys/mbuf.h> 60#include <sys/signalvar.h> 61#include <sys/socket.h> 62#include <sys/socketvar.h> 63#include <sys/sx.h> 64#include <sys/systm.h> 65#include <net/if.h> 66#include <net/route.h> 67 68#include <netatalk/at.h> 69#include <netatalk/at_var.h> 70#include <netatalk/ddp.h> 71#include <netatalk/ddp_var.h> 72#include <netatalk/ddp_pcb.h> 73#include <netatalk/at_extern.h> 74 75static volatile int ddp_forward = 1; 76static volatile int ddp_firewall = 0; 77static struct ddpstat ddpstat; 78 79static struct route forwro; 80 81static void ddp_input(struct mbuf *, struct ifnet *, struct elaphdr *, int); 82 83/* 84 * Could probably merge these two code segments a little better... 85 */ 86void 87at2intr(struct mbuf *m) 88{ 89 90 /* 91 * Phase 2 packet handling 92 */ 93 ddp_input(m, m->m_pkthdr.rcvif, NULL, 2); 94 return; 95} 96 97void 98at1intr(struct mbuf *m) 99{ 100 struct elaphdr *elhp, elh; 101 102 /* 103 * Phase 1 packet handling 104 */ 105 if (m->m_len < SZ_ELAPHDR && ((m = m_pullup(m, SZ_ELAPHDR)) == NULL)) { 106 ddpstat.ddps_tooshort++; 107 return; 108 } 109 110 /* 111 * This seems a little dubious, but I don't know phase 1 so leave it. 112 */ 113 elhp = mtod(m, struct elaphdr *); 114 m_adj(m, SZ_ELAPHDR); 115 116 if (elhp->el_type == ELAP_DDPEXTEND) { 117 ddp_input(m, m->m_pkthdr.rcvif, NULL, 1); 118 } else { 119 bcopy((caddr_t)elhp, (caddr_t)&elh, SZ_ELAPHDR); 120 ddp_input(m, m->m_pkthdr.rcvif, &elh, 1); 121 } 122 return; 123} 124 125static void 126ddp_input(m, ifp, elh, phase) 127 struct mbuf *m; 128 struct ifnet *ifp; 129 struct elaphdr *elh; 130 int phase; 131{ 132 struct sockaddr_at from, to; 133 struct ddpshdr *dsh, ddps; 134 struct at_ifaddr *aa; 135 struct ddpehdr *deh = NULL, ddpe; 136 struct ddpcb *ddp; 137 int dlen, mlen; 138 u_short cksum = 0; 139 140 bzero((caddr_t)&from, sizeof(struct sockaddr_at)); 141 bzero((caddr_t)&to, sizeof(struct sockaddr_at)); 142 if (elh != NULL) { 143 /* 144 * Extract the information in the short header. 145 * netowrk information is defaulted to ATADDR_ANYNET 146 * and node information comes from the elh info. 147 * We must be phase 1. 148 */ 149 ddpstat.ddps_short++; 150 151 if (m->m_len < sizeof(struct ddpshdr) && 152 ((m = m_pullup(m, sizeof(struct ddpshdr))) == NULL)) { 153 ddpstat.ddps_tooshort++; 154 return; 155 } 156 157 dsh = mtod(m, struct ddpshdr *); 158 bcopy((caddr_t)dsh, (caddr_t)&ddps, sizeof(struct ddpshdr)); 159 ddps.dsh_bytes = ntohl(ddps.dsh_bytes); 160 dlen = ddps.dsh_len; 161 162 to.sat_addr.s_net = ATADDR_ANYNET; 163 to.sat_addr.s_node = elh->el_dnode; 164 to.sat_port = ddps.dsh_dport; 165 from.sat_addr.s_net = ATADDR_ANYNET; 166 from.sat_addr.s_node = elh->el_snode; 167 from.sat_port = ddps.dsh_sport; 168 169 /* 170 * Make sure that we point to the phase1 ifaddr info 171 * and that it's valid for this packet. 172 */ 173 for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) { 174 if ((aa->aa_ifp == ifp) 175 && ((aa->aa_flags & AFA_PHASE2) == 0) 176 && ((to.sat_addr.s_node == AA_SAT(aa)->sat_addr.s_node) 177 || (to.sat_addr.s_node == ATADDR_BCAST))) { 178 break; 179 } 180 } 181 /* 182 * maybe we got a broadcast not meant for us.. ditch it. 183 */ 184 if (aa == NULL) { 185 m_freem(m); 186 return; 187 } 188 } else { 189 /* 190 * There was no 'elh' passed on. This could still be 191 * either phase1 or phase2. 192 * We have a long header, but we may be running on a phase 1 net. 193 * Extract out all the info regarding this packet's src & dst. 194 */ 195 ddpstat.ddps_long++; 196 197 if (m->m_len < sizeof(struct ddpehdr) && 198 ((m = m_pullup(m, sizeof(struct ddpehdr))) == NULL)) { 199 ddpstat.ddps_tooshort++; 200 return; 201 } 202 203 deh = mtod(m, struct ddpehdr *); 204 bcopy((caddr_t)deh, (caddr_t)&ddpe, sizeof(struct ddpehdr)); 205 ddpe.deh_bytes = ntohl(ddpe.deh_bytes); 206 dlen = ddpe.deh_len; 207 208 if ((cksum = ddpe.deh_sum) == 0) { 209 ddpstat.ddps_nosum++; 210 } 211 212 from.sat_addr.s_net = ddpe.deh_snet; 213 from.sat_addr.s_node = ddpe.deh_snode; 214 from.sat_port = ddpe.deh_sport; 215 to.sat_addr.s_net = ddpe.deh_dnet; 216 to.sat_addr.s_node = ddpe.deh_dnode; 217 to.sat_port = ddpe.deh_dport; 218 219 if (to.sat_addr.s_net == ATADDR_ANYNET) { 220 /* 221 * The TO address doesn't specify a net, 222 * So by definition it's for this net. 223 * Try find ifaddr info with the right phase, 224 * the right interface, and either to our node, a broadcast, 225 * or looped back (though that SHOULD be covered in the other 226 * cases). 227 * 228 * XXX If we have multiple interfaces, then the first with 229 * this node number will match (which may NOT be what we want, 230 * but it's probably safe in 99.999% of cases. 231 */ 232 for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) { 233 if (phase == 1 && (aa->aa_flags & AFA_PHASE2)) { 234 continue; 235 } 236 if (phase == 2 && (aa->aa_flags & AFA_PHASE2) == 0) { 237 continue; 238 } 239 if ((aa->aa_ifp == ifp) 240 && ((to.sat_addr.s_node == AA_SAT(aa)->sat_addr.s_node) 241 || (to.sat_addr.s_node == ATADDR_BCAST) 242 || (ifp->if_flags & IFF_LOOPBACK))) { 243 break; 244 } 245 } 246 } else { 247 /* 248 * A destination network was given. We just try to find 249 * which ifaddr info matches it. 250 */ 251 for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) { 252 /* 253 * This is a kludge. Accept packets that are 254 * for any router on a local netrange. 255 */ 256 if (to.sat_addr.s_net == aa->aa_firstnet && 257 to.sat_addr.s_node == 0) { 258 break; 259 } 260 /* 261 * Don't use ifaddr info for which we are totally outside the 262 * netrange, and it's not a startup packet. 263 * Startup packets are always implicitly allowed on to 264 * the next test. 265 */ 266 if (((ntohs(to.sat_addr.s_net) < ntohs(aa->aa_firstnet)) 267 || (ntohs(to.sat_addr.s_net) > ntohs(aa->aa_lastnet))) 268 && ((ntohs(to.sat_addr.s_net) < 0xff00) 269 || (ntohs(to.sat_addr.s_net) > 0xfffe))) { 270 continue; 271 } 272 273 /* 274 * Don't record a match either if we just don't have a match 275 * in the node address. This can have if the interface 276 * is in promiscuous mode for example. 277 */ 278 if ((to.sat_addr.s_node != AA_SAT(aa)->sat_addr.s_node) 279 && (to.sat_addr.s_node != ATADDR_BCAST)) { 280 continue; 281 } 282 break; 283 } 284 } 285 } 286 287 /* 288 * Adjust the length, removing any padding that may have been added 289 * at a link layer. We do this before we attempt to forward a packet, 290 * possibly on a different media. 291 */ 292 mlen = m->m_pkthdr.len; 293 if (mlen < dlen) { 294 ddpstat.ddps_toosmall++; 295 m_freem(m); 296 return; 297 } 298 if (mlen > dlen) { 299 m_adj(m, dlen - mlen); 300 } 301 302 /* 303 * If it aint for a net on any of our interfaces, 304 * or it IS for a net on a different interface than it came in on, 305 * (and it is not looped back) then consider if we should forward it. 306 * As we are not really a router this is a bit cheeky, but it may be 307 * useful some day. 308 */ 309 if ((aa == NULL) 310 || ((to.sat_addr.s_node == ATADDR_BCAST) 311 && (aa->aa_ifp != ifp) 312 && ((ifp->if_flags & IFF_LOOPBACK) == 0))) { 313 /* 314 * If we've explicitly disabled it, don't route anything 315 */ 316 if (ddp_forward == 0) { 317 m_freem(m); 318 return; 319 } 320 /* 321 * If the cached forwarding route is still valid, use it. 322 */ 323 if (forwro.ro_rt 324 && (satosat(&forwro.ro_dst)->sat_addr.s_net != to.sat_addr.s_net 325 || satosat(&forwro.ro_dst)->sat_addr.s_node != to.sat_addr.s_node)) { 326 RTFREE(forwro.ro_rt); 327 forwro.ro_rt = NULL; 328 } 329 330 /* 331 * If we don't have a cached one (any more) or it's useless, 332 * Then get a new route. 333 * XXX this could cause a 'route leak'. check this! 334 */ 335 if (forwro.ro_rt == NULL || forwro.ro_rt->rt_ifp == NULL) { 336 forwro.ro_dst.sa_len = sizeof(struct sockaddr_at); 337 forwro.ro_dst.sa_family = AF_APPLETALK; 338 satosat(&forwro.ro_dst)->sat_addr.s_net = to.sat_addr.s_net; 339 satosat(&forwro.ro_dst)->sat_addr.s_node = to.sat_addr.s_node; 340 rtalloc(&forwro); 341 } 342 343 /* 344 * If it's not going to get there on this hop, and it's 345 * already done too many hops, then throw it away. 346 */ 347 if ((to.sat_addr.s_net != satosat(&forwro.ro_dst)->sat_addr.s_net) 348 && (ddpe.deh_hops == DDP_MAXHOPS)) { 349 m_freem(m); 350 return; 351 } 352 353 /* 354 * A ddp router might use the same interface 355 * to forward the packet, which this would not effect. 356 * Don't allow packets to cross from one interface to another however. 357 */ 358 if (ddp_firewall 359 && ((forwro.ro_rt == NULL) 360 || (forwro.ro_rt->rt_ifp != ifp))) { 361 m_freem(m); 362 return; 363 } 364 365 /* 366 * Adjust the header. 367 * If it was a short header then it would have not gotten here, 368 * so we can assume there is room to drop the header in. 369 * XXX what about promiscuous mode, etc... 370 */ 371 ddpe.deh_hops++; 372 ddpe.deh_bytes = htonl(ddpe.deh_bytes); 373 bcopy((caddr_t)&ddpe, (caddr_t)deh, sizeof(u_short)); /* XXX deh? */ 374 if (ddp_route(m, &forwro)) { 375 ddpstat.ddps_cantforward++; 376 } else { 377 ddpstat.ddps_forward++; 378 } 379 return; 380 } 381 382 /* 383 * It was for us, and we have an ifaddr to use with it. 384 */ 385 from.sat_len = sizeof(struct sockaddr_at); 386 from.sat_family = AF_APPLETALK; 387 388 /* 389 * We are no longer interested in the link layer. 390 * so cut it off. 391 */ 392 if (elh != NULL) { 393 m_adj(m, sizeof(struct ddpshdr)); 394 } else { 395 if (ddp_cksum && cksum && cksum != at_cksum(m, sizeof(int))) { 396 ddpstat.ddps_badsum++; 397 m_freem(m); 398 return; 399 } 400 m_adj(m, sizeof(struct ddpehdr)); 401 } 402 403 /* 404 * Search for ddp protocol control blocks that match these 405 * addresses. 406 */ 407 DDP_LIST_SLOCK(); 408 if ((ddp = ddp_search(&from, &to, aa)) == NULL) { 409 goto out; 410 } 411 412#ifdef MAC 413 SOCK_LOCK(ddp->ddp_socket); 414 if (mac_check_socket_deliver(ddp->ddp_socket, m) != 0) { 415 SOCK_UNLOCK(ddp->ddp_socket); 416 goto out; 417 } 418 SOCK_UNLOCK(ddp->ddp_socket); 419#endif 420 421 /* 422 * If we found one, deliver the packet to the socket 423 */ 424 SOCKBUF_LOCK(&ddp->ddp_socket->so_rcv); 425 if (sbappendaddr_locked(&ddp->ddp_socket->so_rcv, (struct sockaddr *)&from, 426 m, NULL) == 0) { 427 SOCKBUF_UNLOCK(&ddp->ddp_socket->so_rcv); 428 /* 429 * If the socket is full (or similar error) dump the packet. 430 */ 431 ddpstat.ddps_nosockspace++; 432 goto out; 433 } 434 /* 435 * And wake up whatever might be waiting for it 436 */ 437 sorwakeup_locked(ddp->ddp_socket); 438 m = NULL; 439out: 440 DDP_LIST_SUNLOCK(); 441 if (m != NULL) 442 m_freem(m); 443} 444 445#if 0 446/* As if we haven't got enough of this sort of think floating 447around the kernel :) */ 448 449#define BPXLEN 48 450#define BPALEN 16 451#include <ctype.h> 452char hexdig[] = "0123456789ABCDEF"; 453 454static void 455bprint(char *data, int len) 456{ 457 char xout[ BPXLEN ], aout[ BPALEN ]; 458 int i = 0; 459 460 bzero(xout, BPXLEN); 461 bzero(aout, BPALEN); 462 463 for (;;) { 464 if (len < 1) { 465 if (i != 0) { 466 printf("%s\t%s\n", xout, aout); 467 } 468 printf("%s\n", "(end)"); 469 break; 470 } 471 472 xout[ (i*3) ] = hexdig[ (*data & 0xf0) >> 4 ]; 473 xout[ (i*3) + 1 ] = hexdig[ *data & 0x0f ]; 474 475 if ((u_char)*data < 0x7f && (u_char)*data > 0x20) { 476 aout[ i ] = *data; 477 } else { 478 aout[ i ] = '.'; 479 } 480 481 xout[ (i*3) + 2 ] = ' '; 482 483 i++; 484 len--; 485 data++; 486 487 if (i > BPALEN - 2) { 488 printf("%s\t%s\n", xout, aout); 489 bzero(xout, BPXLEN); 490 bzero(aout, BPALEN); 491 i = 0; 492 continue; 493 } 494 } 495} 496 497static void 498m_printm(struct mbuf *m) 499{ 500 for (; m; m = m->m_next) { 501 bprint(mtod(m, char *), m->m_len); 502 } 503} 504#endif 505