1 /* $NetBSD: ddp_input.c,v 1.7 2001/11/15 09:48:26 lukem 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.7 2001/11/15 09:48:26 lukem 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/at_extern.h> 50 51 int ddp_forward = 1; 52 int ddp_firewall = 0; 53 extern int ddp_cksum; 54 void ddp_input __P((struct mbuf *, struct ifnet *, 55 struct elaphdr *, int)); 56 57 /* 58 * Could probably merge these two code segments a little better... 59 */ 60 void 61 atintr() 62 { 63 struct elaphdr *elhp, elh; 64 struct ifnet *ifp; 65 struct mbuf *m; 66 struct at_ifaddr *aa; 67 int s; 68 69 for (;;) { 70 s = splnet(); 71 72 IF_DEQUEUE(&atintrq2, m); 73 74 splx(s); 75 76 if (m == 0) { /* no more queued packets */ 77 break; 78 } 79 ifp = m->m_pkthdr.rcvif; 80 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 81 if (aa->aa_ifp == ifp && (aa->aa_flags & AFA_PHASE2)) 82 break; 83 } 84 if (aa == NULL) { /* ifp not an appletalk interface */ 85 m_freem(m); 86 continue; 87 } 88 ddp_input(m, ifp, (struct elaphdr *) NULL, 2); 89 } 90 91 for (;;) { 92 s = splnet(); 93 94 IF_DEQUEUE(&atintrq1, m); 95 96 splx(s); 97 98 if (m == 0) /* no more queued packets */ 99 100 break; 101 ifp = m->m_pkthdr.rcvif; 102 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 103 if (aa->aa_ifp == ifp && 104 (aa->aa_flags & AFA_PHASE2) == 0) 105 break; 106 } 107 if (aa == NULL) { /* ifp not an appletalk interface */ 108 m_freem(m); 109 continue; 110 } 111 if (m->m_len < SZ_ELAPHDR && 112 ((m = m_pullup(m, SZ_ELAPHDR)) == 0)) { 113 ddpstat.ddps_tooshort++; 114 continue; 115 } 116 elhp = mtod(m, struct elaphdr *); 117 m_adj(m, SZ_ELAPHDR); 118 119 if (elhp->el_type == ELAP_DDPEXTEND) { 120 ddp_input(m, ifp, (struct elaphdr *) NULL, 1); 121 } else { 122 bcopy((caddr_t) elhp, (caddr_t) & elh, SZ_ELAPHDR); 123 ddp_input(m, ifp, &elh, 1); 124 } 125 } 126 } 127 128 struct route forwro; 129 130 void 131 ddp_input(m, ifp, elh, phase) 132 struct mbuf *m; 133 struct ifnet *ifp; 134 struct elaphdr *elh; 135 int phase; 136 { 137 struct sockaddr_at from, to; 138 struct ddpshdr *dsh, ddps; 139 struct at_ifaddr *aa; 140 struct ddpehdr *deh = NULL, ddpe; 141 struct ddpcb *ddp; 142 int dlen, mlen; 143 u_short cksum = 0; 144 145 bzero((caddr_t) & from, sizeof(struct sockaddr_at)); 146 if (elh) { 147 ddpstat.ddps_short++; 148 149 if (m->m_len < sizeof(struct ddpshdr) && 150 ((m = m_pullup(m, sizeof(struct ddpshdr))) == 0)) { 151 ddpstat.ddps_tooshort++; 152 return; 153 } 154 dsh = mtod(m, struct ddpshdr *); 155 bcopy((caddr_t) dsh, (caddr_t) & ddps, sizeof(struct ddpshdr)); 156 ddps.dsh_bytes = ntohl(ddps.dsh_bytes); 157 dlen = ddps.dsh_len; 158 159 to.sat_addr.s_net = ATADDR_ANYNET; 160 to.sat_addr.s_node = elh->el_dnode; 161 to.sat_port = ddps.dsh_dport; 162 from.sat_addr.s_net = ATADDR_ANYNET; 163 from.sat_addr.s_node = elh->el_snode; 164 from.sat_port = ddps.dsh_sport; 165 166 for (aa = at_ifaddr.tqh_first; aa; aa = aa->aa_list.tqe_next) { 167 if (aa->aa_ifp == ifp && 168 (aa->aa_flags & AFA_PHASE2) == 0 && 169 (AA_SAT(aa)->sat_addr.s_node == 170 to.sat_addr.s_node || 171 to.sat_addr.s_node == ATADDR_BCAST)) 172 break; 173 } 174 if (aa == NULL) { 175 m_freem(m); 176 return; 177 } 178 } else { 179 ddpstat.ddps_long++; 180 181 if (m->m_len < sizeof(struct ddpehdr) && 182 ((m = m_pullup(m, sizeof(struct ddpehdr))) == 0)) { 183 ddpstat.ddps_tooshort++; 184 return; 185 } 186 deh = mtod(m, struct ddpehdr *); 187 bcopy((caddr_t) deh, (caddr_t) & ddpe, sizeof(struct ddpehdr)); 188 ddpe.deh_bytes = ntohl(ddpe.deh_bytes); 189 dlen = ddpe.deh_len; 190 191 if ((cksum = ddpe.deh_sum) == 0) { 192 ddpstat.ddps_nosum++; 193 } 194 from.sat_addr.s_net = ddpe.deh_snet; 195 from.sat_addr.s_node = ddpe.deh_snode; 196 from.sat_port = ddpe.deh_sport; 197 to.sat_addr.s_net = ddpe.deh_dnet; 198 to.sat_addr.s_node = ddpe.deh_dnode; 199 to.sat_port = ddpe.deh_dport; 200 201 if (to.sat_addr.s_net == ATADDR_ANYNET) { 202 for (aa = at_ifaddr.tqh_first; aa; 203 aa = aa->aa_list.tqe_next) { 204 if (phase == 1 && (aa->aa_flags & AFA_PHASE2)) 205 continue; 206 207 if (phase == 2 && 208 (aa->aa_flags & AFA_PHASE2) == 0) 209 continue; 210 211 if (aa->aa_ifp == ifp && 212 (AA_SAT(aa)->sat_addr.s_node == 213 to.sat_addr.s_node || 214 to.sat_addr.s_node == ATADDR_BCAST || 215 (ifp->if_flags & IFF_LOOPBACK))) 216 break; 217 } 218 } else { 219 for (aa = at_ifaddr.tqh_first; aa; 220 aa = aa->aa_list.tqe_next) { 221 if (to.sat_addr.s_net == aa->aa_firstnet && 222 to.sat_addr.s_node == 0) 223 break; 224 225 if ((ntohs(to.sat_addr.s_net) < 226 ntohs(aa->aa_firstnet) || 227 ntohs(to.sat_addr.s_net) > 228 ntohs(aa->aa_lastnet)) && 229 (ntohs(to.sat_addr.s_net) < 0xff00 || 230 ntohs(to.sat_addr.s_net) > 0xfffe)) 231 continue; 232 233 if (to.sat_addr.s_node != 234 AA_SAT(aa)->sat_addr.s_node && 235 to.sat_addr.s_node != ATADDR_BCAST) 236 continue; 237 238 break; 239 } 240 } 241 } 242 243 /* 244 * Adjust the length, removing any padding that may have been added 245 * at a link layer. We do this before we attempt to forward a packet, 246 * possibly on a different media. 247 */ 248 mlen = m->m_pkthdr.len; 249 if (mlen < dlen) { 250 ddpstat.ddps_toosmall++; 251 m_freem(m); 252 return; 253 } 254 if (mlen > dlen) { 255 m_adj(m, dlen - mlen); 256 } 257 /* 258 * XXX Should we deliver broadcasts locally, also, or rely on the 259 * link layer to give us a copy? For the moment, the latter. 260 */ 261 if (aa == NULL || (to.sat_addr.s_node == ATADDR_BCAST && 262 aa->aa_ifp != ifp && (ifp->if_flags & IFF_LOOPBACK) == 0)) { 263 if (ddp_forward == 0) { 264 m_freem(m); 265 return; 266 } 267 if (forwro.ro_rt && 268 (satosat(&forwro.ro_dst)->sat_addr.s_net != 269 to.sat_addr.s_net || 270 satosat(&forwro.ro_dst)->sat_addr.s_node != 271 to.sat_addr.s_node)) { 272 RTFREE(forwro.ro_rt); 273 forwro.ro_rt = (struct rtentry *) 0; 274 } 275 if (forwro.ro_rt == (struct rtentry *) 0 || 276 forwro.ro_rt->rt_ifp == (struct ifnet *) 0) { 277 bzero(&forwro.ro_dst, sizeof(struct sockaddr_at)); 278 forwro.ro_dst.sa_len = sizeof(struct sockaddr_at); 279 forwro.ro_dst.sa_family = AF_APPLETALK; 280 satosat(&forwro.ro_dst)->sat_addr.s_net = 281 to.sat_addr.s_net; 282 satosat(&forwro.ro_dst)->sat_addr.s_node = 283 to.sat_addr.s_node; 284 rtalloc(&forwro); 285 } 286 if (to.sat_addr.s_net != 287 satosat(&forwro.ro_dst)->sat_addr.s_net && 288 ddpe.deh_hops == DDP_MAXHOPS) { 289 m_freem(m); 290 return; 291 } 292 if (ddp_firewall && 293 (forwro.ro_rt == NULL || forwro.ro_rt->rt_ifp != ifp)) { 294 m_freem(m); 295 return; 296 } 297 ddpe.deh_hops++; 298 ddpe.deh_bytes = htonl(ddpe.deh_bytes); 299 bcopy((caddr_t) & ddpe, (caddr_t) deh, sizeof(u_short));/*XXX*/ 300 if (ddp_route(m, &forwro)) { 301 ddpstat.ddps_cantforward++; 302 } else { 303 ddpstat.ddps_forward++; 304 } 305 return; 306 } 307 from.sat_len = sizeof(struct sockaddr_at); 308 from.sat_family = AF_APPLETALK; 309 310 if (elh) { 311 m_adj(m, sizeof(struct ddpshdr)); 312 } else { 313 if (ddp_cksum && cksum && cksum != at_cksum(m, sizeof(int))) { 314 ddpstat.ddps_badsum++; 315 m_freem(m); 316 return; 317 } 318 m_adj(m, sizeof(struct ddpehdr)); 319 } 320 321 if ((ddp = ddp_search(&from, &to, aa)) == NULL) { 322 m_freem(m); 323 return; 324 } 325 if (sbappendaddr(&ddp->ddp_socket->so_rcv, (struct sockaddr *) & from, 326 m, (struct mbuf *) 0) == 0) { 327 ddpstat.ddps_nosockspace++; 328 m_freem(m); 329 return; 330 } 331 #if IFA_STATS 332 if (aa) 333 aa->aa_ifa.ifa_data.ifad_inbytes += dlen; 334 #endif 335 sorwakeup(ddp->ddp_socket); 336 } 337 338 #if 0 339 340 #define BPXLEN 48 341 #define BPALEN 16 342 #include <ctype.h> 343 char hexdig[] = "0123456789ABCDEF"; 344 345 static void 346 bprint(data, len) 347 char *data; 348 int len; 349 { 350 char xout[BPXLEN], aout[BPALEN]; 351 int i = 0; 352 353 bzero(xout, BPXLEN); 354 bzero(aout, BPALEN); 355 356 for (;;) { 357 if (len < 1) { 358 if (i != 0) { 359 printf("%s\t%s\n", xout, aout); 360 } 361 printf("%s\n", "(end)"); 362 break; 363 } 364 xout[(i * 3)] = hexdig[(*data & 0xf0) >> 4]; 365 xout[(i * 3) + 1] = hexdig[*data & 0x0f]; 366 367 if ((u_char) * data < 0x7f && (u_char) * data > 0x20) { 368 aout[i] = *data; 369 } else { 370 aout[i] = '.'; 371 } 372 373 xout[(i * 3) + 2] = ' '; 374 375 i++; 376 len--; 377 data++; 378 379 if (i > BPALEN - 2) { 380 printf("%s\t%s\n", xout, aout); 381 bzero(xout, BPXLEN); 382 bzero(aout, BPALEN); 383 i = 0; 384 continue; 385 } 386 } 387 } 388 389 static void 390 m_printm(m) 391 struct mbuf *m; 392 { 393 for (; m; m = m->m_next) 394 bprint(mtod(m, char *), m->m_len); 395 } 396 #endif 397