1 /* 2 * Copyright (c) 1984, 1985, 1986, 1987 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that this notice is preserved and that due credit is given 7 * to the University of California at Berkeley. The name of the University 8 * may not be used to endorse or promote products derived from this 9 * software without specific prior written permission. This software 10 * is provided ``as is'' without express or implied warranty. 11 * 12 * @(#)ns_output.c 7.2 (Berkeley) 01/20/88 13 */ 14 15 #include "param.h" 16 #include "mbuf.h" 17 #include "errno.h" 18 #include "socket.h" 19 #include "socketvar.h" 20 21 #include "../net/if.h" 22 #include "../net/route.h" 23 24 #include "ns.h" 25 #include "ns_if.h" 26 #include "idp.h" 27 #include "idp_var.h" 28 29 #ifdef vax 30 #include "../vax/mtpr.h" 31 #endif 32 int ns_hold_output = 0; 33 int ns_copy_output = 0; 34 int ns_output_cnt = 0; 35 struct mbuf *ns_lastout; 36 37 ns_output(m0, ro, flags) 38 struct mbuf *m0; 39 struct route *ro; 40 int flags; 41 { 42 register struct idp *idp = mtod(m0, struct idp *); 43 register struct ifnet *ifp = 0; 44 int error = 0; 45 struct route idproute; 46 struct sockaddr_ns *dst; 47 extern int idpcksum; 48 49 if (ns_hold_output) { 50 if (ns_lastout) { 51 (void)m_free(ns_lastout); 52 } 53 ns_lastout = m_copy(m0, 0, (int)M_COPYALL); 54 } 55 /* 56 * Route packet. 57 */ 58 if (ro == 0) { 59 ro = &idproute; 60 bzero((caddr_t)ro, sizeof (*ro)); 61 } 62 dst = (struct sockaddr_ns *)&ro->ro_dst; 63 if (ro->ro_rt == 0) { 64 dst->sns_family = AF_NS; 65 dst->sns_addr = idp->idp_dna; 66 dst->sns_addr.x_port = 0; 67 /* 68 * If routing to interface only, 69 * short circuit routing lookup. 70 */ 71 if (flags & NS_ROUTETOIF) { 72 struct ns_ifaddr *ia = ns_iaonnetof(&idp->idp_dna); 73 74 if (ia == 0) { 75 error = ENETUNREACH; 76 goto bad; 77 } 78 ifp = ia->ia_ifp; 79 goto gotif; 80 } 81 rtalloc(ro); 82 } else if ((ro->ro_rt->rt_flags & RTF_UP) == 0) { 83 /* 84 * The old route has gone away; try for a new one. 85 */ 86 rtfree(ro->ro_rt); 87 ro->ro_rt = NULL; 88 rtalloc(ro); 89 } 90 if (ro->ro_rt == 0 || (ifp = ro->ro_rt->rt_ifp) == 0) { 91 error = ENETUNREACH; 92 goto bad; 93 } 94 ro->ro_rt->rt_use++; 95 if (ro->ro_rt->rt_flags & (RTF_GATEWAY|RTF_HOST)) 96 dst = (struct sockaddr_ns *)&ro->ro_rt->rt_gateway; 97 gotif: 98 99 /* 100 * Look for multicast addresses and 101 * and verify user is allowed to send 102 * such a packet. 103 */ 104 if (dst->sns_addr.x_host.c_host[0]&1) { 105 if ((ifp->if_flags & IFF_BROADCAST) == 0) { 106 error = EADDRNOTAVAIL; 107 goto bad; 108 } 109 if ((flags & NS_ALLOWBROADCAST) == 0) { 110 error = EACCES; 111 goto bad; 112 } 113 } 114 115 if (htons(idp->idp_len) <= ifp->if_mtu) { 116 ns_output_cnt++; 117 if (ns_copy_output) { 118 ns_watch_output(m0, ifp); 119 } 120 error = (*ifp->if_output)(ifp, m0, (struct sockaddr *)dst); 121 goto done; 122 } else error = EMSGSIZE; 123 124 125 bad: 126 if (ns_copy_output) { 127 ns_watch_output(m0, ifp); 128 } 129 m_freem(m0); 130 done: 131 if (ro == &idproute && (flags & NS_ROUTETOIF) == 0 && ro->ro_rt) 132 RTFREE(ro->ro_rt); 133 return (error); 134 } 135