1 /* $NetBSD: ddp_input.c,v 1.19 2008/04/24 11:38:37 ad Exp $ */ 2 3 /* 4 * Copyright (c) 1990,1994 Regents of The University of Michigan. 5 * All Rights Reserved. 6 * 7 * Permission to use, copy, modify, and distribute this software and 8 * its documentation for any purpose and without fee is hereby granted, 9 * provided that the above copyright notice appears in all copies and 10 * that both that copyright notice and this permission notice appear 11 * in supporting documentation, and that the name of The University 12 * of Michigan not be used in advertising or publicity pertaining to 13 * distribution of the software without specific, written prior 14 * permission. This software is supplied as is without expressed or 15 * implied warranties of any kind. 16 * 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 20 * Research Systems Unix Group 21 * The University of Michigan 22 * c/o Wesley Craig 23 * 535 W. William Street 24 * Ann Arbor, Michigan 25 * +1-313-764-2278 26 * netatalk@umich.edu 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: ddp_input.c,v 1.19 2008/04/24 11:38:37 ad Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 #include <net/netisr.h> 36 #include <sys/mbuf.h> 37 #include <sys/socket.h> 38 #include <sys/socketvar.h> 39 #include <sys/syslog.h> 40 #include <net/if.h> 41 #include <net/route.h> 42 #include <net/if_ether.h> 43 #include <netinet/in.h> 44 45 #include <netatalk/at.h> 46 #include <netatalk/at_var.h> 47 #include <netatalk/ddp.h> 48 #include <netatalk/ddp_var.h> 49 #include <netatalk/ddp_private.h> 50 #include <netatalk/at_extern.h> 51 52 int ddp_forward = 1; 53 int ddp_firewall = 0; 54 extern int ddp_cksum; 55 void ddp_input __P((struct mbuf *, struct ifnet *, 56 struct elaphdr *, int)); 57 58 /* 59 * Could probably merge these two code segments a little better... 60 */ 61 void 62 atintr() 63 { 64 struct elaphdr *elhp, elh; 65 struct ifnet *ifp; 66 struct mbuf *m; 67 struct at_ifaddr *aa; 68 int s; 69 70 mutex_enter(softnet_lock); 71 for (;;) { 72 s = splnet(); 73 74 IF_DEQUEUE(&atintrq2, m); 75 76 splx(s); 77 78 if (m == 0) /* no more queued packets */ 79 break; 80 81 m_claimm(m, &atalk_rx_mowner); 82 ifp = m->m_pkthdr.rcvif; 83 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 84 if (aa->aa_ifp == ifp && (aa->aa_flags & AFA_PHASE2)) 85 break; 86 } 87 if (aa == NULL) { /* ifp not an appletalk interface */ 88 m_freem(m); 89 continue; 90 } 91 ddp_input(m, ifp, (struct elaphdr *) NULL, 2); 92 } 93 94 for (;;) { 95 s = splnet(); 96 97 IF_DEQUEUE(&atintrq1, m); 98 99 splx(s); 100 101 if (m == 0) /* no more queued packets */ 102 103 break; 104 105 m_claimm(m, &atalk_rx_mowner); 106 ifp = m->m_pkthdr.rcvif; 107 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 108 if (aa->aa_ifp == ifp && 109 (aa->aa_flags & AFA_PHASE2) == 0) 110 break; 111 } 112 if (aa == NULL) { /* ifp not an appletalk interface */ 113 m_freem(m); 114 continue; 115 } 116 if (m->m_len < SZ_ELAPHDR && 117 ((m = m_pullup(m, SZ_ELAPHDR)) == 0)) { 118 DDP_STATINC(DDP_STAT_TOOSHORT); 119 continue; 120 } 121 elhp = mtod(m, struct elaphdr *); 122 m_adj(m, SZ_ELAPHDR); 123 124 if (elhp->el_type == ELAP_DDPEXTEND) { 125 ddp_input(m, ifp, (struct elaphdr *) NULL, 1); 126 } else { 127 bcopy((void *) elhp, (void *) & elh, SZ_ELAPHDR); 128 ddp_input(m, ifp, &elh, 1); 129 } 130 } 131 mutex_exit(softnet_lock); 132 } 133 134 struct route forwro; 135 136 void 137 ddp_input(m, ifp, elh, phase) 138 struct mbuf *m; 139 struct ifnet *ifp; 140 struct elaphdr *elh; 141 int phase; 142 { 143 struct rtentry *rt; 144 struct sockaddr_at from, to; 145 struct ddpshdr *dsh, ddps; 146 struct at_ifaddr *aa; 147 struct ddpehdr *deh = NULL, ddpe; 148 struct ddpcb *ddp; 149 int dlen, mlen; 150 u_short cksum = 0; 151 union { 152 struct sockaddr dst; 153 struct sockaddr_at dsta; 154 } u; 155 156 bzero((void *) & from, sizeof(struct sockaddr_at)); 157 if (elh) { 158 DDP_STATINC(DDP_STAT_SHORT); 159 160 if (m->m_len < sizeof(struct ddpshdr) && 161 ((m = m_pullup(m, sizeof(struct ddpshdr))) == 0)) { 162 DDP_STATINC(DDP_STAT_TOOSHORT); 163 return; 164 } 165 dsh = mtod(m, struct ddpshdr *); 166 bcopy((void *) dsh, (void *) & ddps, sizeof(struct ddpshdr)); 167 ddps.dsh_bytes = ntohl(ddps.dsh_bytes); 168 dlen = ddps.dsh_len; 169 170 to.sat_addr.s_net = ATADDR_ANYNET; 171 to.sat_addr.s_node = elh->el_dnode; 172 to.sat_port = ddps.dsh_dport; 173 from.sat_addr.s_net = ATADDR_ANYNET; 174 from.sat_addr.s_node = elh->el_snode; 175 from.sat_port = ddps.dsh_sport; 176 177 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 178 if (aa->aa_ifp == ifp && 179 (aa->aa_flags & AFA_PHASE2) == 0 && 180 (AA_SAT(aa)->sat_addr.s_node == 181 to.sat_addr.s_node || 182 to.sat_addr.s_node == ATADDR_BCAST)) 183 break; 184 } 185 if (aa == NULL) { 186 m_freem(m); 187 return; 188 } 189 } else { 190 DDP_STATINC(DDP_STAT_LONG); 191 192 if (m->m_len < sizeof(struct ddpehdr) && 193 ((m = m_pullup(m, sizeof(struct ddpehdr))) == 0)) { 194 DDP_STATINC(DDP_STAT_TOOSHORT); 195 return; 196 } 197 deh = mtod(m, struct ddpehdr *); 198 bcopy((void *) deh, (void *) & ddpe, sizeof(struct ddpehdr)); 199 ddpe.deh_bytes = ntohl(ddpe.deh_bytes); 200 dlen = ddpe.deh_len; 201 202 if ((cksum = ddpe.deh_sum) == 0) { 203 DDP_STATINC(DDP_STAT_NOSUM); 204 } 205 from.sat_addr.s_net = ddpe.deh_snet; 206 from.sat_addr.s_node = ddpe.deh_snode; 207 from.sat_port = ddpe.deh_sport; 208 to.sat_addr.s_net = ddpe.deh_dnet; 209 to.sat_addr.s_node = ddpe.deh_dnode; 210 to.sat_port = ddpe.deh_dport; 211 212 if (to.sat_addr.s_net == ATADDR_ANYNET) { 213 for (aa = at_ifaddr.tqh_first; aa; 214 aa = aa->aa_list.tqe_next) { 215 if (phase == 1 && (aa->aa_flags & AFA_PHASE2)) 216 continue; 217 218 if (phase == 2 && 219 (aa->aa_flags & AFA_PHASE2) == 0) 220 continue; 221 222 if (aa->aa_ifp == ifp && 223 (AA_SAT(aa)->sat_addr.s_node == 224 to.sat_addr.s_node || 225 to.sat_addr.s_node == ATADDR_BCAST || 226 (ifp->if_flags & IFF_LOOPBACK))) 227 break; 228 } 229 } else { 230 for (aa = at_ifaddr.tqh_first; aa; 231 aa = aa->aa_list.tqe_next) { 232 if (to.sat_addr.s_net == aa->aa_firstnet && 233 to.sat_addr.s_node == 0) 234 break; 235 236 if ((ntohs(to.sat_addr.s_net) < 237 ntohs(aa->aa_firstnet) || 238 ntohs(to.sat_addr.s_net) > 239 ntohs(aa->aa_lastnet)) && 240 (ntohs(to.sat_addr.s_net) < 0xff00 || 241 ntohs(to.sat_addr.s_net) > 0xfffe)) 242 continue; 243 244 if (to.sat_addr.s_node != 245 AA_SAT(aa)->sat_addr.s_node && 246 to.sat_addr.s_node != ATADDR_BCAST) 247 continue; 248 249 break; 250 } 251 } 252 } 253 254 /* 255 * Adjust the length, removing any padding that may have been added 256 * at a link layer. We do this before we attempt to forward a packet, 257 * possibly on a different media. 258 */ 259 mlen = m->m_pkthdr.len; 260 if (mlen < dlen) { 261 DDP_STATINC(DDP_STAT_TOOSMALL); 262 m_freem(m); 263 return; 264 } 265 if (mlen > dlen) { 266 m_adj(m, dlen - mlen); 267 } 268 /* 269 * XXX Should we deliver broadcasts locally, also, or rely on the 270 * link layer to give us a copy? For the moment, the latter. 271 */ 272 if (aa == NULL || (to.sat_addr.s_node == ATADDR_BCAST && 273 aa->aa_ifp != ifp && (ifp->if_flags & IFF_LOOPBACK) == 0)) { 274 if (ddp_forward == 0) { 275 m_freem(m); 276 return; 277 } 278 sockaddr_at_init(&u.dsta, &to.sat_addr, 0); 279 rt = rtcache_lookup(&forwro, &u.dst); 280 #if 0 /* XXX The if-condition is always false. What was this 281 * actually trying to test? 282 */ 283 if (to.sat_addr.s_net != 284 satocsat(rtcache_getdst(&forwro))->sat_addr.s_net && 285 ddpe.deh_hops == DDP_MAXHOPS) { 286 m_freem(m); 287 return; 288 } 289 #endif 290 if (ddp_firewall && (rt == NULL || rt->rt_ifp != ifp)) { 291 m_freem(m); 292 return; 293 } 294 ddpe.deh_hops++; 295 ddpe.deh_bytes = htonl(ddpe.deh_bytes); 296 bcopy((void *) & ddpe, (void *) deh, sizeof(u_short));/*XXX*/ 297 if (ddp_route(m, &forwro)) { 298 DDP_STATINC(DDP_STAT_CANTFORWARD); 299 } else { 300 DDP_STATINC(DDP_STAT_FORWARD); 301 } 302 return; 303 } 304 from.sat_len = sizeof(struct sockaddr_at); 305 from.sat_family = AF_APPLETALK; 306 307 if (elh) { 308 m_adj(m, sizeof(struct ddpshdr)); 309 } else { 310 if (ddp_cksum && cksum && cksum != at_cksum(m, sizeof(int))) { 311 DDP_STATINC(DDP_STAT_BADSUM); 312 m_freem(m); 313 return; 314 } 315 m_adj(m, sizeof(struct ddpehdr)); 316 } 317 318 if ((ddp = ddp_search(&from, &to, aa)) == NULL) { 319 m_freem(m); 320 return; 321 } 322 if (sbappendaddr(&ddp->ddp_socket->so_rcv, (struct sockaddr *) & from, 323 m, (struct mbuf *) 0) == 0) { 324 DDP_STATINC(DDP_STAT_NOSOCKSPACE); 325 m_freem(m); 326 return; 327 } 328 #if IFA_STATS 329 if (aa) 330 aa->aa_ifa.ifa_data.ifad_inbytes += dlen; 331 #endif 332 sorwakeup(ddp->ddp_socket); 333 } 334 335 #if 0 336 337 #define BPXLEN 48 338 #define BPALEN 16 339 #include <ctype.h> 340 341 static void 342 bprint(data, len) 343 char *data; 344 int len; 345 { 346 char xout[BPXLEN], aout[BPALEN]; 347 int i = 0; 348 349 bzero(xout, BPXLEN); 350 bzero(aout, BPALEN); 351 352 for (;;) { 353 if (len < 1) { 354 if (i != 0) { 355 printf("%s\t%s\n", xout, aout); 356 } 357 printf("%s\n", "(end)"); 358 break; 359 } 360 xout[(i * 3)] = hexdigits[(*data & 0xf0) >> 4]; 361 xout[(i * 3) + 1] = hexdigits[*data & 0x0f]; 362 363 if ((u_char) * data < 0x7f && (u_char) * data > 0x20) { 364 aout[i] = *data; 365 } else { 366 aout[i] = '.'; 367 } 368 369 xout[(i * 3) + 2] = ' '; 370 371 i++; 372 len--; 373 data++; 374 375 if (i > BPALEN - 2) { 376 printf("%s\t%s\n", xout, aout); 377 bzero(xout, BPXLEN); 378 bzero(aout, BPALEN); 379 i = 0; 380 continue; 381 } 382 } 383 } 384 385 static void 386 m_printm(m) 387 struct mbuf *m; 388 { 389 for (; m; m = m->m_next) 390 bprint(mtod(m, char *), m->m_len); 391 } 392 #endif 393