Exemple #1
0
// 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;
	}
}