net-snmp
5.4.1
|
00001 #include <net-snmp/net-snmp-config.h> 00002 00003 #include <stdio.h> 00004 #include <sys/types.h> 00005 #include <ctype.h> 00006 #include <errno.h> 00007 00008 #if HAVE_STRING_H 00009 #include <string.h> 00010 #else 00011 #include <strings.h> 00012 #endif 00013 #if HAVE_STDLIB_H 00014 #include <stdlib.h> 00015 #endif 00016 #if HAVE_UNISTD_H 00017 #include <unistd.h> 00018 #endif 00019 #if HAVE_SYS_SOCKET_H 00020 #include <sys/socket.h> 00021 #endif 00022 #include <atm.h> 00023 00024 #if HAVE_DMALLOC_H 00025 #include <dmalloc.h> 00026 #endif 00027 00028 #include <net-snmp/types.h> 00029 #include <net-snmp/output_api.h> 00030 #include <net-snmp/config_api.h> 00031 00032 #include <net-snmp/library/snmp_transport.h> 00033 #include <net-snmp/library/snmpAAL5PVCDomain.h> 00034 00035 00036 oid netsnmp_AAL5PVCDomain[10] = { NETSNMP_ENTERPRISE_MIB, 3, 3, 3 }; 00037 static netsnmp_tdomain aal5pvcDomain; 00038 00039 00040 /* 00041 * Return a string representing the address in data, or else the "far end" 00042 * address if data is NULL. 00043 */ 00044 00045 static char * 00046 netsnmp_aal5pvc_fmtaddr(netsnmp_transport *t, void *data, int len) 00047 { 00048 struct sockaddr_atmpvc *to = NULL; 00049 00050 if (data != NULL && len == sizeof(struct sockaddr_atmpvc)) { 00051 to = (struct sockaddr_atmpvc *) data; 00052 } else if (t != NULL && t->data != NULL && 00053 t->data_length == sizeof(struct sockaddr_atmpvc)) { 00054 to = (struct sockaddr_atmpvc *) t->data; 00055 } 00056 if (to == NULL) { 00057 return strdup("AAL5 PVC: unknown"); 00058 } else { 00059 char tmp[64]; 00060 sprintf(tmp, "AAL5 PVC: %hd.%hd.%d", to->sap_addr.itf, 00061 to->sap_addr.vpi, to->sap_addr.vci); 00062 return strdup(tmp); 00063 } 00064 } 00065 00066 00067 00068 /* 00069 * You can write something into opaque that will subsequently get passed back 00070 * to your send function if you like. For instance, you might want to 00071 * remember where a PDU came from, so that you can send a reply there... 00072 */ 00073 00074 static int 00075 netsnmp_aal5pvc_recv(netsnmp_transport *t, void *buf, int size, 00076 void **opaque, int *olength) 00077 { 00078 int rc = -1; 00079 00080 if (t != NULL && t->sock >= 0) { 00081 while (rc < 0) { 00082 rc = recv(t->sock, buf, size, 0); 00083 if (rc < 0 && errno != EINTR) { 00084 break; 00085 } 00086 } 00087 00088 if (rc >= 0) { 00089 char *str = netsnmp_aal5pvc_fmtaddr(t, NULL, 0); 00090 DEBUGMSGTL(("netsnmp_aal5pvc", 00091 "recv on fd %d got %d bytes (from %s)\n", t->sock, 00092 rc, str)); 00093 free(str); 00094 } else { 00095 DEBUGMSGTL(("netsnmp_aal5pvc", "recv on fd %d err %d (\"%s\")\n", 00096 t->sock, errno, strerror(errno))); 00097 } 00098 *opaque = NULL; 00099 *olength = 0; 00100 } 00101 return rc; 00102 } 00103 00104 00105 00106 static int 00107 netsnmp_aal5pvc_send(netsnmp_transport *t, void *buf, int size, 00108 void **opaque, int *olength) 00109 { 00110 int rc = -1; 00111 struct sockaddr *to = NULL; 00112 00113 if (opaque != NULL && *opaque != NULL && 00114 *olength == sizeof(struct sockaddr_atmpvc)) { 00115 to = (struct sockaddr *) (*opaque); 00116 } else if (t != NULL && t->data != NULL && 00117 t->data_length == sizeof(struct sockaddr_atmpvc)) { 00118 to = (struct sockaddr *) (t->data); 00119 } 00120 00121 if (to != NULL && t != NULL && t->sock >= 0) { 00122 char *str = netsnmp_aal5pvc_fmtaddr(NULL, (void *)to, 00123 sizeof(struct sockaddr_atmpvc)); 00124 DEBUGMSGTL(("netsnmp_aal5pvc","send %d bytes from %p to %s on fd %d\n", 00125 size, buf, str, t->sock)); 00126 free(str); 00127 while (rc < 0) { 00128 rc = send(t->sock, buf, size, 0); 00129 if (rc < 0 && errno != EINTR) { 00130 break; 00131 } 00132 } 00133 } 00134 return rc; 00135 } 00136 00137 00138 00139 static int 00140 netsnmp_aal5pvc_close(netsnmp_transport *t) 00141 { 00142 int rc = -1; 00143 00144 if (t->sock >= 0) { 00145 DEBUGMSGTL(("netsnmp_aal5pvc", "close fd %d\n", t->sock)); 00146 #ifndef HAVE_CLOSESOCKET 00147 rc = close(t->sock); 00148 #else 00149 rc = closesocket(t->sock); 00150 #endif 00151 t->sock = -1; 00152 } 00153 return rc; 00154 } 00155 00156 00157 00158 /* 00159 * Open an AAL5 PVC transport for SNMP. Local is TRUE if addr is the local 00160 * NSAP to bind to (i.e. this is a server-type session); otherwise addr is 00161 * the remote NSAP to send things to. 00162 */ 00163 00164 netsnmp_transport * 00165 netsnmp_aal5pvc_transport(struct sockaddr_atmpvc *addr, int local) 00166 { 00167 char *str = NULL; 00168 struct atm_qos qos; 00169 netsnmp_transport *t = NULL; 00170 00171 if (addr == NULL || addr->sap_family != AF_ATMPVC) { 00172 return NULL; 00173 } 00174 00175 t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport)); 00176 if (t == NULL) { 00177 return NULL; 00178 } 00179 00180 str = netsnmp_aal5pvc_fmtaddr(NULL, (void *) addr, 00181 sizeof(struct sockaddr_atmpvc)); 00182 DEBUGMSGTL(("netsnmp_aal5pvc", "open %s %s\n", local ? "local" : "remote", 00183 str)); 00184 free(str); 00185 00186 memset(t, 0, sizeof(netsnmp_transport)); 00187 00188 t->domain = netsnmp_AAL5PVCDomain; 00189 t->domain_length = 00190 sizeof(netsnmp_AAL5PVCDomain) / sizeof(netsnmp_AAL5PVCDomain[0]); 00191 00192 t->sock = socket(PF_ATMPVC, SOCK_DGRAM, 0); 00193 if (t->sock < 0) { 00194 DEBUGMSGTL(("netsnmp_aal5pvc","socket failed (%s)\n",strerror(errno))); 00195 netsnmp_transport_free(t); 00196 return NULL; 00197 } 00198 DEBUGMSGTL(("netsnmp_aal5pvc", "fd %d opened\n", t->sock)); 00199 00200 /* 00201 * Set up the QOS parameters. 00202 */ 00203 00204 memset(&qos, 0, sizeof(struct atm_qos)); 00205 qos.aal = ATM_AAL5; 00206 qos.rxtp.traffic_class = ATM_UBR; 00207 qos.rxtp.max_sdu = SNMP_MAX_LEN; /* Hmm -- this is a bit small? */ 00208 qos.txtp = qos.rxtp; 00209 00210 if (setsockopt(t->sock, SOL_ATM, SO_ATMQOS, &qos, sizeof(qos)) < 0) { 00211 DEBUGMSGTL(("netsnmp_aal5pvc", "setsockopt failed (%s)\n", 00212 strerror(errno))); 00213 netsnmp_aal5pvc_close(t); 00214 netsnmp_transport_free(t); 00215 return NULL; 00216 } 00217 00218 if (local) { 00219 t->local = (unsigned char*)malloc(8); 00220 if (t->local == NULL) { 00221 netsnmp_transport_free(t); 00222 return NULL; 00223 } 00224 t->local[0] = (addr->sap_addr.itf & 0xff00) >> 8; 00225 t->local[1] = (addr->sap_addr.itf & 0x00ff) >> 0; 00226 t->local[2] = (addr->sap_addr.vpi & 0xff00) >> 8; 00227 t->local[3] = (addr->sap_addr.vpi & 0x00ff) >> 0; 00228 t->local[4] = (addr->sap_addr.vci & 0xff000000) >> 24; 00229 t->local[5] = (addr->sap_addr.vci & 0x00ff0000) >> 16; 00230 t->local[6] = (addr->sap_addr.vci & 0x0000ff00) >> 8; 00231 t->local[7] = (addr->sap_addr.vci & 0x000000ff) >> 0; 00232 t->local_length = 8; 00233 00234 if (bind(t->sock, (struct sockaddr *) addr, 00235 sizeof(struct sockaddr_atmpvc)) < 0) { 00236 DEBUGMSGTL(("netsnmp_aal5pvc", "bind failed (%s)\n", 00237 strerror(errno))); 00238 netsnmp_aal5pvc_close(t); 00239 netsnmp_transport_free(t); 00240 return NULL; 00241 } 00242 } else { 00243 t->remote = (unsigned char*)malloc(8); 00244 if (t->remote == NULL) { 00245 netsnmp_transport_free(t); 00246 return NULL; 00247 } 00248 t->remote[0] = (addr->sap_addr.itf & 0xff00) >> 8; 00249 t->remote[1] = (addr->sap_addr.itf & 0x00ff) >> 0; 00250 t->remote[2] = (addr->sap_addr.vpi & 0xff00) >> 8; 00251 t->remote[3] = (addr->sap_addr.vpi & 0x00ff) >> 0; 00252 t->remote[4] = (addr->sap_addr.vci & 0xff000000) >> 24; 00253 t->remote[5] = (addr->sap_addr.vci & 0x00ff0000) >> 16; 00254 t->remote[6] = (addr->sap_addr.vci & 0x0000ff00) >> 8; 00255 t->remote[7] = (addr->sap_addr.vci & 0x000000ff) >> 0; 00256 t->remote_length = 8; 00257 00258 if (connect(t->sock, (struct sockaddr *) addr, 00259 sizeof(struct sockaddr_atmpvc)) < 0) { 00260 DEBUGMSGTL(("netsnmp_aal5pvc", "connect failed (%s)\n", 00261 strerror(errno))); 00262 netsnmp_aal5pvc_close(t); 00263 netsnmp_transport_free(t); 00264 return NULL; 00265 } 00266 } 00267 00268 t->data = malloc(sizeof(struct sockaddr_atmpvc)); 00269 if (t->data == NULL) { 00270 netsnmp_transport_free(t); 00271 return NULL; 00272 } 00273 memcpy(t->data, addr, sizeof(struct sockaddr_atmpvc)); 00274 t->data_length = sizeof(struct sockaddr_atmpvc); 00275 00276 /* 00277 * 16-bit length field in the trailer, no headers. 00278 */ 00279 00280 t->msgMaxSize = 0xffff; 00281 t->f_recv = netsnmp_aal5pvc_recv; 00282 t->f_send = netsnmp_aal5pvc_send; 00283 t->f_close = netsnmp_aal5pvc_close; 00284 t->f_accept = NULL; 00285 t->f_fmtaddr = netsnmp_aal5pvc_fmtaddr; 00286 00287 return t; 00288 } 00289 00290 00291 00292 netsnmp_transport * 00293 netsnmp_aal5pvc_create_tstring(const char *str, int local, 00294 const char *default_target) 00295 { 00296 struct sockaddr_atmpvc addr; 00297 00298 if (str == NULL || *str == '\0') 00299 str = default_target; 00300 00301 if (str != NULL) { 00302 addr.sap_family = AF_ATMPVC; 00303 00304 if (sscanf(str, "%hd.%hd.%d", &(addr.sap_addr.itf), 00305 &(addr.sap_addr.vpi), &(addr.sap_addr.vci)) == 3) { 00306 return netsnmp_aal5pvc_transport(&addr, local); 00307 } else if (sscanf(str, "%hd.%d", &(addr.sap_addr.vpi), 00308 &(addr.sap_addr.vci)) == 2) { 00309 addr.sap_addr.itf = 0; 00310 return netsnmp_aal5pvc_transport(&addr, local); 00311 } else if (sscanf(str, "%d", &(addr.sap_addr.vci)) == 1) { 00312 addr.sap_addr.itf = 0; 00313 addr.sap_addr.vpi = 0; 00314 return netsnmp_aal5pvc_transport(&addr, local); 00315 } else { 00316 return NULL; 00317 } 00318 } else { 00319 return NULL; 00320 } 00321 } 00322 00323 00324 00325 netsnmp_transport * 00326 netsnmp_aal5pvc_create_ostring(const u_char * o, size_t o_len, int local) 00327 { 00328 struct sockaddr_atmpvc addr; 00329 00330 if (o_len == 8) { 00331 addr.sap_family = AF_ATMPVC; 00332 addr.sap_addr.itf = (o[0] << 8) + (o[1] << 0); 00333 addr.sap_addr.vpi = (o[2] << 8) + (o[3] << 0); 00334 addr.sap_addr.vci = 00335 (o[4] << 24) + (o[5] << 16) + (o[6] << 8) + (o[7] << 0); 00336 return netsnmp_aal5pvc_transport(&addr, local); 00337 } 00338 00339 return NULL; 00340 } 00341 00342 00343 00344 void 00345 netsnmp_aal5pvc_ctor(void) 00346 { 00347 aal5pvcDomain.name = netsnmp_AAL5PVCDomain; 00348 aal5pvcDomain.name_length = sizeof(netsnmp_AAL5PVCDomain) / sizeof(oid); 00349 aal5pvcDomain.prefix = (const char**)calloc(3, sizeof(char *)); 00350 aal5pvcDomain.prefix[0] = "aal5pvc"; 00351 aal5pvcDomain.prefix[1] = "pvc"; 00352 00353 aal5pvcDomain.f_create_from_tstring_new = netsnmp_aal5pvc_create_tstring; 00354 aal5pvcDomain.f_create_from_ostring = netsnmp_aal5pvc_create_ostring; 00355 00356 netsnmp_tdomain_register(&aal5pvcDomain); 00357 }