// Call this to update the PCO for retransmission to the MS. // We cannot just make up a PCO ahead of time and then send it out to // all the MS for two reasons: // o The incoming options have uniquifying transaction identifiers that are // different each time, so we must modify the incoming pcoReq each time while // carefully preserving those modifiers. // o There are two major formats for the PCO options - see below. static void setPco(ByteVector &resultpco, ByteVector &pcoReq, mg_con_t *mgp) { if (mg_dns[0] == 0) { ip_finddns(mg_dns); } // GSM 24.008 10.5.6.3: Procotol Configuration Options. // These are the "negotiated" address params wrapped in PPP, // except they are not very negotiated; we are going to cram them // into the MS and it can accept them or die. // The first byte is the header, followed by any number of: // protocol id (2 octets) // length of contents (1 octet) // I have seen this supplied by the MS in two different ways: // - as two separate 0x8021 requests, each with a single option request // (Blackberry) // - as a single 0x8021 request with two option requests for the two DNS servers. // (Samsung phone) resultpco.clone(pcoReq); unsigned char *pc = resultpco.begin(); unsigned char *end = pc + resultpco.size(); __attribute__((unused)) const char *protname = ""; if (pc == NULL) { MGERROR("SGSN: Empty PCO field") } else if (*pc++ != 0x80) { MGERROR("SGSN: Unrecognized PCO Config Protocol: %d\n",pc[-1]); } else while (pc < end) { unsigned proto = (pc[0] << 8) + pc[1]; pc += 2; unsigned ipcplen = *pc++; if (proto == 0x8021) { // IP Control Protocol. // IPCP looks like this: // 1 byte: command: 1 => configure-request // 1 byte: transaction uniquifying identifier. // 2 bytes: total length of ipcp (even though length above was a byte) // Followed by IPCP options, where each option is: // 1 byte: option code // 1 byte: total option length N (should be 6) // N bytes: data if (pc[0] == 1) { // command = configure-request // pc[1] is the uniquifying identifier, leave it alone. // pc[2]&pc[3] are another length. // Followed by one or more 6 byte option consisting of: // pc[4]: IPCP option code // pc[5]: length (6) // pc[6-9]: data // Note: the 4 byte header length is included in the option_len unsigned ipcp_len = pc[3]; // pc[2] better be 0. unsigned char *op; for (op = &pc[4]; op < pc + ipcp_len; op += op[1]) { const char *what = ""; switch (op[0]) { case 0x03: pc[0] = 2; if (op[1] < 6) { goto bad_ipcp_opt_len; } memcpy(&op[2], &mgp->mg_ip, 4); break; case 0x81: // primary dns. pc[0] = 2; // IPCP command = ACK if (op[1] < 6) { bad_ipcp_opt_len: MGERROR("SGSN: Invalid PCO IPCP Config Option Length: opt=0x%x len=%d\n", op[0], op[1]); goto next_protocol; } memcpy(&op[2], &mg_dns[0], 4); // addr in network order. break; case 0x83: // secondary dns pc[0] = 2; // IPCP command = ACK if (op[1] < 6) { goto bad_ipcp_opt_len; } memcpy(&op[2], &mg_dns[mg_dns[1] ? 1 : 0], 4); // addr in network order. break; case 2: what = "IP Compression Protocol"; goto bad_ipcp; case 0x82: what = "primary NBNS [NetBios Name Service]"; goto bad_ipcp; case 0x84: what = "secondary NBNS [NetBios Name Service]"; goto bad_ipcp; default: bad_ipcp: // It would be nice to send an SMS message that the phone is set up improperly. MGWARN("SGSN: warning: ignoring PDP Context activation IPCP option %d %s\n",pc[4],what); break; } } } } else if (proto == 0xc021) { // LCP: protname = "(LCP [Link Control Protocol] for PPP)"; goto unsupported_protocol; } else if (proto == 0xc223) { // CHAP: protname = "(CHAP [Challenge-Handshake Authentication Protocol] for PPP)"; goto unsupported_protocol; } else if (proto == 0xc023) { // PAP: Password authentication protocol. protname = "(PAP [Password Authentication Protocol] for PPP)"; // 6-12: Remove this message for the 3.0 release because we get // lots of bogus complaints about PAP. //goto unsupported_protocol; goto next_protocol; } else { // If we see any of these options are non-empty, the MS may be configured to use PPP. // It is hopeless; user must reconfigure the MS. unsupported_protocol: if (ipcplen) { MGWARN("SGSN: warning: ignoring PDP Context activation sub-protocol 0x%x %s; MS may require reconfiguration.\n",proto,protname); } } next_protocol: pc += ipcplen; } }